提交 f6debb87 编写于 作者: B Benjamin Pasero

multi root - add action to add folders

上级 3be08cf8
......@@ -28,6 +28,7 @@ import { isEqual, isEqualOrParent } from 'vs/base/common/paths';
import { IWindowsMainService, IOpenConfiguration } from "vs/platform/windows/electron-main/windows";
import { IHistoryMainService } from "vs/platform/history/electron-main/historyMainService";
import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from "vs/base/common/platform";
import { TPromise } from "vs/base/common/winjs.base";
enum WindowError {
UNRESPONSIVE,
......@@ -1141,6 +1142,14 @@ export class WindowsManager implements IWindowsMainService {
this.fileDialog.pickAndOpen({ pickFolders: true, forceNewWindow, window }, 'openFolder', data);
}
public pickFolder(): TPromise<string[]> {
return new TPromise((c, e) => {
this.fileDialog.getFileOrFolderPaths({ pickFolders: true }, folders => {
c(folders || []);
});
});
}
public quit(): void {
// If the user selected to exit from an extension development host window, do not quit, but just
......@@ -1193,7 +1202,7 @@ class FileDialog {
});
}
private getFileOrFolderPaths(options: INativeOpenDialogOptions, clb: (paths: string[]) => void): void {
public getFileOrFolderPaths(options: INativeOpenDialogOptions, clb: (paths: string[]) => void): void {
const workingDir = options.path || this.storageService.getItem<string>(FileDialog.workingDirPickerStorageKey);
const focussedWindow = options.window || this.windowsMainService.getFocusedWindow();
......
......@@ -24,6 +24,7 @@ export interface IWindowsService {
pickFileFolderAndOpen(windowId: number, forceNewWindow?: boolean, data?: ITelemetryData): TPromise<void>;
pickFileAndOpen(windowId: number, forceNewWindow?: boolean, path?: string, data?: ITelemetryData): TPromise<void>;
pickFolderAndOpen(windowId: number, forceNewWindow?: boolean, data?: ITelemetryData): TPromise<void>;
pickFolder(): TPromise<string[]>;
reloadWindow(windowId: number): TPromise<void>;
openDevTools(windowId: number): TPromise<void>;
toggleDevTools(windowId: number): TPromise<void>;
......@@ -77,6 +78,7 @@ export interface IWindowService {
pickFileFolderAndOpen(forceNewWindow?: boolean, data?: ITelemetryData): TPromise<void>;
pickFileAndOpen(forceNewWindow?: boolean, path?: string, data?: ITelemetryData): TPromise<void>;
pickFolderAndOpen(forceNewWindow?: boolean, data?: ITelemetryData): TPromise<void>;
pickFolder(): TPromise<string[]>;
reloadWindow(): TPromise<void>;
openDevTools(): TPromise<void>;
toggleDevTools(): TPromise<void>;
......
......@@ -17,6 +17,7 @@ export interface IWindowsChannel extends IChannel {
call(command: 'pickFileFolderAndOpen', arg: [number, boolean, ITelemetryData]): TPromise<void>;
call(command: 'pickFileAndOpen', arg: [number, boolean, string, ITelemetryData]): TPromise<void>;
call(command: 'pickFolderAndOpen', arg: [number, boolean, ITelemetryData]): TPromise<void>;
call(command: 'pickFolder'): TPromise<string[]>;
call(command: 'reloadWindow', arg: number): TPromise<void>;
call(command: 'toggleDevTools', arg: number): TPromise<void>;
call(command: 'closeFolder', arg: number): TPromise<void>;
......@@ -67,6 +68,7 @@ export class WindowsChannel implements IWindowsChannel {
case 'pickFileFolderAndOpen': return this.service.pickFileFolderAndOpen(arg[0], arg[1], arg[2]);
case 'pickFileAndOpen': return this.service.pickFileAndOpen(arg[0], arg[1], arg[2], arg[3]);
case 'pickFolderAndOpen': return this.service.pickFolderAndOpen(arg[0], arg[1], arg[2]);
case 'pickFolder': return this.service.pickFolder();
case 'reloadWindow': return this.service.reloadWindow(arg);
case 'openDevTools': return this.service.openDevTools(arg);
case 'toggleDevTools': return this.service.toggleDevTools(arg);
......@@ -127,6 +129,10 @@ export class WindowsChannelClient implements IWindowsService {
return this.channel.call('pickFolderAndOpen', [windowId, forceNewWindow, data]);
}
pickFolder(): TPromise<string[]> {
return this.channel.call('pickFolder');
}
reloadWindow(windowId: number): TPromise<void> {
return this.channel.call('reloadWindow', windowId);
}
......
......@@ -34,6 +34,10 @@ export class WindowService implements IWindowService {
return this.windowsService.pickFolderAndOpen(this.windowId, forceNewWindow, data);
}
pickFolder(): TPromise<string[]> {
return this.windowsService.pickFolder();
}
reloadWindow(): TPromise<void> {
return this.windowsService.reloadWindow(this.windowId);
}
......
......@@ -52,6 +52,7 @@ export interface IWindowsMainService {
pickFileFolderAndOpen(forceNewWindow?: boolean, data?: ITelemetryData): void;
pickFileAndOpen(forceNewWindow?: boolean, path?: string, window?: ICodeWindow, data?: ITelemetryData): void;
pickFolderAndOpen(forceNewWindow?: boolean, window?: ICodeWindow, data?: ITelemetryData): void;
pickFolder(): TPromise<string[]>;
focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow;
getLastActiveWindow(): ICodeWindow;
findWindow(workspacePath: string, filePath?: string, extensionDevelopmentPath?: string): ICodeWindow;
......
......@@ -67,6 +67,10 @@ export class WindowsService implements IWindowsService, IDisposable {
return TPromise.as(null);
}
pickFolder(): TPromise<string[]> {
return this.windowsMainService.pickFolder();
}
reloadWindow(windowId: number): TPromise<void> {
const codeWindow = this.windowsMainService.getWindowById(windowId);
......
......@@ -10,6 +10,8 @@ import { Action } from 'vs/base/common/actions';
import nls = require('vs/nls');
import { IWindowService } from 'vs/platform/windows/common/windows';
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceEditingService } from "vs/workbench/services/workspace/common/workspaceEditing";
import URI from "vs/base/common/uri";
export class OpenFolderAction extends Action {
......@@ -46,3 +48,24 @@ export class OpenFileFolderAction extends Action {
return this.windowService.pickFileFolderAndOpen(undefined, data);
}
}
export class AddFolderAction extends Action {
static ID = 'workbench.action.files.addFolder';
static LABEL = nls.localize('addFolder', "Add Folder...");
constructor(
id: string,
label: string,
@IWindowService private windowService: IWindowService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService
) {
super(id, label);
}
public run(event?: any, data?: ITelemetryData): TPromise<any> {
return this.windowService.pickFolder().then(folders => {
this.workspaceEditingService.addRoots(folders.map(folder => URI.file(folder)));
});
}
}
\ No newline at end of file
......@@ -96,6 +96,8 @@ import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, inRecentFil
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingsRegistry } from "vs/platform/keybinding/common/keybindingsRegistry";
import { getQuickNavigateHandler, inQuickOpenContext } from "vs/workbench/browser/parts/quickopen/quickopen";
import { IWorkspaceEditingService } from "vs/workbench/services/workspace/common/workspaceEditing";
import { WorkspaceEditingService } from "vs/workbench/services/workspace/node/workspaceEditingService";
export const MessagesVisibleContext = new RawContextKey<boolean>('globalMessageVisible', false);
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
......@@ -567,6 +569,9 @@ export class Workbench implements IPartService {
this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService);
serviceCollection.set(IConfigurationEditingService, this.configurationEditingService);
// Workspace Editing
serviceCollection.set(IWorkspaceEditingService, new SyncDescriptor(WorkspaceEditingService));
// Keybinding Editing
serviceCollection.set(IKeybindingEditingService, this.instantiationService.createInstance(KeybindingsEditingService));
......
......@@ -19,7 +19,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { FileStat } from 'vs/workbench/parts/files/common/explorerViewModel';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/fileActions';
import { OpenFolderAction, OpenFileFolderAction, AddFolderAction } from 'vs/workbench/browser/actions/fileActions';
import { copyFocusedFilesExplorerViewItem, revealInOSFocusedFilesExplorerItem, openFocusedExplorerItemSideBySideCommand, copyPathOfFocusedExplorerItem, copyPathCommand, revealInExplorerCommand, revealInOSCommand, openFolderPickerCommand, openWindowCommand, openFileInNewWindowCommand, deleteFocusedFilesExplorerViewItemCommand, moveFocusedFilesExplorerViewItemToTrashCommand, renameFocusedFilesExplorerViewItemCommand } from 'vs/workbench/parts/files/browser/fileCommands';
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
......@@ -196,6 +196,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAsAction, Save
registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewUntitledFileAction, GlobalNewUntitledFileAction.ID, GlobalNewUntitledFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_N }), 'Files: New Untitled File', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction, GlobalRevealInOSAction.ID, GlobalRevealInOSAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R) }), 'Files: Reveal Active File', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'Files: Open Active File in New Window', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(AddFolderAction, AddFolderAction.ID, AddFolderAction.LABEL), 'Files: Add Folder...', category);
if (isMacintosh) {
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'Files: Open...', category);
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import URI from "vs/base/common/uri";
export const IWorkspaceEditingService = createDecorator<IWorkspaceEditingService>('workspaceEditingService');
export interface IWorkspaceEditingService {
_serviceBrand: ServiceIdentifier<any>;
addRoots(roots: URI[]): TPromise<void>;
removeRoots(roots: URI[]): TPromise<void>;
clearRoots(): TPromise<void>;
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IWorkspaceEditingService } from "vs/workbench/services/workspace/common/workspaceEditing";
import URI from "vs/base/common/uri";
import { equals, distinct } from "vs/base/common/arrays";
import { TPromise } from "vs/base/common/winjs.base";
import { IWorkspaceContextService } from "vs/platform/workspace/common/workspace";
import { IConfigurationEditingService, ConfigurationTarget } from "vs/workbench/services/configuration/common/configurationEditing";
import { IConfigurationService } from "vs/platform/configuration/common/configuration";
interface IWorkspaceConfiguration {
[master: string]: {
folders: string[];
};
}
const workspaceConfigKey = 'workspace';
export class WorkspaceEditingService implements IWorkspaceEditingService {
public _serviceBrand: any;
constructor(
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService,
@IConfigurationService private configurationService: IConfigurationService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
) {
}
public addRoots(rootsToAdd: URI[]): TPromise<void> {
if (!this.contextService.hasWorkspace()) {
return TPromise.as(void 0); // we need a workspace to begin with
}
const roots = this.contextService.getWorkspace2().roots;
return this.doSetRoots([...roots, ...rootsToAdd]);
}
public removeRoots(rootsToRemove: URI[]): TPromise<void> {
if (!this.contextService.hasWorkspace()) {
return TPromise.as(void 0); // we need a workspace to begin with
}
const roots = this.contextService.getWorkspace2().roots;
const rootsToRemoveRaw = rootsToRemove.map(root => root.toString());
return this.doSetRoots(roots.filter(root => rootsToRemoveRaw.indexOf(root.toString()) === -1));
}
public clearRoots(roots: URI[]): TPromise<void> {
if (!this.contextService.hasWorkspace()) {
return TPromise.as(void 0); // we need a workspace to begin with
}
return this.doSetRoots([]);
}
private doSetRoots(roots: URI[]): TPromise<void> {
const workspaceUserConfig = this.configurationService.lookup(workspaceConfigKey).user as IWorkspaceConfiguration || Object.create(null);
const master = this.contextService.getWorkspace2().roots[0].toString();
const currentWorkspaceRoots = (workspaceUserConfig[master.toString()] && workspaceUserConfig[master.toString()].folders) || [];
const newWorkspaceRoots = distinct(roots.map(root => root.toString()));
// Make sure we do not set the master folder as root
const masterIndex = newWorkspaceRoots.indexOf(master);
if (masterIndex >= 0) {
newWorkspaceRoots.splice(masterIndex, 1);
}
// See if there are any changes
if (equals(currentWorkspaceRoots, newWorkspaceRoots)) {
return TPromise.as(void 0);
}
// Apply to config
workspaceUserConfig[master.toString()] = {
folders: newWorkspaceRoots
};
return this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: workspaceConfigKey, value: workspaceUserConfig }).then(() => void 0);
}
}
\ No newline at end of file
......@@ -854,6 +854,10 @@ export class TestWindowService implements IWindowService {
return TPromise.as(void 0);
}
pickFolder(): TPromise<string[]> {
return TPromise.as([]);
}
reloadWindow(): TPromise<void> {
return TPromise.as(void 0);
}
......@@ -964,96 +968,130 @@ export class TestWindowsService implements IWindowsService {
pickFileFolderAndOpen(windowId: number, forceNewWindow?: boolean): TPromise<void> {
return TPromise.as(void 0);
}
pickFileAndOpen(windowId: number, forceNewWindow?: boolean, path?: string): TPromise<void> {
return TPromise.as(void 0);
}
pickFolderAndOpen(windowId: number, forceNewWindow?: boolean): TPromise<void> {
return TPromise.as(void 0);
}
pickFolder(): TPromise<string[]> {
return TPromise.as([]);
}
reloadWindow(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
openDevTools(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
toggleDevTools(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
// TODO@joao: rename, shouldn't this be closeWindow?
closeFolder(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
toggleFullScreen(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
setRepresentedFilename(windowId: number, fileName: string): TPromise<void> {
return TPromise.as(void 0);
}
addToRecentlyOpen(paths: { path: string, isFile?: boolean }[]): TPromise<void> {
return TPromise.as(void 0);
}
removeFromRecentlyOpen(paths: string[]): TPromise<void> {
return TPromise.as(void 0);
}
clearRecentPathsList(): TPromise<void> {
return TPromise.as(void 0);
}
getRecentlyOpen(windowId: number): TPromise<{ files: string[]; folders: string[]; }> {
return TPromise.as(void 0);
}
focusWindow(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
isMaximized(windowId: number): TPromise<boolean> {
return TPromise.as(void 0);
}
maximizeWindow(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
unmaximizeWindow(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
onWindowTitleDoubleClick(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
setDocumentEdited(windowId: number, flag: boolean): TPromise<void> {
return TPromise.as(void 0);
}
quit(): TPromise<void> {
return TPromise.as(void 0);
}
relaunch(options: { addArgs?: string[], removeArgs?: string[] }): TPromise<void> {
return TPromise.as(void 0);
}
whenSharedProcessReady(): TPromise<void> {
return TPromise.as(void 0);
}
toggleSharedProcess(): TPromise<void> {
return TPromise.as(void 0);
}
// Global methods
openWindow(paths: string[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean }): TPromise<void> {
return TPromise.as(void 0);
}
openNewWindow(): TPromise<void> {
return TPromise.as(void 0);
}
showWindow(windowId: number): TPromise<void> {
return TPromise.as(void 0);
}
getWindows(): TPromise<{ id: number; path: string; title: string; }[]> {
return TPromise.as(void 0);
}
getWindowCount(): TPromise<number> {
return TPromise.as(this.windowCount);
}
log(severity: string, ...messages: string[]): TPromise<void> {
return TPromise.as(void 0);
}
// TODO@joao: what?
closeExtensionHostWindow(extensionDevelopmentPaths: string[]): TPromise<void> {
return TPromise.as(void 0);
}
showItemInFolder(path: string): TPromise<void> {
return TPromise.as(void 0);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册