diff --git a/package.json b/package.json index 771599b8..4f4ebc89 100644 --- a/package.json +++ b/package.json @@ -291,6 +291,11 @@ "command": "one.cfgEditor.setDefaultValues", "key": "ctrl+shift+/", "when": "activeCustomEditorId == one.editor.cfg" + }, + { + "command": "one.explorer.rename", + "key": "F2", + "when": "OneExplorerView.active && one.explorer:hasSelectedCfg" } ], "menus": { diff --git a/src/OneExplorer/OneExplorer.ts b/src/OneExplorer/OneExplorer.ts index 57a1f671..ee5d5bac 100644 --- a/src/OneExplorer/OneExplorer.ts +++ b/src/OneExplorer/OneExplorer.ts @@ -442,6 +442,7 @@ export class OneNode extends vscode.TreeItem { super(node.name, collapsibleState); this.id = node.id; + this.node = node; this.resourceUri = node.uri; this.description = true; this.tooltip = `${this.node.path}`; @@ -483,6 +484,7 @@ export class OneTreeDataProvider implements vscode.TreeDataProvider { public static didHideExtra: boolean = false; public static hasSelectedCfg: boolean = false; + public static selectedCfgs: Node[] = []; public static register(context: vscode.ExtensionContext) { const provider = new OneTreeDataProvider(context.extension.extensionKind); @@ -492,7 +494,16 @@ export class OneTreeDataProvider implements vscode.TreeDataProvider { showCollapseAll: true, canSelectMany: true, }); - provider._treeView.onDidChangeSelection(() => { + + provider._treeView.onDidChangeSelection((event) => { + const selectedItems = event.selection; + OneTreeDataProvider.hasSelectedCfg = selectedItems.some( + (item) => item.type === NodeType.config + ); + OneTreeDataProvider.selectedCfgs = selectedItems.filter( + (item) => item.type === NodeType.config + ); + provider.refreshCfgSelection(); }); @@ -587,9 +598,28 @@ export class OneTreeDataProvider implements vscode.TreeDataProvider { vscode.commands.registerCommand("one.explorer.delete", (node: Node) => provider.delete(node) ), - vscode.commands.registerCommand("one.explorer.rename", (node: Node) => - provider.rename(node) - ), + vscode.commands.registerCommand("one.explorer.rename", async () => { + const nodes = provider.getSelectedCfg(); + if(nodes === undefined) { + return; + } + //await Promise.all(nodes.map((node) => this.renameSingleFile(node))); + + + await provider.renameCfgFiles(nodes); + // assert.ok(nodes.length > 0); + // assert.ok(nodes.every((node) => node.type === NodeType.config)); + + + // Rename the files one-by-one + // const promises = nodes.map(async (cfg) => { + // Logger.info("ONE Explorer", "Shortcut", `rename ${cfg.uri.fsPath}`); + // await provider.renameSingleFile(cfg); + // await provider.refresh(cfg.parent); + // return; + // }); + // promises.reduce((prev, curr) => prev.then(() => curr), Promise.resolve()); + }), vscode.commands.registerCommand("one.explorer.refactor", (node: Node) => provider.refactor(node) ), @@ -748,7 +778,7 @@ export class OneTreeDataProvider implements vscode.TreeDataProvider { */ private askNewName = (node: Node) => { return vscode.window.showInputBox({ - title: "Enter a file name:", + title: `Renaming '${path.basename(node.uri.fsPath)}':`, value: `${path.basename(node.uri.fsPath)}`, valueSelection: [ 0, @@ -787,26 +817,40 @@ export class OneTreeDataProvider implements vscode.TreeDataProvider { }; /** - * Rename a file + * Rename a multiple cfg files * @note Renaming is only allowed for config files as it has no impact on the explorer view. * @command one.explorer.rename + * @assumption All nodes are config files + * @todo prohibit special characters from new name for security ('..', '*', etc) + */ + async renameCfgFiles(nodes: Node[]): Promise { + assert.ok(nodes.length > 0); + assert.ok(nodes.every((node) => node.type === NodeType.config)); + + await Promise.all(nodes.map(async (node) => await this.renameSingleFile(node).then(async ()=>await this.refresh(node.parent)))); + } + + + /** + * Rename a single file + * @note Renaming is only allowed for config files as it has no impact on the explorer view. * @todo prohibit special characters from new name for security ('..', '*', etc) */ - rename(node: Node): void { + async renameSingleFile(node: Node): Promise { assert.ok(node.type === NodeType.config); if (node.type !== NodeType.config) { return; } - this.askNewName(node).then((newname) => { + await this.askNewName(node).then(async (newname) => { if (newname) { const dirpath = path.dirname(node.uri.fsPath); const newpath = `${dirpath}/${newname}`; const edit = new vscode.WorkspaceEdit(); edit.renameFile(node.uri, vscode.Uri.file(newpath)); - vscode.workspace.applyEdit(edit); + await vscode.workspace.applyEdit(edit); } }); }