提交 6f3f9edc 编写于 作者: B Benjamin Pasero

Add a command to open a new window as tab (Sierra tabs) (fixes #25919)

上级 ac60be30
......@@ -607,6 +607,7 @@ export class Menubar {
if (this.currentEnableNativeTabs) {
const hasMultipleWindows = this.windowsMainService.getWindowCount() > 1;
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mNewTab', "New Tab"), 'workbench.action.newWindowTab'));
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowPreviousTab', "Show Previous Tab"), 'workbench.action.showPreviousWindowTab', hasMultipleWindows));
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mShowNextTab', "Show Next Tab"), 'workbench.action.showNextWindowTab', hasMultipleWindows));
this.nativeTabMenuItems.push(this.createMenuItem(nls.localize('mMoveTabToNewWindow', "Move Tab to New Window"), 'workbench.action.moveWindowTabToNewWindow', hasMultipleWindows));
......
......@@ -500,6 +500,12 @@ export class CodeWindow implements ICodeWindow {
});
}
addTabbedWindow(window: ICodeWindow): void {
if (isMacintosh) {
this._win.addTabbedWindow(window.win);
}
}
load(config: IWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void {
// If this is the first time the window is loaded, we associate the paths
......
......@@ -81,6 +81,7 @@ interface IOpenBrowserWindowOptions {
filesToWait?: IPathsToWaitFor;
forceNewWindow?: boolean;
forceNewTabbedWindow?: boolean;
windowToUse?: ICodeWindow;
emptyWindowBackupFolder?: string;
......@@ -546,7 +547,7 @@ export class WindowsManager implements IWindowsMainService {
// Special case: we started with --wait and we got back a folder to open. In this case
// we actually prefer to not open the folder but operate purely on the file.
if (typeof bestWindowOrFolder === 'string' && filesToWait) {
//TODO: #54483 Ben This should not happen
//TODO@Ben: #54483 This should not happen
console.error(`This should not happen`, bestWindowOrFolder, WindowsManager.WINDOWS);
bestWindowOrFolder = !openFilesInNewWindow ? this.getLastActiveWindow() : null;
}
......@@ -580,7 +581,7 @@ export class WindowsManager implements IWindowsMainService {
// We found a suitable folder to open: add it to foldersToOpen
else if (typeof bestWindowOrFolder === 'string') {
//TODO: #54483 Ben This should not happen
//TODO@Ben: #54483 Ben This should not happen
// foldersToOpen.push(bestWindowOrFolder);
console.error(`This should not happen`, bestWindowOrFolder, WindowsManager.WINDOWS);
}
......@@ -595,7 +596,8 @@ export class WindowsManager implements IWindowsMainService {
filesToCreate,
filesToDiff,
filesToWait,
forceNewWindow: true
forceNewWindow: true,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow
}));
// Reset these because we handled them
......@@ -700,6 +702,7 @@ export class WindowsManager implements IWindowsMainService {
filesToDiff,
filesToWait,
forceNewWindow: true,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow,
emptyWindowBackupFolder
}));
......@@ -720,7 +723,8 @@ export class WindowsManager implements IWindowsMainService {
userEnv: openConfig.userEnv,
cli: openConfig.cli,
initialStartup: openConfig.initialStartup,
forceNewWindow: openFolderInNewWindow
forceNewWindow: openFolderInNewWindow,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow
}));
openFolderInNewWindow = true; // any other window to open must open in new window then
......@@ -767,6 +771,7 @@ export class WindowsManager implements IWindowsMainService {
filesToDiff,
filesToWait,
forceNewWindow,
forceNewTabbedWindow: openConfig.forceNewTabbedWindow,
windowToUse
});
......@@ -1128,6 +1133,7 @@ export class WindowsManager implements IWindowsMainService {
}
private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow {
// Build IWindowConfiguration from config and options
const configuration: IWindowConfiguration = mixin({}, options.cli); // inherit all properties from CLI
configuration.appRoot = this.environmentService.appRoot;
......@@ -1152,7 +1158,7 @@ export class WindowsManager implements IWindowsMainService {
}
let window: ICodeWindow;
if (!options.forceNewWindow) {
if (!options.forceNewWindow && !options.forceNewTabbedWindow) {
window = options.windowToUse || this.getLastActiveWindow();
if (window) {
window.focus();
......@@ -1179,12 +1185,21 @@ export class WindowsManager implements IWindowsMainService {
state.mode = WindowMode.Normal;
}
// Create the window
window = this.instantiationService.createInstance(CodeWindow, {
state,
extensionDevelopmentPath: configuration.extensionDevelopmentPath,
isExtensionTestHost: !!configuration.extensionTestsPath
});
// Add as window tab if configured (macOS only)
if (options.forceNewTabbedWindow) {
const activeWindow = this.getLastActiveWindow();
if (activeWindow) {
activeWindow.addTabbedWindow(window);
}
}
// Add to our list of windows
WindowsManager.WINDOWS.push(window);
......@@ -1475,6 +1490,10 @@ export class WindowsManager implements IWindowsMainService {
return this.open({ context, cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true });
}
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
}
waitForWindowCloseOrLoad(windowId: number): TPromise<void> {
return new TPromise<void>(c => {
function handler(id: number) {
......
......@@ -143,6 +143,7 @@ export interface IWindowsService {
relaunch(options: { addArgs?: string[], removeArgs?: string[] }): TPromise<void>;
// macOS Native Tabs
newWindowTab(): TPromise<void>;
showPreviousWindowTab(): TPromise<void>;
showNextWindowTab(): TPromise<void>;
moveWindowTabToNewWindow(): TPromise<void>;
......
......@@ -44,6 +44,7 @@ export interface IWindowsChannel extends IChannel {
call(command: 'removeFromRecentlyOpened', arg: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | string)[]): TPromise<void>;
call(command: 'clearRecentlyOpened'): TPromise<void>;
call(command: 'getRecentlyOpened', arg: number): TPromise<IRecentlyOpened>;
call(command: 'newWindowTab'): TPromise<void>;
call(command: 'showPreviousWindowTab'): TPromise<void>;
call(command: 'showNextWindowTab'): TPromise<void>;
call(command: 'moveWindowTabToNewWindow'): TPromise<void>;
......@@ -147,6 +148,7 @@ export class WindowsChannel implements IWindowsChannel {
return this.service.removeFromRecentlyOpened(paths);
}
case 'clearRecentlyOpened': return this.service.clearRecentlyOpened();
case 'newWindowTab': return this.service.newWindowTab();
case 'showPreviousWindowTab': return this.service.showPreviousWindowTab();
case 'showNextWindowTab': return this.service.showNextWindowTab();
case 'moveWindowTabToNewWindow': return this.service.moveWindowTabToNewWindow();
......@@ -280,6 +282,10 @@ export class WindowsChannelClient implements IWindowsService {
});
}
newWindowTab(): TPromise<void> {
return this.channel.call('newWindowTab');
}
showPreviousWindowTab(): TPromise<void> {
return this.channel.call('showPreviousWindowTab');
}
......
......@@ -48,6 +48,8 @@ export interface ICodeWindow {
readyState: ReadyState;
ready(): TPromise<ICodeWindow>;
addTabbedWindow(window: ICodeWindow): void;
load(config: IWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void;
reload(configuration?: IWindowConfiguration, cli?: ParsedArgs): void;
......@@ -110,6 +112,7 @@ export interface IWindowsMainService {
getLastActiveWindow(): ICodeWindow;
waitForWindowCloseOrLoad(windowId: number): TPromise<void>;
openNewWindow(context: OpenContext): ICodeWindow[];
openNewTabbedWindow(context: OpenContext): ICodeWindow[];
sendToFocused(channel: string, ...args: any[]): void;
sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void;
getFocusedWindow(): ICodeWindow;
......@@ -127,6 +130,7 @@ export interface IOpenConfiguration {
urisToOpen?: URI[];
preferNewWindow?: boolean;
forceNewWindow?: boolean;
forceNewTabbedWindow?: boolean;
forceReuseWindow?: boolean;
forceEmpty?: boolean;
diffMode?: boolean;
......
......@@ -258,6 +258,14 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
return TPromise.as(this.historyService.getRecentlyOpened());
}
newWindowTab(): TPromise<void> {
this.logService.trace('windowsService#newWindowTab');
this.windowsMainService.openNewTabbedWindow(OpenContext.API);
return TPromise.as(void 0);
}
showPreviousWindowTab(): TPromise<void> {
this.logService.trace('windowsService#showPreviousWindowTab');
Menu.sendActionToFirstResponder('selectPreviousTab:');
......@@ -413,7 +421,9 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
openNewWindow(): TPromise<void> {
this.logService.trace('windowsService#openNewWindow');
this.windowsMainService.openNewWindow(OpenContext.API);
return TPromise.as(null);
}
......
......@@ -1459,6 +1459,24 @@ export class DecreaseViewSizeAction extends BaseResizeViewAction {
}
}
export class NewWindowTab extends Action {
static readonly ID = 'workbench.action.newWindowTab';
static readonly LABEL = nls.localize('newTab', "New Window Tab");
constructor(
id: string,
label: string,
@IWindowsService private windowsService: IWindowsService
) {
super(NewWindowTab.ID, NewWindowTab.LABEL);
}
run(): TPromise<boolean> {
return this.windowsService.newWindowTab().then(() => true);
}
}
export class ShowPreviousWindowTab extends Action {
static readonly ID = 'workbench.action.showPreviousWindowTab';
......
......@@ -84,7 +84,7 @@ import { MenuService } from 'vs/workbench/services/actions/common/menuService';
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions';
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, ReloadWindowWithExtensionsDisabledAction, NewWindowTab } from 'vs/workbench/electron-browser/actions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
......@@ -317,6 +317,7 @@ export class Workbench extends Disposable implements IPartService {
// Actions for macOS native tabs management (only when enabled)
const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
registry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowTab, NewWindowTab.ID, NewWindowTab.LABEL), 'New Window Tab');
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowPreviousWindowTab, ShowPreviousWindowTab.ID, ShowPreviousWindowTab.LABEL), 'Show Previous Window Tab');
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowNextWindowTab, ShowNextWindowTab.ID, ShowNextWindowTab.LABEL), 'Show Next Window Tab');
registry.registerWorkbenchAction(new SyncActionDescriptor(MoveWindowTabToNewWindow, MoveWindowTabToNewWindow.ID, MoveWindowTabToNewWindow.LABEL), 'Move Window Tab to New Window');
......
......@@ -1292,6 +1292,10 @@ export class TestWindowsService implements IWindowsService {
return TPromise.as(void 0);
}
newWindowTab(): TPromise<void> {
return TPromise.as(void 0);
}
showPreviousWindowTab(): TPromise<void> {
return TPromise.as(void 0);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册