From 6ee97b3cc5544ed3f83c6985749e671a5e171820 Mon Sep 17 00:00:00 2001 From: Remi Schnekenburger Date: Tue, 19 Sep 2023 09:26:49 +0200 Subject: [PATCH] dialogs - Allow multiple selection on Open... fixes #12905 - allow multiple selection in doOpen dialog - handle an array or a single URI or undefined when closing dialog Contributed on behalf of ST Microelectronics Signed-off-by: Remi Schnekenburger Address review comments - remove checks for files against workspace URI - update variable name to a more representative one - Simplify algorithm for single selected URI case - update signatures to indicate an array of files or folders can be opened rather than a single element --- CHANGELOG.md | 1 + .../workspace-frontend-contribution.ts | 76 +++++++++++++------ 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 114bac6cc5d07..cbd4bbacde3aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - [core] fixed logger level propagation when log config file changes at runtime [#12566](https://github.com/eclipse-theia/theia/pull/12566) - Contributed on behalf of STMicroelectronics - [core] improve frontend startup time [#12936](https://github.com/eclipse-theia/theia/pull/12936) - Contributed on behalf of STMicroelectronics - [dev-packages] restore src-gen frontend production behavior [12950](https://github.com/eclipse-theia/theia/pull/12950) - Contributed on behalf of STMicroelectronics +- [dialogs] allow multiple selection on Open... [#12923](https://github.com/eclipse-theia/theia/pull/12923) - Contributed on behalf of STMicroelectronics. - [vscode] stub TestController invalidateTestResults [#12944](https://github.com/eclipse-theia/theia/pull/12944) - Contributed by STMicroelectronics - [vscode] support iconPath in QuickPickItem [#12945](https://github.com/eclipse-theia/theia/pull/12945) - Contributed by STMicroelectronics - [vsx-registry] added a hint to extension fetching ENOTFOUND errors [#12858](https://github.com/eclipse-theia/theia/pull/12858) - Contributed by STMicroelectronics diff --git a/packages/workspace/src/browser/workspace-frontend-contribution.ts b/packages/workspace/src/browser/workspace-frontend-contribution.ts index 765c5aeae90ac..43e652511044a 100644 --- a/packages/workspace/src/browser/workspace-frontend-contribution.ts +++ b/packages/workspace/src/browser/workspace-frontend-contribution.ts @@ -262,50 +262,76 @@ export class WorkspaceFrontendContribution implements CommandContribution, Keybi * This is the generic `Open` method. Opens files and directories too. Resolves to the opened URI. * Except when you are on either Windows or Linux `AND` running in electron. If so, it opens a file. */ - protected async doOpen(): Promise { + protected async doOpen(): Promise { if (!isOSX && this.isElectron()) { return this.doOpenFile(); } const [rootStat] = await this.workspaceService.roots; - const destinationUri = await this.fileDialogService.showOpenDialog({ + let selectedUris = await this.fileDialogService.showOpenDialog({ title: WorkspaceCommands.OPEN.dialogLabel, canSelectFolders: true, - canSelectFiles: true + canSelectFiles: true, + canSelectMany: true }, rootStat); - if (destinationUri && this.getCurrentWorkspaceUri()?.toString() !== destinationUri.toString()) { - const destination = await this.fileService.resolve(destinationUri); - if (destination.isDirectory) { - this.workspaceService.open(destinationUri); - } else { - await open(this.openerService, destinationUri); + if (selectedUris) { + if (!Array.isArray(selectedUris)) { + selectedUris = [selectedUris]; + } + const folders: URI[] = []; + // Only open files then open all folders in a new workspace, as done with Electron see doOpenFolder. + for (const uri of selectedUris) { + const destination = await this.fileService.resolve(uri); + if (destination.isDirectory) { + if (this.getCurrentWorkspaceUri()?.toString() !== uri.toString()) { + folders.push(uri); + } + } else { + await open(this.openerService, uri); + } } - return destinationUri; + if (folders.length > 0) { + const openableURI = await this.getOpenableWorkspaceUri(folders); + if (openableURI && (!this.workspaceService.workspace || !openableURI.isEqual(this.workspaceService.workspace.resource))) { + this.workspaceService.open(openableURI); + } + } + + return selectedUris; } return undefined; } /** - * Opens a file after prompting the `Open File` dialog. Resolves to `undefined`, if + * Opens a set of files after prompting the `Open File` dialog. Resolves to `undefined`, if * - the workspace root is not set, * - the file to open does not exist, or * - it was not a file, but a directory. * - * Otherwise, resolves to the URI of the file. + * Otherwise, resolves to the set of URIs of the files. */ - protected async doOpenFile(): Promise { + protected async doOpenFile(): Promise { const props: OpenFileDialogProps = { title: WorkspaceCommands.OPEN_FILE.dialogLabel, canSelectFolders: false, - canSelectFiles: true + canSelectFiles: true, + canSelectMany: true }; const [rootStat] = await this.workspaceService.roots; - const destinationFileUri = await this.fileDialogService.showOpenDialog(props, rootStat); - if (destinationFileUri) { - const destinationFile = await this.fileService.resolve(destinationFileUri); - if (!destinationFile.isDirectory) { - await open(this.openerService, destinationFileUri); - return destinationFileUri; + let selectedFilesUris: MaybeArray | undefined = await this.fileDialogService.showOpenDialog(props, rootStat); + if (selectedFilesUris) { + if (!Array.isArray(selectedFilesUris)) { + selectedFilesUris = [selectedFilesUris]; } + + const result = []; + for (const uri of selectedFilesUris) { + const destination = await this.fileService.resolve(uri); + if (destination.isFile) { + await open(this.openerService, uri); + result.push(uri); + } + } + return result; } return undefined; } @@ -329,11 +355,11 @@ export class WorkspaceFrontendContribution implements CommandContribution, Keybi const [rootStat] = await this.workspaceService.roots; const targetFolders = await this.fileDialogService.showOpenDialog(props, rootStat); if (targetFolders) { - const openableURI = await this.getOpenableWorkspaceUri(targetFolders); - if (openableURI) { - if (!this.workspaceService.workspace || !openableURI.isEqual(this.workspaceService.workspace.resource)) { - this.workspaceService.open(openableURI); - return openableURI; + const openableUri = await this.getOpenableWorkspaceUri(targetFolders); + if (openableUri) { + if (!this.workspaceService.workspace || !openableUri.isEqual(this.workspaceService.workspace.resource)) { + this.workspaceService.open(openableUri); + return openableUri; } }; }