From aa19069e0412c8fea48f7067519b793f18e5dbde Mon Sep 17 00:00:00 2001 From: Till Salinger Date: Wed, 14 Feb 2018 10:13:37 +0100 Subject: [PATCH] Add multi-path creation from file explorer --- .../files/electron-browser/fileActions.ts | 58 ++++++++++++++++--- .../files/test/node/fileService.test.ts | 26 +++++++++ 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/parts/files/electron-browser/fileActions.ts b/src/vs/workbench/parts/files/electron-browser/fileActions.ts index e881b123159..7e5522edc52 100644 --- a/src/vs/workbench/parts/files/electron-browser/fileActions.ts +++ b/src/vs/workbench/parts/files/electron-browser/fileActions.ts @@ -498,7 +498,8 @@ export abstract class BaseCreateAction extends BaseRenameAction { return validateFileName(parent, name, false); } - return super.validateFileName(parent, name); + console.log('The other validateFilename function was called!'); + return super.validateFileName(parent, name); // TODO: when is this called? } } @@ -1325,31 +1326,42 @@ export class CopyPathAction extends Action { } } -export function validateFileName(parent: IFileStat, name: string, allowOverwriting: boolean = false): string { +export function validateFileName(parent: IFileStat, name: string, allowOverwriting: boolean = false, isFile: boolean = false): string { // TODO: param file or folder? // Produce a well formed file name name = getWellFormedFileName(name); // Name not provided - if (!name || name.length === 0 || /^\s+$/.test(name)) { + if (!name || name.length === 0 || /^\s+$/.test(name)) { // TODO: replace with strings.isFalsyOrWhitespace? return nls.localize('emptyFileNameError', "A file or folder name must be provided."); } + // if () --> is file && trailing slash --> return + const names: string[] = trimTrailingSlashes(name) // prevents empty last array element after split + .split(/[\\/]/); + // Do not allow to overwrite existing file if (!allowOverwriting) { - if (parent.children && parent.children.some((c) => { - if (isLinux) { - return c.name === name; + let p = parent; + + const alreadyExisting = names.every((folderName) => { + let { exists, child } = alreadyExists(p, folderName); + + if (!exists) { + return false; + } else { + p = child; + return true; } + }); - return c.name.toLowerCase() === name.toLowerCase(); - })) { + if (alreadyExisting) { return nls.localize('fileNameExistsError', "A file or folder **{0}** already exists at this location. Please choose a different name.", name); } } // Invalid File name - if (!paths.isValidBasename(name)) { + if (names.some((folderName) => !paths.isValidBasename(folderName))) { return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", trimLongName(name)); } @@ -1364,6 +1376,34 @@ export function validateFileName(parent: IFileStat, name: string, allowOverwriti return null; } +function trimTrailingSlashes(str): string | undefined { + if (!str) { return str; } + return str.replace(/[\\/]*$/, ''); +} + +function alreadyExists(parent: IFileStat, name: string): { exists: boolean, child: IFileStat | undefined } { + let foundDupChild: IFileStat; + + if (parent.children) { + let exists: boolean = parent.children.some((c) => { + let found = compareFolderNames(c.name, name); + if (found) { foundDupChild = c; } + return found; + }); + return { exists, child: foundDupChild }; + } + + return { exists: false, child: undefined }; +} + +function compareFolderNames(name1: string, name2: string): boolean { + if (isLinux) { + return name1 === name2; + } + + return name1.toLowerCase() === name2.toLowerCase(); +} + function trimLongName(name: string): string { if (name && name.length > 255) { return `${name.substr(0, 255)}...`; diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index 378b1b91a08..13ebd6743cf 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -136,6 +136,32 @@ suite('FileService', () => { }, error => onError(error, done)); }); + test('createFolder: creating multiple folders at once', function (done: () => void) { + let event: FileOperationEvent; + const toDispose = service.onAfterOperation(e => { + event = e; + }); + + const multiFolderPaths = 'a/couple/of/folders'; + service.resolveFile(uri.file(testDir)).done(parent => { + const resource = uri.file(path.join(parent.resource.fsPath, multiFolderPaths)); + + return service.createFolder(resource).then(f => { + // assert.equal(f.name, multiFolderPaths); + assert.equal(fs.existsSync(f.resource.fsPath), true); + + assert.ok(event); + assert.equal(event.resource.fsPath, resource.fsPath); + assert.equal(event.operation, FileOperation.CREATE); + assert.equal(event.target.resource.fsPath, resource.fsPath); + assert.equal(event.target.isDirectory, true); + toDispose.dispose(); + + done(); + }); + }, error => onError(error, done)); + }); + test('touchFile', function (done: () => void) { service.touchFile(uri.file(path.join(testDir, 'test.txt'))).done(s => { assert.equal(s.name, 'test.txt'); -- GitLab