diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index d4846e4e48a..019a298634e 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -22,10 +22,10 @@ import { Action, IAction } from 'vs/base/common/actions'; import { MessageType, IInputValidator } from 'vs/base/browser/ui/inputbox/inputBox'; import { ITree, IHighlightEvent, IActionProvider } from 'vs/base/parts/tree/browser/tree'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { VIEWLET_ID } from 'vs/workbench/parts/files/common/files'; +import { VIEWLET_ID, FileOnDiskContentProvider } from 'vs/workbench/parts/files/common/files'; import labels = require('vs/base/common/labels'); import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService, IFileStat, FileChangeType } from 'vs/platform/files/common/files'; +import { IFileService, IFileStat } from 'vs/platform/files/common/files'; import { toResource, IEditorIdentifier, EditorInput } from 'vs/workbench/common/editor'; import { FileStat, Model, NewStatPlaceholder } from 'vs/workbench/parts/files/common/explorerModel'; import { ExplorerView } from 'vs/workbench/parts/files/browser/views/explorerView'; @@ -42,16 +42,13 @@ import { IInstantiationService, IConstructorSignature2, ServicesAccessor } from import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; -import { IEditorViewState, IModel } from 'vs/editor/common/editorCommon'; +import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; import { withFocusedFilesExplorer, revealInOSCommand, revealInExplorerCommand, copyPathCommand } from 'vs/workbench/parts/files/browser/fileCommands'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IMode } from 'vs/editor/common/modes'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; export interface IEditableData { action: IAction; @@ -2013,7 +2010,7 @@ export function getWellFormedFileName(filename: string): string { return filename; } -export class CompareWithSavedAction extends Action implements ITextModelContentProvider { +export class CompareWithSavedAction extends Action { public static ID = 'workbench.files.action.compareWithSaved'; public static LABEL = nls.localize('compareWithSaved', "Compare Active File with Saved"); @@ -2021,24 +2018,25 @@ export class CompareWithSavedAction extends Action implements ITextModelContentP private static SCHEME = 'showModifications'; private resource: URI; - private fileWatcher: IDisposable; + private toDispose: IDisposable[]; constructor( id: string, label: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @ITextFileService private textFileService: ITextFileService, - @IFileService private fileService: IFileService, - @IMessageService messageService: IMessageService, - @IModeService private modeService: IModeService, - @IModelService private modelService: IModelService, + @IInstantiationService instantiationService: IInstantiationService, @ITextModelService textModelService: ITextModelService ) { super(id, label); - textModelService.registerTextModelContentProvider(CompareWithSavedAction.SCHEME, this); - this.enabled = true; + this.toDispose = []; + + const provider = instantiationService.createInstance(FileOnDiskContentProvider); + this.toDispose.push(provider); + + const registrationDisposal = textModelService.registerTextModelContentProvider(CompareWithSavedAction.SCHEME, provider); + this.toDispose.push(registrationDisposal); } public setResource(resource: URI) { @@ -2063,61 +2061,10 @@ export class CompareWithSavedAction extends Action implements ITextModelContentP return TPromise.as(true); } - public provideTextContent(resource: URI): TPromise { - - // Make sure our file from disk is resolved up to date - return this.resolveEditorModel(resource).then(codeEditorModel => { - - // Make sure to keep contents on disk up to date when it changes - if (!this.fileWatcher) { - this.fileWatcher = this.fileService.onFileChanges(changes => { - if (changes.contains(resource, FileChangeType.UPDATED)) { - this.resolveEditorModel(resource, false /* do not create if missing */).done(null, errors.onUnexpectedError); // update model when resource changes - } - }); - - const disposeListener = codeEditorModel.onWillDispose(() => { - disposeListener.dispose(); - this.fileWatcher.dispose(); - this.fileWatcher = void 0; - }); - } - - return codeEditorModel; - }); - } - - private resolveEditorModel(resource: URI, createAsNeeded = true): TPromise { - const fileOnDiskResource = URI.file(resource.fsPath); - - return this.textFileService.resolveTextContent(fileOnDiskResource).then(content => { - let codeEditorModel = this.modelService.getModel(resource); - if (codeEditorModel) { - this.modelService.updateModel(codeEditorModel, content.value); - } else if (createAsNeeded) { - const fileOnDiskModel = this.modelService.getModel(fileOnDiskResource); - - let mode: TPromise; - if (fileOnDiskModel) { - mode = this.modeService.getOrCreateMode(fileOnDiskModel.getModeId()); - } else { - mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(fileOnDiskResource.fsPath); - } - - codeEditorModel = this.modelService.createModel(content.value, mode, resource); - } - - return codeEditorModel; - }); - } - public dispose(): void { super.dispose(); - if (this.fileWatcher) { - this.fileWatcher.dispose(); - this.fileWatcher = void 0; - } + this.toDispose = dispose(this.toDispose); } } diff --git a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts index 01cf1d38652..ebb71f191a3 100644 --- a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts @@ -18,25 +18,22 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { ITextFileService, ISaveErrorHandler, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService, ServicesAccessor } 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'; -import { IModelService } from 'vs/editor/common/services/modelService'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; -import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; -import { IModel } from 'vs/editor/common/editorCommon'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ResourceMap } from 'vs/base/common/map'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IMode } from 'vs/editor/common/modes'; +import { FileOnDiskContentProvider } from 'vs/workbench/parts/files/common/files'; export const CONFLICT_RESOLUTION_CONTEXT = 'saveConflictResolutionContext'; export const CONFLICT_RESOLUTION_SCHEME = 'conflictResolution'; // A handler for save error happening with conflict resolution actions -export class SaveErrorHandler implements ISaveErrorHandler, IWorkbenchContribution, ITextModelContentProvider { +export class SaveErrorHandler implements ISaveErrorHandler, IWorkbenchContribution { private messages: ResourceMap<() => void>; private toUnbind: IDisposable[]; private conflictResolutionContext: IContextKey; @@ -44,22 +41,21 @@ export class SaveErrorHandler implements ISaveErrorHandler, IWorkbenchContributi constructor( @IMessageService private messageService: IMessageService, @ITextFileService private textFileService: ITextFileService, - @ITextModelService private textModelResolverService: ITextModelService, - @IModelService private modelService: IModelService, - @IModeService private modeService: IModeService, @IInstantiationService private instantiationService: IInstantiationService, @IEditorGroupService private editorGroupService: IEditorGroupService, @IContextKeyService contextKeyService: IContextKeyService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService + @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @ITextModelService textModelService: ITextModelService ) { + this.toUnbind = []; this.messages = new ResourceMap<() => void>(); this.conflictResolutionContext = new RawContextKey(CONFLICT_RESOLUTION_CONTEXT, false).bindTo(contextKeyService); - this.toUnbind = []; - // Register as text model content provider that supports to load a resource as it actually - // is stored on disk as opposed to using the file:// scheme that will return a dirty buffer - // if there is one. - this.textModelResolverService.registerTextModelContentProvider(CONFLICT_RESOLUTION_SCHEME, this); + const provider = instantiationService.createInstance(FileOnDiskContentProvider); + this.toUnbind.push(provider); + + const registrationDisposal = textModelService.registerTextModelContentProvider(CONFLICT_RESOLUTION_SCHEME, provider); + this.toUnbind.push(registrationDisposal); // Hook into model TextFileEditorModel.setSaveErrorHandler(this); @@ -67,31 +63,6 @@ export class SaveErrorHandler implements ISaveErrorHandler, IWorkbenchContributi this.registerListeners(); } - public provideTextContent(resource: URI): TPromise { - const fileOnDiskResource = URI.file(resource.fsPath); - - // Make sure our file from disk is resolved up to date - return this.textFileService.resolveTextContent(fileOnDiskResource).then(content => { - let codeEditorModel = this.modelService.getModel(resource); - if (codeEditorModel) { - this.modelService.updateModel(codeEditorModel, content.value); - } else { - const fileOnDiskModel = this.modelService.getModel(fileOnDiskResource); - - let mode: TPromise; - if (fileOnDiskModel) { - mode = this.modeService.getOrCreateMode(fileOnDiskModel.getModeId()); - } else { - mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(fileOnDiskResource.fsPath); - } - - codeEditorModel = this.modelService.createModel(content.value, mode, resource); - } - - return codeEditorModel; - }); - } - public getId(): string { return 'vs.files.saveerrorhandler'; } diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index eed0da7e6ac..f25ed1b9106 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -7,9 +7,18 @@ import URI from 'vs/base/common/uri'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; -import { IFilesConfiguration } from 'vs/platform/files/common/files'; +import { IFilesConfiguration, FileChangeType, IFileService } from 'vs/platform/files/common/files'; import { FileStat, OpenEditor } from 'vs/workbench/parts/files/common/explorerModel'; import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { IModel } from 'vs/editor/common/editorCommon'; +import { IMode } from 'vs/editor/common/modes'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; /** * Explorer viewlet id. @@ -104,4 +113,71 @@ export const SortOrderConfiguration = { MODIFIED: 'modified' }; -export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified'; \ No newline at end of file +export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified'; + +export class FileOnDiskContentProvider implements ITextModelContentProvider { + private fileWatcher: IDisposable; + + constructor( + @ITextFileService private textFileService: ITextFileService, + @IFileService private fileService: IFileService, + @IModeService private modeService: IModeService, + @IModelService private modelService: IModelService + ) { + } + + public provideTextContent(resource: URI): TPromise { + + // Make sure our file from disk is resolved up to date + return this.resolveEditorModel(resource).then(codeEditorModel => { + + // Make sure to keep contents on disk up to date when it changes + if (!this.fileWatcher) { + this.fileWatcher = this.fileService.onFileChanges(changes => { + if (changes.contains(resource, FileChangeType.UPDATED)) { + this.resolveEditorModel(resource, false /* do not create if missing */).done(null, onUnexpectedError); // update model when resource changes + } + }); + + const disposeListener = codeEditorModel.onWillDispose(() => { + disposeListener.dispose(); + this.fileWatcher.dispose(); + this.fileWatcher = void 0; + }); + } + + return codeEditorModel; + }); + } + + private resolveEditorModel(resource: URI, createAsNeeded = true): TPromise { + const fileOnDiskResource = URI.file(resource.fsPath); + + return this.textFileService.resolveTextContent(fileOnDiskResource).then(content => { + let codeEditorModel = this.modelService.getModel(resource); + if (codeEditorModel) { + this.modelService.updateModel(codeEditorModel, content.value); + } else if (createAsNeeded) { + const fileOnDiskModel = this.modelService.getModel(fileOnDiskResource); + + let mode: TPromise; + if (fileOnDiskModel) { + mode = this.modeService.getOrCreateMode(fileOnDiskModel.getModeId()); + } else { + mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(fileOnDiskResource.fsPath); + } + + codeEditorModel = this.modelService.createModel(content.value, mode, resource); + } + + return codeEditorModel; + }); + } + + public dispose(): void { + if (this.fileWatcher) { + this.fileWatcher.dispose(); + this.fileWatcher = void 0; + } + } +} \ No newline at end of file