提交 96afb61c 编写于 作者: B Benjamin Pasero

adopt more typed file events (for #7176)

上级 20c3935a
......@@ -14,7 +14,7 @@ import URI from 'vs/base/common/uri';
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
import {IEventService} from 'vs/platform/event/common/event';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {EventType as FileEventType, TextFileChangeEvent, ITextFileService} from 'vs/workbench/parts/files/common/files';
import {TextFileModelChangeEvent, ITextFileService} from 'vs/workbench/parts/files/common/files';
import {TPromise} from 'vs/base/common/winjs.base';
import {IFileService} from 'vs/platform/files/common/files';
import {IModeService} from 'vs/editor/common/services/modeService';
......@@ -61,17 +61,17 @@ export class MainThreadDocuments extends MainThreadDocumentsShape {
modelService.onModelRemoved(this._onModelRemoved, this, this._toDispose);
modelService.onModelModeChanged(this._onModelModeChanged, this, this._toDispose);
this._toDispose.push(eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => {
this._toDispose.push(textFileService.models.onModelSaved(e => {
if (this._shouldHandleFileEvent(e)) {
this._proxy.$acceptModelSaved(e.resource.toString());
}
}));
this._toDispose.push(eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => {
this._toDispose.push(textFileService.models.onModelReverted(e => {
if (this._shouldHandleFileEvent(e)) {
this._proxy.$acceptModelReverted(e.resource.toString());
}
}));
this._toDispose.push(eventService.addListener2(FileEventType.FILE_DIRTY, (e: TextFileChangeEvent) => {
this._toDispose.push(textFileService.models.onModelDirty(e => {
if (this._shouldHandleFileEvent(e)) {
this._proxy.$acceptModelDirty(e.resource.toString());
}
......@@ -93,7 +93,7 @@ export class MainThreadDocuments extends MainThreadDocumentsShape {
this._toDispose = dispose(this._toDispose);
}
private _shouldHandleFileEvent(e: TextFileChangeEvent): boolean {
private _shouldHandleFileEvent(e: TextFileModelChangeEvent): boolean {
const model = this._modelService.getModel(e.resource);
return model && !model.isTooLargeForHavingARichMode();
}
......
......@@ -24,7 +24,7 @@ import {Action, IAction} from 'vs/base/common/actions';
import {MessageType, IInputValidator} from 'vs/base/browser/ui/inputbox/inputBox';
import {ITree, IHighlightEvent} from 'vs/base/parts/tree/browser/tree';
import {dispose, IDisposable} from 'vs/base/common/lifecycle';
import {LocalFileChangeEvent, VIEWLET_ID, ITextFileService, TextFileChangeEvent, EventType as FileEventType} from 'vs/workbench/parts/files/common/files';
import {LocalFileChangeEvent, VIEWLET_ID, ITextFileService} from 'vs/workbench/parts/files/common/files';
import {IFileService, IFileStat, IImportResult} from 'vs/platform/files/common/files';
import {DiffEditorInput, toDiffLabel} from 'vs/workbench/common/editor/diffEditorInput';
import {asFileEditorInput, getUntitledOrFileResource, UntitledEditorInput, IEditorIdentifier} from 'vs/workbench/common/editor';
......@@ -1558,10 +1558,10 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting {
private registerListeners(): void {
// listen to files being changed locally
this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_DIRTY, (e: TextFileChangeEvent) => this.updateEnablement(true)));
this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => this.updateEnablement(false)));
this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => this.updateEnablement(false)));
this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_SAVE_ERROR, (e: TextFileChangeEvent) => this.updateEnablement(true)));
this.toDispose.push(this.textFileService.models.onModelDirty(e => this.updateEnablement(true)));
this.toDispose.push(this.textFileService.models.onModelSaved(e => this.updateEnablement(false)));
this.toDispose.push(this.textFileService.models.onModelReverted(e => this.updateEnablement(false)));
this.toDispose.push(this.textFileService.models.onModelSaveError(e => this.updateEnablement(true)));
if (this.includeUntitled()) {
this.toDispose.push(this.untitledEditorService.onDidChangeDirty(resource => this.updateEnablement(this.untitledEditorService.isDirty(resource))));
......
......@@ -23,7 +23,7 @@ import {SaveFileAsAction, RevertFileAction, SaveFileAction} from 'vs/workbench/p
import {IFileService, IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IEventService} from 'vs/platform/event/common/event';
import {EventType as FileEventType, TextFileChangeEvent, ITextFileService, ISaveErrorHandler, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files';
import {ITextFileService, ISaveErrorHandler, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IMessageService, IMessageWithAction, Severity, CancelAction} from 'vs/platform/message/common/message';
import {IModeService} from 'vs/editor/common/services/modeService';
......@@ -36,6 +36,7 @@ export class SaveErrorHandler implements ISaveErrorHandler {
constructor(
@IMessageService private messageService: IMessageService,
@IEventService private eventService: IEventService,
@ITextFileService private textFileService: ITextFileService,
@IInstantiationService private instantiationService: IInstantiationService
) {
this.messages = Object.create(null);
......@@ -44,8 +45,8 @@ export class SaveErrorHandler implements ISaveErrorHandler {
}
private registerListeners(): void {
this.eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => this.onFileSavedOrReverted(e.resource));
this.eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => this.onFileSavedOrReverted(e.resource));
this.textFileService.models.onModelSaved(e => this.onFileSavedOrReverted(e.resource));
this.textFileService.models.onModelReverted(e => this.onFileSavedOrReverted(e.resource));
}
private onFileSavedOrReverted(resource: URI): void {
......
......@@ -20,7 +20,7 @@ import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding';
import {IEditorStacksModel, IStacksModelChangeEvent, IEditorGroup} from 'vs/workbench/common/editor';
import {SaveAllAction} from 'vs/workbench/parts/files/browser/fileActions';
import {AdaptiveCollapsibleViewletView} from 'vs/workbench/browser/viewlet';
import {ITextFileService, IFilesConfiguration, VIEWLET_ID, AutoSaveMode, EventType as FileEventType} from 'vs/workbench/parts/files/common/files';
import {ITextFileService, IFilesConfiguration, VIEWLET_ID, AutoSaveMode} from 'vs/workbench/parts/files/common/files';
import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService';
import {Renderer, DataSource, Controller, AccessibilityProvider, ActionProvider, OpenEditor, DragAndDrop} from 'vs/workbench/parts/files/browser/views/openEditorsViewer';
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
......@@ -133,7 +133,7 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(e.config)));
// Also handle dirty count indicator #10556
this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_DIRTY, (e) => this.updateDirtyIndicator()));
this.toDispose.push(this.textFileService.models.onModelDirty(e => this.updateDirtyIndicator()));
// We are not updating the tree while the viewlet is not visible. Thus refresh when viewlet becomes visible #6702
this.toDispose.push(this.viewletService.onDidViewletOpen(viewlet => {
......
......@@ -16,7 +16,7 @@ import assert = require('vs/base/common/assert');
import {IEditorRegistry, Extensions, EditorModel, EncodingMode, ConfirmResult, IEditorDescriptor} from 'vs/workbench/common/editor';
import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel';
import {IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files';
import {ITextFileService, BINARY_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput, AutoSaveMode, ModelState, EventType as FileEventType, TextFileChangeEvent, IFileEditorDescriptor} from 'vs/workbench/parts/files/common/files';
import {ITextFileService, BINARY_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput, AutoSaveMode, ModelState, TextFileModelChangeEvent, IFileEditorDescriptor} from 'vs/workbench/parts/files/common/files';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
......@@ -66,13 +66,13 @@ export class FileEditorInput extends CommonFileEditorInput {
}
private registerListeners(): void {
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_DIRTY, (e: TextFileChangeEvent) => this.onDirtyStateChange(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_SAVE_ERROR, (e: TextFileChangeEvent) => this.onDirtyStateChange(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => this.onDirtyStateChange(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => this.onDirtyStateChange(e)));
this.toUnbind.push(this.textFileService.models.onModelDirty(e => this.onDirtyStateChange(e)));
this.toUnbind.push(this.textFileService.models.onModelSaveError(e => this.onDirtyStateChange(e)));
this.toUnbind.push(this.textFileService.models.onModelSaved(e => this.onDirtyStateChange(e)));
this.toUnbind.push(this.textFileService.models.onModelReverted(e => this.onDirtyStateChange(e)));
}
private onDirtyStateChange(e: TextFileChangeEvent): void {
private onDirtyStateChange(e: TextFileModelChangeEvent): void {
if (e.resource.toString() === this.resource.toString()) {
this._onDidChangeDirty.fire();
}
......
......@@ -5,6 +5,7 @@
'use strict';
import nls = require('vs/nls');
import Event, {Emitter} from 'vs/base/common/event';
import {TPromise} from 'vs/base/common/winjs.base';
import {onUnexpectedError} from 'vs/base/common/errors';
import {toErrorMessage} from 'vs/base/common/errorMessage';
......@@ -16,7 +17,7 @@ import types = require('vs/base/common/types');
import {IModelContentChangedEvent} from 'vs/editor/common/editorCommon';
import {IMode} from 'vs/editor/common/modes';
import {EventType as WorkbenchEventType, ResourceEvent} from 'vs/workbench/common/events';
import {EventType as FileEventType, TextFileChangeEvent, ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveErrorHandler} from 'vs/workbench/parts/files/common/files';
import {EventType as FileEventType, TextFileChangeEvent, ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveErrorHandler, StateChange} from 'vs/workbench/parts/files/common/files';
import {EncodingMode, EditorModel} from 'vs/workbench/common/editor';
import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel';
import {IFileService, IFileStat, IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files';
......@@ -55,6 +56,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
private inErrorMode: boolean;
private lastSaveAttemptTime: number;
private createTextEditorModelPromise: TPromise<TextFileEditorModel>;
private _onDidStateChange: Emitter<StateChange>;
constructor(
resource: URI,
......@@ -75,6 +77,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
throw new Error('TextFileEditorModel can only handle file:// resources.');
}
this._onDidStateChange = new Emitter<StateChange>();
this.preferredEncoding = preferredEncoding;
this.textModelChangeListener = null;
this.dirty = false;
......@@ -101,6 +104,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
}
}
public get onDidStateChange(): Event<StateChange> {
return this._onDidStateChange.event;
}
/**
* Set a save error handler to install code that executes when save errors occur.
*/
......@@ -143,12 +150,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
return this.load(true /* force */).then(() => {
// Emit file change event
this.emitEvent(FileEventType.FILE_REVERTED, new TextFileChangeEvent(this.resource, this.textEditorModel));
this._onDidStateChange.fire(StateChange.REVERTED);
}, (error) => {
// FileNotFound means the file got deleted meanwhile, so emit revert event because thats ok
if ((<IFileOperationResult>error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) {
this.emitEvent(FileEventType.FILE_REVERTED, new TextFileChangeEvent(this.resource, this.textEditorModel));
this._onDidStateChange.fire(StateChange.REVERTED);
}
// Set flags back to previous values, we are still dirty if revert failed and we where
......@@ -296,7 +303,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// Emit event
if (wasDirty) {
this.emitEvent(FileEventType.FILE_REVERTED, new TextFileChangeEvent(this.resource, this.textEditorModel));
this._onDidStateChange.fire(StateChange.REVERTED);
}
return;
......@@ -325,7 +332,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// Emit as Event if we turned dirty
if (!wasDirty) {
this.emitEvent(FileEventType.FILE_DIRTY, new TextFileChangeEvent(this.resource, this.textEditorModel));
this._onDidStateChange.fire(StateChange.DIRTY);
}
}
......@@ -454,7 +461,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
this.updateVersionOnDiskStat(stat);
// Emit File Saved Event
this.emitEvent(FileEventType.FILE_SAVED, new TextFileChangeEvent(this.resource, this.textEditorModel));
this._onDidStateChange.fire(StateChange.SAVED);
}, (error) => {
diag('doSave(' + versionId + ') - exit - resulted in a save error: ' + error.toString(), this.resource, new Date());
......@@ -468,7 +475,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
this.onSaveError(error);
// Emit as event
this.emitEvent(FileEventType.FILE_SAVE_ERROR, new TextFileChangeEvent(this.resource, this.textEditorModel));
this._onDidStateChange.fire(StateChange.SAVE_ERROR);
});
return this.mapPendingSaveToVersionId[versionId];
......@@ -676,6 +683,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
this.inConflictResolutionMode = false;
this.inErrorMode = false;
this._onDidStateChange.dispose();
this.createTextEditorModelPromise = null;
if (this.textModelChangeListener) {
......
......@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import Event, {Emitter} from 'vs/base/common/event';
import {TPromise} from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel';
import {ITextFileEditorModelManager} from 'vs/workbench/parts/files/common/files';
import {dispose, IDisposable} from 'vs/base/common/lifecycle';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
import {ModelState, ITextFileEditorModel, LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files';
import {ModelState, ITextFileEditorModel, LocalFileChangeEvent, ITextFileEditorModelManager, TextFileModelChangeEvent, StateChange} from 'vs/workbench/parts/files/common/files';
import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle';
import {IEventService} from 'vs/platform/event/common/event';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
......@@ -24,7 +24,13 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
private toUnbind: IDisposable[];
private _onModelDirty: Emitter<TextFileModelChangeEvent>;
private _onModelSaveError: Emitter<TextFileModelChangeEvent>;
private _onModelSaved: Emitter<TextFileModelChangeEvent>;
private _onModelReverted: Emitter<TextFileModelChangeEvent>;
private mapResourceToDisposeListener: { [resource: string]: IDisposable; };
private mapResourceToStateChangeListener: { [resource: string]: IDisposable; };
private mapResourcePathToModel: { [resource: string]: TextFileEditorModel; };
private mapResourceToPendingModelLoaders: { [resource: string]: TPromise<TextFileEditorModel>};
......@@ -36,8 +42,19 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
) {
this.toUnbind = [];
this._onModelDirty = new Emitter<TextFileModelChangeEvent>();
this._onModelSaveError = new Emitter<TextFileModelChangeEvent>();
this._onModelSaved = new Emitter<TextFileModelChangeEvent>();
this._onModelReverted = new Emitter<TextFileModelChangeEvent>();
this.toUnbind.push(this._onModelDirty);
this.toUnbind.push(this._onModelSaveError);
this.toUnbind.push(this._onModelSaved);
this.toUnbind.push(this._onModelReverted);
this.mapResourcePathToModel = Object.create(null);
this.mapResourceToDisposeListener = Object.create(null);
this.mapResourceToStateChangeListener = Object.create(null);
this.mapResourceToPendingModelLoaders = Object.create(null);
this.registerListeners();
......@@ -118,6 +135,22 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
return true;
}
public get onModelDirty(): Event<TextFileModelChangeEvent> {
return this._onModelDirty.event;
}
public get onModelSaveError(): Event<TextFileModelChangeEvent> {
return this._onModelSaveError.event;
}
public get onModelSaved(): Event<TextFileModelChangeEvent> {
return this._onModelSaved.event;
}
public get onModelReverted(): Event<TextFileModelChangeEvent> {
return this._onModelReverted.event;
}
public get(resource: URI): TextFileEditorModel {
return this.mapResourcePathToModel[resource.toString()];
}
......@@ -146,6 +179,21 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
else {
model = this.instantiationService.createInstance(TextFileEditorModel, resource, encoding);
modelPromise = model.load();
// Install state change listener
this.mapResourceToStateChangeListener[resource.toString()] = model.onDidStateChange(state => {
const event = new TextFileModelChangeEvent(model, state);
switch(state) {
case StateChange.DIRTY:
this._onModelDirty.fire(event);
case StateChange.SAVE_ERROR:
this._onModelSaveError.fire(event);
case StateChange.SAVED:
this._onModelSaved.fire(event);
case StateChange.REVERTED:
this._onModelReverted.fire(event);
}
});
}
// Store pending loads to avoid race conditions
......@@ -203,6 +251,12 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
dispose(disposeListener);
delete this.mapResourceToDisposeListener[resource.toString()];
}
const stateChangeListener = this.mapResourceToStateChangeListener[resource.toString()];
if (stateChangeListener) {
dispose(stateChangeListener);
delete this.mapResourceToStateChangeListener[resource.toString()];
}
}
public clear(): void {
......@@ -210,10 +264,15 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager {
// model cache
this.mapResourcePathToModel = Object.create(null);
// dispose listeners
const keys = Object.keys(this.mapResourceToDisposeListener);
// dispose dispose listeners
let keys = Object.keys(this.mapResourceToDisposeListener);
dispose(keys.map(k => this.mapResourceToDisposeListener[k]));
this.mapResourceToDisposeListener = Object.create(null);
// dispose state change listeners
keys = Object.keys(this.mapResourceToStateChangeListener);
dispose(keys.map(k => this.mapResourceToStateChangeListener[k]));
this.mapResourceToStateChangeListener = Object.create(null);
}
private disposeUnusedModels(): void {
......
......@@ -112,31 +112,10 @@ export interface ISaveErrorHandler {
*/
export const EventType = {
/**
* Indicates that a file content has changed but not yet saved.
*/
FILE_DIRTY: 'files:fileDirty',
/**
* Indicates that a file is being saved.
*/
FILE_SAVING: 'files:fileSaving',
/**
* Indicates that a file save resulted in an error.
*/
FILE_SAVE_ERROR: 'files:fileSaveError',
/**
* Indicates that a file content has been saved to the disk.
*/
FILE_SAVED: 'files:fileSaved',
/**
* Indicates that a file content has been reverted to the state
* on disk.
*/
FILE_REVERTED: 'files:fileReverted'
};
/**
......@@ -236,6 +215,32 @@ export class TextFileChangeEvent extends BaseEvent {
}
}
export enum StateChange {
DIRTY,
SAVING,
SAVE_ERROR,
SAVED,
REVERTED
}
export class TextFileModelChangeEvent {
private _resource: URI;
private _kind: StateChange;
constructor(model: ITextFileEditorModel, kind: StateChange) {
this._resource = model.getResource();
this._kind = kind;
}
public get resource(): URI {
return this._resource;
}
public get kind(): StateChange {
return this._kind;
}
}
export const TEXT_FILE_SERVICE_ID = 'textFileService';
export interface ITextFileOperationResult {
......@@ -288,6 +293,11 @@ export interface IRawTextContent extends IBaseStat {
export interface ITextFileEditorModelManager {
onModelDirty: Event<TextFileModelChangeEvent>;
onModelSaveError: Event<TextFileModelChangeEvent>;
onModelSaved: Event<TextFileModelChangeEvent>;
onModelReverted: Event<TextFileModelChangeEvent>;
get(resource: URI): ITextFileEditorModel;
getAll(resource?: URI): ITextFileEditorModel[];
......
......@@ -8,7 +8,7 @@
import nls = require('vs/nls');
import errors = require('vs/base/common/errors');
import {IWorkbenchContribution} from 'vs/workbench/common/contributions';
import {VIEWLET_ID, TextFileChangeEvent, EventType as FileEventType, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files';
import {VIEWLET_ID, TextFileModelChangeEvent, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files';
import {platform, Platform} from 'vs/base/common/platform';
import {IWindowService} from 'vs/workbench/services/window/electron-browser/windowService';
import {IEventService} from 'vs/platform/event/common/event';
......@@ -57,10 +57,10 @@ export class DirtyFilesTracker implements IWorkbenchContribution {
// Local text file changes
this.toUnbind.push(this.untitledEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_DIRTY, (e: TextFileChangeEvent) => this.onTextFileDirty(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => this.onTextFileSaved(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_SAVE_ERROR, (e: TextFileChangeEvent) => this.onTextFileSaveError(e)));
this.toUnbind.push(this.eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => this.onTextFileReverted(e)));
this.toUnbind.push(this.textFileService.models.onModelDirty(e => this.onTextFileDirty(e)));
this.toUnbind.push(this.textFileService.models.onModelSaved(e => this.onTextFileSaved(e)));
this.toUnbind.push(this.textFileService.models.onModelSaveError(e => this.onTextFileSaveError(e)));
this.toUnbind.push(this.textFileService.models.onModelReverted(e => this.onTextFileReverted(e)));
// Lifecycle
this.lifecycleService.onShutdown(this.dispose, this);
......@@ -78,7 +78,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution {
}
}
private onTextFileDirty(e: TextFileChangeEvent): void {
private onTextFileDirty(e: TextFileModelChangeEvent): void {
if ((this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) && !this.isDocumentedEdited) {
this.updateDocumentEdited(); // no indication needed when auto save is enabled for short delay
}
......@@ -119,7 +119,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution {
})).done(null, errors.onUnexpectedError);
}
private onTextFileSaved(e: TextFileChangeEvent): void {
private onTextFileSaved(e: TextFileModelChangeEvent): void {
if (this.isDocumentedEdited) {
this.updateDocumentEdited();
}
......@@ -129,7 +129,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution {
}
}
private onTextFileSaveError(e: TextFileChangeEvent): void {
private onTextFileSaveError(e: TextFileModelChangeEvent): void {
if (!this.isDocumentedEdited) {
this.updateDocumentEdited();
}
......@@ -137,7 +137,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution {
this.updateActivityBadge();
}
private onTextFileReverted(e: TextFileChangeEvent): void {
private onTextFileReverted(e: TextFileModelChangeEvent): void {
if (this.isDocumentedEdited) {
this.updateDocumentEdited();
}
......
......@@ -14,7 +14,7 @@ import paths = require('vs/base/common/paths');
import {EncodingMode} from 'vs/workbench/common/editor';
import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel';
import {IEventService} from 'vs/platform/event/common/event';
import {EventType, ITextFileService, ModelState} from 'vs/workbench/parts/files/common/files';
import {EventType, ITextFileService, ModelState, StateChange} from 'vs/workbench/parts/files/common/files';
import {workbenchInstantiationService, TestTextFileService} from 'vs/test/utils/servicesTestUtils';
import {TextFileEditorModelManager} from 'vs/workbench/parts/files/common/editors/textFileEditorModelManager';
import {FileOperationResult, IFileOperationResult} from 'vs/platform/files/common/files';
......@@ -103,12 +103,8 @@ suite('Files - TextFileEditorModel', () => {
assert.ok(false);
});
accessor.eventService.addListener2(EventType.FILE_DIRTY, () => {
assert.ok(false);
});
accessor.eventService.addListener2(EventType.FILE_SAVED, () => {
assert.ok(false);
model.onDidStateChange(e => {
assert.ok(e !== StateChange.DIRTY && e !== StateChange.SAVED);
});
model.load().then(() => {
......@@ -141,12 +137,15 @@ suite('Files - TextFileEditorModel', () => {
test('Revert', function (done) {
let eventCounter = 0;
accessor.eventService.addListener2(EventType.FILE_REVERTED, () => {
eventCounter++;
});
const model = instantiationService.createInstance(TextFileEditorModel, toResource('/path/index_async.txt'), 'utf8');
model.onDidStateChange(e => {
if (e === StateChange.REVERTED) {
eventCounter++;
}
});
model.load().then(() => {
model.textEditorModel.setValue('foo');
......@@ -217,12 +216,10 @@ suite('Files - TextFileEditorModel', () => {
(<any>model).autoSaveAfterMillies = 10;
(<any>model).autoSaveAfterMilliesEnabled = true;
accessor.eventService.addListener2(EventType.FILE_DIRTY, () => {
eventCounter++;
});
accessor.eventService.addListener2(EventType.FILE_SAVED, () => {
eventCounter++;
model.onDidStateChange(e => {
if (e === StateChange.DIRTY || e === StateChange.SAVED) {
eventCounter++;
}
});
model.load().then(() => {
......@@ -282,10 +279,12 @@ suite('Files - TextFileEditorModel', () => {
let eventCounter = 0;
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource('/path/index_async.txt'), 'utf8');
accessor.eventService.addListener2(EventType.FILE_SAVED, (e) => {
assert.equal(model.getValue(), 'bar');
assert.ok(!model.isDirty());
eventCounter++;
model.onDidStateChange(e => {
if (e === StateChange.SAVED) {
assert.equal(model.getValue(), 'bar');
assert.ok(!model.isDirty());
eventCounter++;
}
});
accessor.eventService.addListener2(EventType.FILE_SAVING, (e) => {
......
......@@ -113,6 +113,8 @@ suite('Files - TextFileEditorModelManager', () => {
assert.notEqual(model3, model2);
assert.equal(manager.get(resource), model3);
model3.dispose();
done();
});
});
......@@ -158,6 +160,7 @@ suite('Files - TextFileEditorModelManager', () => {
accessor.editorGroupService.fireChange();
assert.ok(model.isDisposed());
model.dispose();
manager.dispose();
});
......@@ -176,6 +179,8 @@ suite('Files - TextFileEditorModelManager', () => {
assert.ok(model.isDisposed());
model.dispose();
manager.dispose();
});
......@@ -252,9 +257,55 @@ suite('Files - TextFileEditorModelManager', () => {
assert.ok(!model.isDisposed());
model.dispose();
manager.dispose();
done();
});
});
});
test('events', function (done) {
const manager: TextFileEditorModelManager = instantiationService.createInstance(TextFileEditorModelManager);
const resource1 = toResource('/path/index.txt');
const resource2 = toResource('/path/other.txt');
let dirtyCounter = 0;
let revertedCounter = 0;
let savedCounter = 0;
manager.onModelDirty(e => {
dirtyCounter++;
assert.equal(e.resource.toString(), resource1.toString());
});
manager.onModelReverted(e => {
revertedCounter++;
assert.equal(e.resource.toString(), resource1.toString());
});
manager.onModelSaved(e => {
savedCounter++;
assert.equal(e.resource.toString(), resource1.toString());
});
manager.loadOrCreate(resource1, 'utf8').then(model1 => {
return manager.loadOrCreate(resource2, 'utf8').then(model2 => {
model1.textEditorModel.setValue('changed');
return model1.revert().then(() => {
model1.textEditorModel.setValue('changed again');
return model1.save().then(() => {
model1.dispose();
model2.dispose();
return model1.revert().then(() => { // should not trigger another event if disposed
done();
});
});
});
});
});
});
});
\ No newline at end of file
......@@ -20,7 +20,7 @@ import { IFileStatus, IGitServiceError, GitErrorCodes, Status, StatusType, AutoF
import { Model } from 'vs/workbench/parts/git/common/gitModel';
import { NativeGitIndexStringEditorInput, GitIndexDiffEditorInput, GitWorkingTreeDiffEditorInput, GitDiffEditorInput } from 'vs/workbench/parts/git/browser/gitEditorInputs';
import { GitOperation } from 'vs/workbench/parts/git/browser/gitOperations';
import { EventType as WorkbenchFileEventType, TextFileChangeEvent } from 'vs/workbench/parts/files/common/files';
import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/parts/files/common/files';
import { IFileService, EventType as FileEventType, FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files';
import { ThrottledDelayer, PeriodThrottledDelayer } from 'vs/base/common/async';
import severity from 'vs/base/common/severity';
......@@ -396,6 +396,7 @@ export class GitService extends EventEmitter
private eventService: IEventService;
private contextService: IWorkspaceContextService;
private messageService: IMessageService;
private textFileService: ITextFileService;
private instantiationService: IInstantiationService;
private editorService: IWorkbenchEditorService;
private lifecycleService: ILifecycleService;
......@@ -433,6 +434,7 @@ export class GitService extends EventEmitter
@IMessageService messageService: IMessageService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IOutputService outputService: IOutputService,
@ITextFileService textFileService: ITextFileService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@ILifecycleService lifecycleService: ILifecycleService,
@IStorageService storageService: IStorageService,
......@@ -444,6 +446,7 @@ export class GitService extends EventEmitter
this.eventService = eventService;
this.messageService = messageService;
this.editorService = editorService;
this.textFileService = textFileService;
this.outputService = outputService;
this.contextService = contextService;
this.lifecycleService = lifecycleService;
......@@ -500,8 +503,8 @@ export class GitService extends EventEmitter
private registerListeners(): void {
this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_CHANGES, (e) => this.onFileChanges(e)));
this.toDispose.push(this.eventService.addListener2(WorkbenchFileEventType.FILE_SAVED, (e) => this.onTextFileChange(e)));
this.toDispose.push(this.eventService.addListener2(WorkbenchFileEventType.FILE_REVERTED, (e) => this.onTextFileChange(e)));
this.toDispose.push(this.textFileService.models.onModelSaved((e) => this.onTextFileChange(e)));
this.toDispose.push(this.textFileService.models.onModelReverted((e) => this.onTextFileChange(e)));
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => {
if (this._allowHugeRepositories) {
return;
......@@ -529,7 +532,7 @@ export class GitService extends EventEmitter
this.toDispose.push(blurEvent(() => this.isFocused = false));
}
private onTextFileChange(e: TextFileChangeEvent): void {
private onTextFileChange(e: TextFileModelChangeEvent): void {
var shouldTriggerStatus = paths.basename(e.resource.fsPath) === '.gitignore';
if (!shouldTriggerStatus) {
......
......@@ -8,6 +8,7 @@ import { IRawGitService, RawServiceState, IGitConfiguration } from 'vs/workbench
import { NoOpGitService } from 'vs/workbench/parts/git/common/noopGitService';
import { GitService } from 'vs/workbench/parts/git/browser/gitServices';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { ITextFileService } from 'vs/workbench/parts/files/common/files';
import { IOutputService } from 'vs/workbench/parts/output/common/output';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -199,6 +200,7 @@ export class ElectronGitService extends GitService {
@IMessageService messageService: IMessageService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IOutputService outputService: IOutputService,
@ITextFileService textFileService: ITextFileService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@ILifecycleService lifecycleService: ILifecycleService,
@IStorageService storageService: IStorageService,
......@@ -228,6 +230,6 @@ export class ElectronGitService extends GitService {
}
}
super(raw, instantiationService, eventService, messageService, editorService, outputService, contextService, lifecycleService, storageService, configurationService);
super(raw, instantiationService, eventService, messageService, editorService, outputService, textFileService, contextService, lifecycleService, storageService, configurationService);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册