NotebookDiffEditorInput extends DiffEditorInput.

This commit is contained in:
rebornix 2021-06-14 13:25:54 -07:00
parent 75484f617b
commit 952bcbd666
6 changed files with 62 additions and 184 deletions

View file

@ -25,7 +25,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
*/
export class DiffEditorInput extends SideBySideEditorInput {
static override readonly ID = 'workbench.editors.diffEditorInput';
static override readonly ID: string = 'workbench.editors.diffEditorInput';
override get typeId(): string {
return DiffEditorInput.ID;

View file

@ -48,9 +48,9 @@ registerAction2(class extends Action2 {
await editorService.openEditor(
{
originalInput: { resource: diffEditorInput.originalResource },
originalInput: { resource: diffEditorInput.originalInput.resource },
modifiedInput: { resource: diffEditorInput.resource },
label: diffEditorInput.textDiffName,
label: diffEditorInput.getName(),
options: {
preserveFocus: false,
override: EditorOverride.DISABLED

View file

@ -122,10 +122,10 @@ class NotebookDiffEditorSerializer implements IEditorInputSerializer {
assertType(input instanceof NotebookDiffEditorInput);
return JSON.stringify({
resource: input.resource,
originalResource: input.originalResource,
name: input.name,
originalName: input.originalName,
textDiffName: input.textDiffName,
originalResource: input.originalInput.resource,
name: input.getName(),
originalName: input.originalInput.getName(),
textDiffName: input.getName(),
viewType: input.viewType,
});
}
@ -136,14 +136,12 @@ class NotebookDiffEditorSerializer implements IEditorInputSerializer {
if (!data) {
return undefined;
}
const { resource, originalResource, name, originalName, textDiffName, viewType } = data;
if (!data || !URI.isUri(resource) || !URI.isUri(originalResource) || typeof name !== 'string' || typeof originalName !== 'string' || typeof viewType !== 'string') {
const { resource, originalResource, name, viewType } = data;
if (!data || !URI.isUri(resource) || !URI.isUri(originalResource) || typeof name !== 'string' || typeof viewType !== 'string') {
return undefined;
}
const input = NotebookDiffEditorInput.create(instantiationService, resource, name, originalResource, originalName,
textDiffName || nls.localize('diffLeftRightLabel', "{0} ⟷ {1}", originalResource.toString(true), resource.toString(true)),
viewType);
const input = NotebookDiffEditorInput.create(instantiationService, resource, name, undefined, originalResource, viewType);
return input;
}

View file

@ -3,24 +3,16 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as glob from 'vs/base/common/glob';
import { IEditorInput, GroupIdentifier, ISaveOptions, IMoveResult, IRevertOptions, EditorInputCapabilities, IResourceDiffEditorInput } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { GroupIdentifier, IResourceDiffEditorInput } from 'vs/workbench/common/editor';
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { URI } from 'vs/base/common/uri';
import { isEqual } from 'vs/base/common/resources';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
import { IReference } from 'vs/base/common/lifecycle';
import { INotebookDiffEditorModel, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Schemas } from 'vs/base/common/network';
import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
interface NotebookEditorInputOptions {
startDirty?: boolean;
}
import { IFileService } from 'vs/platform/files/common/files';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { ILabelService } from 'vs/platform/label/common/label';
class NotebookDiffEditorModel extends EditorModel implements INotebookDiffEditorModel {
constructor(
@ -50,174 +42,73 @@ class NotebookDiffEditorModel extends EditorModel implements INotebookDiffEditor
}
}
export class NotebookDiffEditorInput extends EditorInput {
static create(instantiationService: IInstantiationService, resource: URI, name: string, originalResource: URI, originalName: string, textDiffName: string, viewType: string | undefined, options: NotebookEditorInputOptions = {}) {
return instantiationService.createInstance(NotebookDiffEditorInput, resource, name, originalResource, originalName, textDiffName, viewType, options);
export class NotebookDiffEditorInput extends DiffEditorInput {
static create(instantiationService: IInstantiationService, resource: URI, name: string | undefined, description: string | undefined, originalResource: URI, viewType: string) {
const originalInput = NotebookEditorInput.create(instantiationService, originalResource, viewType);
const modifiedInput = NotebookEditorInput.create(instantiationService, resource, viewType);
return instantiationService.createInstance(NotebookDiffEditorInput, name, description, originalInput, modifiedInput, viewType);
}
static readonly ID: string = 'workbench.input.diffNotebookInput';
static override readonly ID: string = 'workbench.input.diffNotebookInput';
private _modifiedTextModel: IReference<IResolvedNotebookEditorModel> | null = null;
private _originalTextModel: IReference<IResolvedNotebookEditorModel> | null = null;
private _defaultDirtyState: boolean = false;
private _modifiedTextModel: IResolvedNotebookEditorModel | null = null;
private _originalTextModel: IResolvedNotebookEditorModel | null = null;
override get resource() {
return this.modifiedInput.resource;
}
constructor(
public readonly resource: URI,
public readonly name: string,
public readonly originalResource: URI,
public readonly originalName: string,
public readonly textDiffName: string,
public readonly viewType: string | undefined,
public readonly options: NotebookEditorInputOptions,
@INotebookService private readonly _notebookService: INotebookService,
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
@IFileDialogService private readonly _fileDialogService: IFileDialogService,
@IFileService private readonly _fileService: IFileService
name: string | undefined,
description: string | undefined,
override readonly originalInput: NotebookEditorInput,
override readonly modifiedInput: NotebookEditorInput,
public readonly viewType: string,
@IFileService fileService: IFileService,
@ILabelService labelService: ILabelService,
) {
super();
this._defaultDirtyState = !!options.startDirty;
super(
name,
description,
originalInput,
modifiedInput,
undefined,
labelService,
fileService
);
}
override get typeId(): string {
return NotebookDiffEditorInput.ID;
}
override get capabilities(): EditorInputCapabilities {
let capabilities = EditorInputCapabilities.None;
override async resolve(): Promise<NotebookDiffEditorModel> {
if (this._modifiedTextModel?.object.resource.scheme === Schemas.untitled) {
capabilities |= EditorInputCapabilities.Untitled;
const [originalEditorModel, modifiedEditorModel] = await Promise.all([
this.originalInput.resolve(),
this.modifiedInput.resolve(),
]);
this._originalTextModel?.dispose();
this._modifiedTextModel?.dispose();
// TODO@rebornix check how we restore the editor in text diff editor
if (!modifiedEditorModel) {
throw new Error(`Fail to resolve modified editor model for resource ${this.modifiedInput.resource} with notebookType ${this.viewType}`);
}
if (this._modifiedTextModel) {
if (this._modifiedTextModel.object.isReadonly()) {
capabilities |= EditorInputCapabilities.Readonly;
}
} else {
if (this._fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly)) {
capabilities |= EditorInputCapabilities.Readonly;
}
if (!originalEditorModel) {
throw new Error(`Fail to resolve original editor model for resource ${this.originalInput.resource} with notebookType ${this.viewType}`);
}
return capabilities;
}
override getName(): string {
return this.textDiffName;
}
override isDirty() {
if (!this._modifiedTextModel) {
return this._defaultDirtyState;
}
return this._modifiedTextModel.object.isDirty();
}
override async save(group: GroupIdentifier, options?: ISaveOptions): Promise<IEditorInput | undefined> {
if (this._modifiedTextModel) {
if (this.hasCapability(EditorInputCapabilities.Untitled)) {
return this.saveAs(group, options);
} else {
await this._modifiedTextModel.object.save();
}
return this;
}
return undefined;
}
override async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise<IEditorInput | undefined> {
if (!this._modifiedTextModel || !this.viewType) {
return undefined;
}
const provider = this._notebookService.getContributedNotebookType(this.viewType!);
if (!provider) {
return undefined;
}
const dialogPath = this._modifiedTextModel.object.resource;
const target = await this._fileDialogService.pickFileToSave(dialogPath, options?.availableFileSystems);
if (!target) {
return undefined; // save cancelled
}
if (!provider.matches(target)) {
const patterns = provider.selectors.map(pattern => {
if (typeof pattern === 'string') {
return pattern;
}
if (glob.isRelativePattern(pattern)) {
return `${pattern} (base ${pattern.base})`;
}
return `${pattern.include} (exclude: ${pattern.exclude})`;
}).join(', ');
throw new Error(`File name ${target} is not supported by ${provider.providerDisplayName}.
Please make sure the file name matches following patterns:
${patterns}
`);
}
if (!await this._modifiedTextModel.object.saveAs(target)) {
return undefined;
}
return this._move(group, target)?.editor;
}
// called when users rename a notebook document
override rename(group: GroupIdentifier, target: URI): IMoveResult | undefined {
if (this._modifiedTextModel) {
const contributedNotebookProviders = this._notebookService.getContributedNotebookTypes(target);
if (contributedNotebookProviders.find(provider => provider.id === this._modifiedTextModel!.object.viewType)) {
return this._move(group, target);
}
}
return undefined;
}
private _move(group: GroupIdentifier, newResource: URI): { editor: IEditorInput } | undefined {
return undefined;
}
override async revert(group: GroupIdentifier, options?: IRevertOptions): Promise<void> {
if (this._modifiedTextModel && this._modifiedTextModel.object.isDirty()) {
await this._modifiedTextModel.object.revert(options);
}
return;
}
override async resolve(): Promise<INotebookDiffEditorModel | null> {
if (!await this._notebookService.canResolve(this.viewType!)) {
return null;
}
if (!this._modifiedTextModel) {
this._modifiedTextModel = await this._notebookModelResolverService.resolve(this.resource, this.viewType!);
this._register(this._modifiedTextModel.object.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
if (this._modifiedTextModel.object.isDirty() !== this._defaultDirtyState) {
this._onDidChangeDirty.fire();
}
}
if (!this._originalTextModel) {
this._originalTextModel = await this._notebookModelResolverService.resolve(this.originalResource, this.viewType!);
}
return new NotebookDiffEditorModel(this._originalTextModel.object, this._modifiedTextModel.object);
this._originalTextModel = originalEditorModel;
this._modifiedTextModel = modifiedEditorModel;
return new NotebookDiffEditorModel(this._originalTextModel, this._modifiedTextModel);
}
override asResourceEditorInput(group: GroupIdentifier): IResourceDiffEditorInput {
return {
originalInput: { resource: this.originalResource },
originalInput: { resource: this.originalInput.resource },
modifiedInput: { resource: this.resource },
options: {
override: this.viewType

View file

@ -21,7 +21,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
@ -59,7 +58,6 @@ export class NotebookProviderInfoStore extends Disposable {
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILabelService private readonly _labelService: ILabelService,
@IFileService private readonly _fileService: IFileService,
) {
super();
@ -167,9 +165,7 @@ export class NotebookProviderInfoStore extends Disposable {
const notebookEditorDiffFactory: DiffEditorInputFactoryFunction = diffEditorInput => {
const modifiedInput = diffEditorInput.modifiedInput;
const originalInput = diffEditorInput.originalInput;
const notebookUri = modifiedInput.resource!;
const originalNotebookUri = originalInput.resource!;
return { editor: NotebookDiffEditorInput.create(this._instantiationService, notebookUri, modifiedInput.resource ? this._labelService.getUriBasenameLabel(modifiedInput.resource) : '', originalNotebookUri, originalInput.resource ? this._labelService.getUriBasenameLabel(originalInput.resource) : '', this._labelService.getUriBasenameLabel(notebookUri), notebookProviderInfo.id) };
return { editor: NotebookDiffEditorInput.create(this._instantiationService, modifiedInput.resource!, undefined, undefined, originalInput.resource!, notebookProviderInfo.id) };
};
// Register the notebook editor
disposables.add(this._editorOverrideService.registerEditor(

View file

@ -10,7 +10,6 @@ import { mock } from 'vs/base/test/common/mock';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IFileService } from 'vs/platform/files/common/files';
import { ILabelService } from 'vs/platform/label/common/label';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { NotebookProviderInfoStore } from 'vs/workbench/contrib/notebook/browser/notebookServiceImpl';
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
@ -24,11 +23,6 @@ suite('NotebookProviderInfoStore', function () {
test('Can\'t open untitled notebooks in test #119363', function () {
const instantiationService = workbenchInstantiationService();
const labelService = new class extends mock<ILabelService>() {
override getUriBasenameLabel(uri: URI) {
return uri.toString();
}
};
const store = new NotebookProviderInfoStore(
new class extends mock<IStorageService>() {
override get() { return ''; }
@ -41,7 +35,6 @@ suite('NotebookProviderInfoStore', function () {
new TestConfigurationService(),
new class extends mock<IAccessibilityService>() { },
instantiationService,
labelService,
new class extends mock<IFileService>() {
override canHandleResource() { return true; }
}