extract things into file operations, https://github.com/microsoft/vscode/issues/91383
This commit is contained in:
parent
83ed704964
commit
506c6d02b3
|
@ -96,13 +96,13 @@ class BulkEdit {
|
|||
|
||||
private async _performFileEdits(edits: WorkspaceFileEdit[], progress: IProgress<void>) {
|
||||
this._logService.debug('_performFileEdits', JSON.stringify(edits));
|
||||
const model = this._instaService.createInstance(BulkFileEdits, progress, edits);
|
||||
const model = this._instaService.createInstance(BulkFileEdits, this._label || localize('workspaceEdit', "Workspace Edit"), progress, edits);
|
||||
await model.apply();
|
||||
}
|
||||
|
||||
private async _performTextEdits(edits: WorkspaceTextEdit[], progress: IProgress<void>): Promise<void> {
|
||||
this._logService.debug('_performTextEdits', JSON.stringify(edits));
|
||||
const model = this._instaService.createInstance(BulkTextEdits, this._label, this._editor, progress, edits);
|
||||
const model = this._instaService.createInstance(BulkTextEdits, this._label || localize('workspaceEdit', "Workspace Edit"), this._editor, progress, edits);
|
||||
await model.apply();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,55 +4,148 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
import { WorkspaceFileEdit } from 'vs/editor/common/modes';
|
||||
import { WorkspaceFileEdit, WorkspaceFileEditOptions } from 'vs/editor/common/modes';
|
||||
import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
import { IProgress } from 'vs/platform/progress/common/progress';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkspaceUndoRedoElement, UndoRedoElementType, IResourceUndoRedoElement, IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
|
||||
interface IFileOperation {
|
||||
perform(): Promise<IFileOperation>;
|
||||
}
|
||||
|
||||
class Noop implements IFileOperation {
|
||||
async perform() { return this; }
|
||||
}
|
||||
|
||||
class RenameOperation implements IFileOperation {
|
||||
|
||||
constructor(
|
||||
readonly newUri: URI,
|
||||
readonly oldUri: URI,
|
||||
readonly options: WorkspaceFileEditOptions,
|
||||
@IWorkingCopyFileService private readonly _workingCopyFileService: IWorkingCopyFileService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
) { }
|
||||
|
||||
async perform(): Promise<IFileOperation> {
|
||||
// rename
|
||||
if (this.options.overwrite === undefined && this.options.ignoreIfExists && await this._fileService.exists(this.newUri)) {
|
||||
return new Noop(); // not overwriting, but ignoring, and the target file exists
|
||||
}
|
||||
await this._workingCopyFileService.move(this.oldUri, this.newUri, this.options.overwrite);
|
||||
return new RenameOperation(this.oldUri, this.newUri, this.options, this._workingCopyFileService, this._fileService);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateOperation implements IFileOperation {
|
||||
|
||||
constructor(
|
||||
readonly newUri: URI,
|
||||
readonly options: WorkspaceFileEditOptions,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IInstantiationService private readonly _instaService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
async perform(): Promise<IFileOperation> {
|
||||
// create file
|
||||
if (this.options.overwrite === undefined && this.options.ignoreIfExists && await this._fileService.exists(this.newUri)) {
|
||||
return new Noop(); // not overwriting, but ignoring, and the target file exists
|
||||
}
|
||||
await this._textFileService.create(this.newUri, undefined, { overwrite: this.options.overwrite });
|
||||
return this._instaService.createInstance(DeleteOperation, this.newUri, this.options);
|
||||
}
|
||||
}
|
||||
|
||||
class DeleteOperation implements IFileOperation {
|
||||
|
||||
constructor(
|
||||
readonly oldUri: URI,
|
||||
readonly options: WorkspaceFileEditOptions,
|
||||
@IWorkingCopyFileService private readonly _workingCopyFileService: IWorkingCopyFileService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IInstantiationService private readonly _instaService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
async perform(): Promise<IFileOperation> {
|
||||
// delete file
|
||||
if (await this._fileService.exists(this.oldUri)) {
|
||||
let useTrash = this._configurationService.getValue<boolean>('files.enableTrash');
|
||||
if (useTrash && !(this._fileService.hasCapability(this.oldUri, FileSystemProviderCapabilities.Trash))) {
|
||||
useTrash = false; // not supported by provider
|
||||
}
|
||||
await this._workingCopyFileService.delete(this.oldUri, { useTrash, recursive: this.options.recursive });
|
||||
} else if (!this.options.ignoreIfNotExists) {
|
||||
throw new Error(`${this.oldUri} does not exist and can not be deleted`);
|
||||
}
|
||||
return this._instaService.createInstance(CreateOperation, this.oldUri, this.options);
|
||||
}
|
||||
}
|
||||
|
||||
class FileUndoRedoElement implements IWorkspaceUndoRedoElement {
|
||||
|
||||
readonly type = UndoRedoElementType.Workspace;
|
||||
|
||||
readonly resources: readonly URI[] = [];
|
||||
|
||||
constructor(
|
||||
readonly label: string,
|
||||
readonly operations: IFileOperation[]
|
||||
) { }
|
||||
|
||||
undo(): void | Promise<void> {
|
||||
// throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
redo(): void | Promise<void> {
|
||||
// throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
split(): IResourceUndoRedoElement[] {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export class BulkFileEdits {
|
||||
|
||||
constructor(
|
||||
private readonly _label: string,
|
||||
private readonly _progress: IProgress<void>,
|
||||
private readonly _edits: WorkspaceFileEdit[],
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@IWorkingCopyFileService private readonly _workingCopyFileService: IWorkingCopyFileService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||
@IInstantiationService private readonly _instaService: IInstantiationService,
|
||||
@IUndoRedoService private readonly _undoRedoService: IUndoRedoService,
|
||||
) { }
|
||||
|
||||
async apply(): Promise<void> {
|
||||
const undoOperations: IFileOperation[] = [];
|
||||
for (const edit of this._edits) {
|
||||
this._progress.report(undefined);
|
||||
|
||||
const options = edit.options || {};
|
||||
|
||||
let op: IFileOperation | undefined;
|
||||
if (edit.newUri && edit.oldUri) {
|
||||
// rename
|
||||
if (options.overwrite === undefined && options.ignoreIfExists && await this._fileService.exists(edit.newUri)) {
|
||||
continue; // not overwriting, but ignoring, and the target file exists
|
||||
}
|
||||
await this._workingCopyFileService.move(edit.oldUri, edit.newUri, options.overwrite);
|
||||
|
||||
op = this._instaService.createInstance(RenameOperation, edit.newUri, edit.oldUri, options);
|
||||
} else if (!edit.newUri && edit.oldUri) {
|
||||
// delete file
|
||||
if (await this._fileService.exists(edit.oldUri)) {
|
||||
let useTrash = this._configurationService.getValue<boolean>('files.enableTrash');
|
||||
if (useTrash && !(this._fileService.hasCapability(edit.oldUri, FileSystemProviderCapabilities.Trash))) {
|
||||
useTrash = false; // not supported by provider
|
||||
}
|
||||
await this._workingCopyFileService.delete(edit.oldUri, { useTrash, recursive: options.recursive });
|
||||
} else if (!options.ignoreIfNotExists) {
|
||||
throw new Error(`${edit.oldUri} does not exist and can not be deleted`);
|
||||
}
|
||||
op = this._instaService.createInstance(DeleteOperation, edit.oldUri, options);
|
||||
} else if (edit.newUri && !edit.oldUri) {
|
||||
// create file
|
||||
if (options.overwrite === undefined && options.ignoreIfExists && await this._fileService.exists(edit.newUri)) {
|
||||
continue; // not overwriting, but ignoring, and the target file exists
|
||||
}
|
||||
await this._textFileService.create(edit.newUri, undefined, { overwrite: options.overwrite });
|
||||
op = this._instaService.createInstance(CreateOperation, edit.newUri, options);
|
||||
}
|
||||
if (op) {
|
||||
await op.perform();
|
||||
undoOperations.push(op);
|
||||
}
|
||||
}
|
||||
|
||||
this._undoRedoService.pushElement(new FileUndoRedoElement(this._label, undoOperations));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import { Selection } from 'vs/editor/common/core/selection';
|
|||
import { EndOfLineSequence, IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model';
|
||||
import { WorkspaceTextEdit } from 'vs/editor/common/modes';
|
||||
import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IProgress } from 'vs/platform/progress/common/progress';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
|
@ -120,7 +119,7 @@ export class BulkTextEdits {
|
|||
private readonly _edits = new ResourceMap<WorkspaceTextEdit[]>();
|
||||
|
||||
constructor(
|
||||
private readonly _label: string | undefined,
|
||||
private readonly _label: string,
|
||||
private readonly _editor: ICodeEditor | undefined,
|
||||
private readonly _progress: IProgress<void>,
|
||||
edits: WorkspaceTextEdit[],
|
||||
|
@ -228,7 +227,7 @@ export class BulkTextEdits {
|
|||
} else {
|
||||
// prepare multi model undo element
|
||||
const multiModelEditStackElement = new MultiModelEditStackElement(
|
||||
this._label || localize('workspaceEdit', "Workspace Edit"),
|
||||
this._label,
|
||||
tasks.map(t => new SingleModelEditStackElement(t.model, t.getBeforeCursorState()))
|
||||
);
|
||||
this._undoRedoService.pushElement(multiModelEditStackElement);
|
||||
|
|
Loading…
Reference in a new issue