diff --git a/.gitignore b/.gitignore index fa4e7c02e4bb..343a0c6a87c7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,3 @@ npm-debug.log # optional dev config file and plugins directory .hyper.js .hyper_plugins - diff --git a/app/index.js b/app/index.js index e4456b1c39fa..03287d29bdca 100644 --- a/app/index.js +++ b/app/index.js @@ -49,7 +49,6 @@ const isDev = require('electron-is-dev'); // Ours const AutoUpdater = require('./auto-updater'); const toElectronBackgroundColor = require('./utils/to-electron-background-color'); -const createMenu = require('./menu'); const createRPC = require('./rpc'); const notify = require('./notify'); const fetchNotifications = require('./notifications'); @@ -61,6 +60,7 @@ const config = require('./config'); config.init(); +const createMenu = require('./menu'); const plugins = require('./plugins'); const Session = require('./session'); @@ -198,7 +198,8 @@ app.on('ready', () => installDevExtensions(isDev).then(() => { // If no callback is passed to createWindow, // a new session will be created by default. if (!fn) { - fn = win => win.rpc.emit('termgroup add req'); + const shellOpts = options.shellOpts || {}; + fn = win => win.rpc.emit('termgroup add req', {shellOpts}); } // app.windowCallback is the createWindow callback @@ -217,9 +218,9 @@ app.on('ready', () => installDevExtensions(isDev).then(() => { } }); - rpc.on('new', ({rows = 40, cols = 100, cwd = process.argv[1] && isAbsolute(process.argv[1]) ? process.argv[1] : homedir(), splitDirection}) => { - const shell = cfg.shell; - const shellArgs = cfg.shellArgs && Array.from(cfg.shellArgs); + rpc.on('new', ({rows = 40, cols = 100, shellOpts = {}, cwd = process.argv[1] && isAbsolute(process.argv[1]) ? process.argv[1] : homedir(), splitDirection}) => { + const shell = shellOpts.path || cfg.shell; + const shellArgs = shellOpts.args || (cfg.shellArgs && Array.from(cfg.shellArgs)); initSession({rows, cols, cwd, shell, shellArgs}, (uid, session) => { sessions.set(uid, session); diff --git a/app/menu.js b/app/menu.js index cca978575aac..5ecd5864aebc 100644 --- a/app/menu.js +++ b/app/menu.js @@ -1,12 +1,16 @@ +'use strict'; + const os = require('os'); const path = require('path'); const {app, shell, dialog} = require('electron'); const {accelerators} = require('./accelerators'); -const {getConfigDir} = require('./config'); +const {getConfig,getConfigDir} = require('./config'); const isMac = process.platform === 'darwin'; const appName = app.getName(); +const shells = getConfig().shells || {}; +const shellKeys = Object.keys(shells); // based on and inspired by // https://github.com/sindresorhus/anatine/blob/master/menu.js @@ -59,6 +63,56 @@ module.exports = ({createWindow, updatePlugins}) => { ] }; + const otherShellsMenu = { + label: 'Other Shells', + submenu: [] + }; + + for (const shellName of shellKeys) { + const shellOpts = shells[shellName]; + + otherShellsMenu.submenu.push({ + label: shellName, + submenu: [ + { + label: 'New Window', + click() { + createWindow(null, {shellOpts}); + } + }, + { + label: 'New Tab', + click(item, focusedWindow) { + if (focusedWindow) { + focusedWindow.rpc.emit('termgroup add req', {shellOpts}); + } else { + createWindow(null, {shellOpts}); + } + } + }, + { + type: 'separator' + }, + { + label: 'Split Vertically', + click(item, focusedWindow) { + if (focusedWindow) { + focusedWindow.rpc.emit('split request vertical', {shellOpts}); + } + } + }, + { + label: 'Split Horizontally', + click(item, focusedWindow) { + if (focusedWindow) { + focusedWindow.rpc.emit('split request horizontal', {shellOpts}); + } + } + } + ] + }); + } + const shellOrFileMenu = { label: isMac ? 'Shell' : 'File', submenu: [ @@ -101,6 +155,11 @@ module.exports = ({createWindow, updatePlugins}) => { } } }, + ...( + shellKeys.length > 0 ? + [{type: 'separator'}, otherShellsMenu] : + [] + ), { type: 'separator' }, diff --git a/lib/actions/term-groups.js b/lib/actions/term-groups.js index 15f7bfac9c9d..e9ab28f7fe16 100644 --- a/lib/actions/term-groups.js +++ b/lib/actions/term-groups.js @@ -12,14 +12,16 @@ import getRootGroups from '../selectors'; import {setActiveSession, ptyExitSession, userExitSession} from './sessions'; function requestSplit(direction) { - return () => (dispatch, getState) => { + return options => (dispatch, getState) => { + const {shellOpts} = options || {}; const {ui} = getState(); dispatch({ type: SESSION_REQUEST, effect: () => { rpc.emit('new', { splitDirection: direction, - cwd: ui.cwd + cwd: ui.cwd, + shellOpts }); } }); @@ -37,8 +39,9 @@ export function resizeTermGroup(uid, sizes) { }; } -export function requestTermGroup() { +export function requestTermGroup(options) { return (dispatch, getState) => { + const {shellOpts} = options || {}; const {ui} = getState(); const {cols, rows, cwd} = ui; dispatch({ @@ -48,7 +51,8 @@ export function requestTermGroup() { isNewGroup: true, cols, rows, - cwd + cwd, + shellOpts }); } }); diff --git a/lib/index.js b/lib/index.js index 093ace47767b..dc9f95881b2b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -86,16 +86,16 @@ rpc.on('session clear req', () => { store_.dispatch(sessionActions.clearActiveSession()); }); -rpc.on('termgroup add req', () => { - store_.dispatch(termGroupActions.requestTermGroup()); +rpc.on('termgroup add req', options => { + store_.dispatch(termGroupActions.requestTermGroup(options)); }); -rpc.on('split request horizontal', () => { - store_.dispatch(termGroupActions.requestHorizontalSplit()); +rpc.on('split request horizontal', options => { + store_.dispatch(termGroupActions.requestHorizontalSplit(options)); }); -rpc.on('split request vertical', () => { - store_.dispatch(termGroupActions.requestVerticalSplit()); +rpc.on('split request vertical', options => { + store_.dispatch(termGroupActions.requestVerticalSplit(options)); }); rpc.on('reset fontSize req', () => {