mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
197 lines
6.1 KiB
TypeScript
197 lines
6.1 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { GroupIdentifier, IEditorInput, IRevertOptions } from 'vs/workbench/common/editor';
|
|
import { AbstractResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
|
import { URI } from 'vs/base/common/uri';
|
|
import { ITextFileService, ITextFileSaveOptions, IModeSupport } from 'vs/workbench/services/textfile/common/textfiles';
|
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
|
import { IFileService } from 'vs/platform/files/common/files';
|
|
import { ILabelService } from 'vs/platform/label/common/label';
|
|
import { Schemas } from 'vs/base/common/network';
|
|
import { isEqual } from 'vs/base/common/resources';
|
|
import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
|
|
import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResourceEditorModel';
|
|
import { IReference } from 'vs/base/common/lifecycle';
|
|
|
|
/**
|
|
* The base class for all editor inputs that open in text editors.
|
|
*/
|
|
export abstract class AbstractTextResourceEditorInput extends AbstractResourceEditorInput {
|
|
|
|
constructor(
|
|
resource: URI,
|
|
preferredResource: URI | undefined,
|
|
@IEditorService protected readonly editorService: IEditorService,
|
|
@ITextFileService protected readonly textFileService: ITextFileService,
|
|
@ILabelService labelService: ILabelService,
|
|
@IFileService fileService: IFileService
|
|
) {
|
|
super(resource, preferredResource, labelService, fileService);
|
|
}
|
|
|
|
override save(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
|
|
|
|
// If this is neither an `untitled` resource, nor a resource
|
|
// we can handle with the file service, we can only "Save As..."
|
|
if (this.resource.scheme !== Schemas.untitled && !this.fileService.canHandleResource(this.resource)) {
|
|
return this.saveAs(group, options);
|
|
}
|
|
|
|
// Normal save
|
|
return this.doSave(options, false);
|
|
}
|
|
|
|
override saveAs(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
|
|
return this.doSave(options, true);
|
|
}
|
|
|
|
private async doSave(options: ITextFileSaveOptions | undefined, saveAs: boolean): Promise<IEditorInput | undefined> {
|
|
|
|
// Save / Save As
|
|
let target: URI | undefined;
|
|
if (saveAs) {
|
|
target = await this.textFileService.saveAs(this.resource, undefined, { ...options, suggestedTarget: this.preferredResource });
|
|
} else {
|
|
target = await this.textFileService.save(this.resource, options);
|
|
}
|
|
|
|
if (!target) {
|
|
return undefined; // save cancelled
|
|
}
|
|
|
|
// If this save operation results in a new editor, either
|
|
// because it was saved to disk (e.g. from untitled) or
|
|
// through an explicit "Save As", make sure to replace it.
|
|
if (
|
|
target.scheme !== this.resource.scheme ||
|
|
(saveAs && !isEqual(target, this.preferredResource))
|
|
) {
|
|
return this.editorService.createEditorInput({ resource: target });
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
override async revert(group: GroupIdentifier, options?: IRevertOptions): Promise<void> {
|
|
await this.textFileService.revert(this.resource, options);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A read-only text editor input whos contents are made of the provided resource that points to an existing
|
|
* code editor model.
|
|
*/
|
|
export class TextResourceEditorInput extends AbstractTextResourceEditorInput implements IModeSupport {
|
|
|
|
static readonly ID: string = 'workbench.editors.resourceEditorInput';
|
|
|
|
override get typeId(): string {
|
|
return TextResourceEditorInput.ID;
|
|
}
|
|
|
|
private cachedModel: TextResourceEditorModel | undefined = undefined;
|
|
private modelReference: Promise<IReference<ITextEditorModel>> | undefined = undefined;
|
|
|
|
constructor(
|
|
resource: URI,
|
|
private name: string | undefined,
|
|
private description: string | undefined,
|
|
private preferredMode: string | undefined,
|
|
@ITextModelService private readonly textModelResolverService: ITextModelService,
|
|
@ITextFileService textFileService: ITextFileService,
|
|
@IEditorService editorService: IEditorService,
|
|
@IFileService fileService: IFileService,
|
|
@ILabelService labelService: ILabelService
|
|
) {
|
|
super(resource, undefined, editorService, textFileService, labelService, fileService);
|
|
}
|
|
|
|
override getName(): string {
|
|
return this.name || super.getName();
|
|
}
|
|
|
|
setName(name: string): void {
|
|
if (this.name !== name) {
|
|
this.name = name;
|
|
|
|
this._onDidChangeLabel.fire();
|
|
}
|
|
}
|
|
|
|
override getDescription(): string | undefined {
|
|
return this.description;
|
|
}
|
|
|
|
setDescription(description: string): void {
|
|
if (this.description !== description) {
|
|
this.description = description;
|
|
|
|
this._onDidChangeLabel.fire();
|
|
}
|
|
}
|
|
|
|
setMode(mode: string): void {
|
|
this.setPreferredMode(mode);
|
|
|
|
if (this.cachedModel) {
|
|
this.cachedModel.setMode(mode);
|
|
}
|
|
}
|
|
|
|
setPreferredMode(mode: string): void {
|
|
this.preferredMode = mode;
|
|
}
|
|
|
|
override async resolve(): Promise<ITextEditorModel> {
|
|
if (!this.modelReference) {
|
|
this.modelReference = this.textModelResolverService.createModelReference(this.resource);
|
|
}
|
|
|
|
const ref = await this.modelReference;
|
|
|
|
// Ensure the resolved model is of expected type
|
|
const model = ref.object;
|
|
if (!(model instanceof TextResourceEditorModel)) {
|
|
ref.dispose();
|
|
this.modelReference = undefined;
|
|
|
|
throw new Error(`Unexpected model for TextResourceEditorInput: ${this.resource}`);
|
|
}
|
|
|
|
this.cachedModel = model;
|
|
|
|
// Set mode if we have a preferred mode configured
|
|
if (this.preferredMode) {
|
|
model.setMode(this.preferredMode);
|
|
}
|
|
|
|
return model;
|
|
}
|
|
|
|
override matches(otherInput: unknown): boolean {
|
|
if (otherInput === this) {
|
|
return true;
|
|
}
|
|
|
|
if (otherInput instanceof TextResourceEditorInput) {
|
|
return isEqual(otherInput.resource, this.resource);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
override dispose(): void {
|
|
if (this.modelReference) {
|
|
this.modelReference.then(ref => ref.dispose());
|
|
this.modelReference = undefined;
|
|
}
|
|
|
|
this.cachedModel = undefined;
|
|
|
|
super.dispose();
|
|
}
|
|
}
|