mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-16 00:43:20 +01:00
Save conflict: left hand diff editor does not update on changes to file (fixes #33792)
This commit is contained in:
@@ -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<IModel> {
|
||||
|
||||
// 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<IModel> {
|
||||
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<IMode>;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<boolean>;
|
||||
@@ -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<boolean>(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<IModel> {
|
||||
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<IMode>;
|
||||
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';
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
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<IModel> {
|
||||
|
||||
// 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<IModel> {
|
||||
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<IMode>;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user