diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index 7aa53a9439447ff2444176305e47c56a59d79460..785456cd56bad8a55f58fa9eda7fdd5b3d7bbabc 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -155,7 +155,7 @@ class NewWorkspaceAction extends BaseWorkspacesAction { } private createWorkspace(folders: URI[]): TPromise { - const workspaceFolders = distinct(folders.map(folder => folder.toString(true /* encoding */))); + const workspaceFolders = distinct(folders.map(folder => folder.toString(true /* skip encoding to preserve drive letters readable */))); return this.windowService.createAndOpenWorkspace(workspaceFolders); } diff --git a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts index c8465be42aabf1edddd5e2d3a4dc8ba96d252e42..103be1a380fc1f86f671171239626f8b11b09358 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts @@ -39,6 +39,7 @@ import { Themable, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_T import { attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { IMessageService } from 'vs/platform/message/common/message'; import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; export enum Rochade { NONE, @@ -152,7 +153,8 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro @IWindowsService private windowsService: IWindowsService, @IThemeService themeService: IThemeService, @IFileService private fileService: IFileService, - @IMessageService private messageService: IMessageService + @IMessageService private messageService: IMessageService, + @IWorkspacesService private workspacesService: IWorkspacesService ) { super(themeService); @@ -1118,7 +1120,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro else { const droppedResources = extractResources(e).filter(r => r.resource.scheme === 'file' || r.resource.scheme === 'untitled'); if (droppedResources.length) { - handleWorkspaceExternalDrop(droppedResources, $this.fileService, $this.messageService, $this.windowsService, $this.windowService).then(handled => { + handleWorkspaceExternalDrop(droppedResources, $this.fileService, $this.messageService, $this.windowsService, $this.windowService, $this.workspacesService).then(handled => { if (handled) { return; } diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 88561c185a7ce6d49303b7f06deeb742dd2f94f1..d03ccd2d2020a813fdcd5848bde93ea253c91ac0 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -43,6 +43,7 @@ import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; import { activeContrastBorder, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; interface IEditorInputLabel { name: string; @@ -74,7 +75,8 @@ export class TabsTitleControl extends TitleControl { @IWindowService private windowService: IWindowService, @IWindowsService private windowsService: IWindowsService, @IThemeService themeService: IThemeService, - @IFileService private fileService: IFileService + @IFileService private fileService: IFileService, + @IWorkspacesService private workspacesService: IWorkspacesService ) { super(contextMenuService, instantiationService, editorService, editorGroupService, contextKeyService, keybindingService, telemetryService, messageService, menuService, quickOpenService, themeService); @@ -691,7 +693,7 @@ export class TabsTitleControl extends TitleControl { if (droppedResources.length) { DOM.EventHelper.stop(e, true); - handleWorkspaceExternalDrop(droppedResources, this.fileService, this.messageService, this.windowsService, this.windowService).then(handled => { + handleWorkspaceExternalDrop(droppedResources, this.fileService, this.messageService, this.windowsService, this.windowService, this.workspacesService).then(handled => { if (handled) { return; } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 9f8c718ebd2dddb3c7296a84d5aa3ef0fb190bdc..9ea0997f0d85d734ce41fe44ddd6c12c318bb2e3 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -40,10 +40,11 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Themable } from 'vs/workbench/common/theme'; import { IDraggedResource } from 'vs/base/browser/dnd'; -import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { WORKSPACE_EXTENSION, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { extname } from 'vs/base/common/paths'; import { IFileService } from 'vs/platform/files/common/files'; import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import URI from 'vs/base/common/uri'; export interface IToolbarActions { primary: IAction[]; @@ -492,7 +493,8 @@ export function handleWorkspaceExternalDrop( fileService: IFileService, messageService: IMessageService, windowsService: IWindowsService, - windowService: IWindowService + windowService: IWindowService, + workspacesService: IWorkspacesService ): TPromise { // Return early if there are no external resources @@ -501,40 +503,54 @@ export function handleWorkspaceExternalDrop( return TPromise.as(false); } + const externalWorkspaceResources: { workspaces: URI[], folders: URI[] } = { + workspaces: [], + folders: [] + }; + return TPromise.join(externalResources.map(resource => { // Check for Workspace if (extname(resource.fsPath) === `.${WORKSPACE_EXTENSION}`) { - return TPromise.as(true); // Workspace + externalWorkspaceResources.workspaces.push(resource); + + return void 0; } // Check for Folder - return fileService.resolveFile(resource).then(stat => stat.isDirectory, error => false); - })).then(res => { + return fileService.resolveFile(resource).then(stat => { + if (stat.isDirectory) { + externalWorkspaceResources.folders.push(stat.resource); + } + }, error => void 0); + })).then(_ => { + const { workspaces, folders } = externalWorkspaceResources; // Return early if no external resource is a folder or workspace - const openAsWorkspace = res.some(res => !!res); - if (!openAsWorkspace) { - return false; // not handled as workspace + if (workspaces.length === 0 && folders.length === 0) { + return false; } // Pass focus to window windowService.focusWindow(); - // Ask the user when opening a potential large number of folders - let doOpen = true; - if (externalResources.length > 20) { - doOpen = messageService.confirm({ - message: nls.localize('confirmOpen', "Are you sure you want to open {0} workspaces?", externalResources.length), - primaryButton: nls.localize({ key: 'confirmOpenButton', comment: ['&& denotes a mnemonic'] }, "&&Open"), - type: 'question' - }); + let workspacesToOpen: TPromise; + + // Open in separate windows if we drop workspaces or just one folder + if (workspaces.length > 0 || folders.length === 1) { + workspacesToOpen = TPromise.as([...workspaces, ...folders].map(resources => resources.fsPath)); } - if (doOpen) { - windowsService.openWindow(externalResources.map(r => r.fsPath), { forceReuseWindow: true }); + // Multiple folders: Create new workspace with folders and open + else if (folders.length > 1) { + workspacesToOpen = workspacesService.createWorkspace([...folders].map(folder => folder.toString(true /* skip encoding to preserve drive letters readable */))).then(workspace => [workspace.configPath]); } + // Open + workspacesToOpen.then(workspaces => { + windowsService.openWindow(workspaces, { forceReuseWindow: true }); + }); + return true; }); } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index f7a75b6a00ca3c80dd668cc5b1f19bc18c8f1103..01f266cf06d9ceae2f077062f6d67d66e6622a8c 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -895,7 +895,7 @@ export class FileDragAndDrop implements IDragAndDrop { const currentRoots = this.contextService.getWorkspace().roots; const newRoots = [...currentRoots, ...folders]; - return this.windowService.createAndOpenWorkspace(distinct(newRoots.map(root => root.toString(true /* encoding */)))); + return this.windowService.createAndOpenWorkspace(distinct(newRoots.map(root => root.toString(true /* skip encoding to preserve drive letters readable */)))); } }