mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 18:22:34 -05:00
Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d
This commit is contained in:
committed by
AzureDataStudio
parent
a8a7559229
commit
1388493cc1
180
src/vs/workbench/services/bulkEdit/browser/bulkFileEdits.ts
Normal file
180
src/vs/workbench/services/bulkEdit/browser/bulkFileEdits.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkspaceUndoRedoElement, UndoRedoElementType, IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
interface IFileOperation {
|
||||
uris: URI[];
|
||||
perform(): Promise<IFileOperation>;
|
||||
}
|
||||
|
||||
class Noop implements IFileOperation {
|
||||
readonly uris = [];
|
||||
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,
|
||||
) { }
|
||||
|
||||
get uris() {
|
||||
return [this.newUri, this.oldUri];
|
||||
}
|
||||
|
||||
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([{ source: this.oldUri, target: this.newUri }], { overwrite: 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,
|
||||
readonly contents: VSBuffer | undefined,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IWorkingCopyFileService private readonly _workingCopyFileService: IWorkingCopyFileService,
|
||||
@IInstantiationService private readonly _instaService: IInstantiationService,
|
||||
) { }
|
||||
|
||||
get uris() {
|
||||
return [this.newUri];
|
||||
}
|
||||
|
||||
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._workingCopyFileService.create(this.newUri, this.contents, { 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,
|
||||
@ILogService private readonly _logService: ILogService
|
||||
) { }
|
||||
|
||||
get uris() {
|
||||
return [this.oldUri];
|
||||
}
|
||||
|
||||
async perform(): Promise<IFileOperation> {
|
||||
// delete file
|
||||
if (!await this._fileService.exists(this.oldUri)) {
|
||||
if (!this.options.ignoreIfNotExists) {
|
||||
throw new Error(`${this.oldUri} does not exist and can not be deleted`);
|
||||
}
|
||||
return new Noop();
|
||||
}
|
||||
|
||||
let contents: VSBuffer | undefined;
|
||||
try {
|
||||
contents = (await this._fileService.readFile(this.oldUri)).value;
|
||||
} catch (err) {
|
||||
this._logService.critical(err);
|
||||
}
|
||||
|
||||
const useTrash = this._fileService.hasCapability(this.oldUri, FileSystemProviderCapabilities.Trash) && this._configurationService.getValue<boolean>('files.enableTrash');
|
||||
await this._workingCopyFileService.delete([this.oldUri], { useTrash, recursive: this.options.recursive });
|
||||
return this._instaService.createInstance(CreateOperation, this.oldUri, this.options, contents);
|
||||
}
|
||||
}
|
||||
|
||||
class FileUndoRedoElement implements IWorkspaceUndoRedoElement {
|
||||
|
||||
readonly type = UndoRedoElementType.Workspace;
|
||||
|
||||
readonly resources: readonly URI[];
|
||||
|
||||
constructor(
|
||||
readonly label: string,
|
||||
readonly operations: IFileOperation[]
|
||||
) {
|
||||
this.resources = (<URI[]>[]).concat(...operations.map(op => op.uris));
|
||||
}
|
||||
|
||||
async undo(): Promise<void> {
|
||||
await this._reverse();
|
||||
}
|
||||
|
||||
async redo(): Promise<void> {
|
||||
await this._reverse();
|
||||
}
|
||||
|
||||
private async _reverse() {
|
||||
for (let i = 0; i < this.operations.length; i++) {
|
||||
const op = this.operations[i];
|
||||
const undo = await op.perform();
|
||||
this.operations[i] = undo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BulkFileEdits {
|
||||
|
||||
constructor(
|
||||
private readonly _label: string,
|
||||
private readonly _progress: IProgress<void>,
|
||||
private readonly _edits: WorkspaceFileEdit[],
|
||||
@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
|
||||
op = this._instaService.createInstance(RenameOperation, edit.newUri, edit.oldUri, options);
|
||||
} else if (!edit.newUri && edit.oldUri) {
|
||||
// delete file
|
||||
op = this._instaService.createInstance(DeleteOperation, edit.oldUri, options);
|
||||
} else if (edit.newUri && !edit.oldUri) {
|
||||
// create file
|
||||
op = this._instaService.createInstance(CreateOperation, edit.newUri, options, undefined);
|
||||
}
|
||||
if (op) {
|
||||
const undoOp = await op.perform();
|
||||
undoOperations.push(undoOp);
|
||||
}
|
||||
}
|
||||
|
||||
this._undoRedoService.pushElement(new FileUndoRedoElement(this._label, undoOperations));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user