Source: index.js

const exec = require('child_process').exec;
const fs = require('fs');
const path = require('path');
const commandExists = require('command-exists');
const platform = process.platform;

/**
 * Launches a Terminal at the given directory and executes a command.
 * @param {string} [command]    The command to execute in the terminal.
 * @param {string} [cwd]        The current working directory where the terminal
 *                              will be launched.
 * @param {string} [terminal=getDefaultTerminal()]
 *                              The terminal to launch. This will depend on your
 *                              operating system.
 * @param {Callback} [callback] Calls back errors.
 */
function launchTerminal(command, cwd, terminal = getDefaultTerminal(),
                        callback = noop) {

  if (!terminal) return callback(Error('Could not find the terminal.'));
  if (platform == 'darwin') {
    _getDarwinCommand(command, cwd, terminal, (err, cmd) => {
      if (err) return callback(err);
      exec(cmd, callback);
    });
  } else if (platform == 'linux') {
    exec(_getLinuxCommand(command, cwd, terminal), callback);
  } else if (platform == 'win32') {
    exec(_getWindowsCommand(command, cwd, terminal), callback);
  } else {
    callback(Error('Only Linux, OS X and Windows are supported'));
  }
}

function _getDarwinCommand(command, cwd, terminal, callback) {
  var cmd = `open -a ${terminal}`;

  if (!command) {
    if (cwd) {
      cmd = `${cmd} "${cwd}"`;
    }
    callback(null, cmd);
  } else {
    var scriptPath = path.join(__dirname, 'cmd-script.sh');
    var script = `#!/bin/bash\n${_joinCommands(cwd, command, '\n')}\n/bin/bash`;

    fs.writeFile(scriptPath, script, (err) => {
      if (err) return callback(err);
      fs.chmod(scriptPath, '755', (err) => {
        if (err) return callback(err);
        callback(null, `${cmd} "${scriptPath}"`);
      });
    });
  }
}

function _getLinuxCommand(command, cwd, terminal) {
  // http://askubuntu.com/questions/484993/run-command-on-anothernew-terminal-window
  var commands = _joinCommands(cwd, command, '; ');
  if (commands) {
    return `${terminal} -e 'bash -c "${commands}; exec bash"'`;
  }
  return terminal;
}

function _getWindowsCommand(command, cwd, terminal) {
  var term = terminal.toLowerCase().trim().replace(/\.exe$/g, '');

  switch (term) {
    case 'cmder':
      return _getCmderCommand(command, cwd);
    case 'powershell':
      return _getPowershellCommand(command, cwd);
    case 'cmd':
    default:
      return _getCmdCommand(command, cwd);
  }
}

function _getCmdCommand(command, cwd) {
  var commandSegment = '';
  if (command) {
    if (cwd) {
      commandSegment = ('"cd /d ' + cwd + ' & ' + command + '"');
    } else {
      commandSegment = command;
    }
  }
  return `start cmd /K ${commandSegment}`;
}

function _getPowershellCommand(command, cwd) {
  var commandSegment = '';
  if (command) {
    if (cwd) {
      commandSegment = ('"cd ' + cwd + ' ; ' +
        command.replace(/"/g, '\\"') + '"');
    } else {
      commandSegment = command.replace(/"/g, '\\"');
    }
  }
  return `start powershell -noexit -command ${commandSegment}`;
}

function _getCmderCommand(command, cwd) {
  var cwdSegment = '';
  if (cwd) {
    cwd = cwd.replace(/"/g, '\\"');
    cwdSegment = '/START "' + cwd + '"';
  }

  var commandSegment = '';
  if (command) {
    commandSegment = '/TASK "' + command.replace(/"/g, '\\"') + '"';
  }

  return `start cmder ${cwdSegment} ${commandSegment}`;
}

/**
 * Launches a jupyter or ipython console and connects to the kernel defined in
 * the connection file. It starts the console by execution
 * <code>jupyter jupyterConsole --existing connectionFile</code>.
 * @param {string} connectionFile The path to the connection file of the kernel
 *                                to connect to.
 * @param {string} [cwd]          The current working directory where the
 *                                terminal will be launched.
 * @param {string} [jupyterConsole=console]
 *                                The jupyter console to start (eg qtconsole).
 * @param {string} [terminal=getDefaultTerminal()]
 *                                The terminal to launch. This will depend on
 *                                your operating system.
 * @param {Callback} [callback]   Calls back errors.
 */
function launchJupyter(connectionFile, cwd, jupyterConsole = 'console',
                       terminal = getDefaultTerminal(), callback = noop) {

  getConnectionCommand(connectionFile, jupyterConsole, function(err, command) {
    if (err) return callback(err);
    launchTerminal(command, cwd, terminal, callback);
  })
}

/**
 * Returns the command to connect to the kernel defined in the connection file.
 * E.g. <code>jupyter console --existing connectionFile</code>.
 * @param {string} connectionFile The path to the connection file of the kernel
 *                                to connect to.
 * @param {string} [jupyterConsole=console]
 *                                The jupyter console to start (e.g. console or qtconsole).
 * @param {Callback} [callback]   Calls back any errors and the connection command (err, command).
 */
function getConnectionCommand(connectionFile, jupyterConsole, callback) {
  if (!callback && typeof jupyterConsole === 'function') {
    callback = jupyterConsole;
    jupyterConsole = 'console';
  }
  var args = ` ${jupyterConsole} --existing ${connectionFile}`;
  commandExists('jupyter', function(err, exist) {
    if (err) return callback(err);
    if(exist) {
      callback(null, 'jupyter' + args);
    } else {
      commandExists('ipython', function(err, exist) {
        if (err) return callback(err);
        if(exist) {
          callback(null, 'ipython' + args);
        } else {
          callback(Error('Could not find `jupyter` or `ipython`.'));
        }
      });
    }
  });
}

/**
 * Returns the default terminal for your operation system: <br>
 * macOS: Terminal.app <br>
 * Windows: cmd <br>
 * Linux: Checks for the existance of gnome-terminal, konsole, xfce4-terminal,
 *        lxterminal or xterm.
 * @return {string} terminal
 */
function getDefaultTerminal() {
  if (platform == 'darwin') {
    return 'Terminal.app';
  } else if (platform == 'win32') {
    return 'cmd';
  } else {
    // Check for existance of common terminals.
    // ref https://github.com/drelyn86/atom-terminus
    var terminal = '';
    var terms = [
      'gnome-terminal',
      'konsole',
      'xfce4-terminal',
      'lxterminal',
      'xterm'
    ];
    for (let t of terms) {
      try {
        if (fs.statSync('/usr/bin/' + t).isFile()) {
          terminal = t;
          break;
        }
      } catch (err) {/* Don't throw error */}
    }
    return terminal;
  }
}

function _joinCommands(cwd, cmd, delimiter) {
  var cmds = [];
  if (cwd) {
    cmds.push(`cd "${cwd}"`);
  }
  if (cmd) {
    cmds.push(cmd);
  }
  return cmds.join(delimiter);
}

function noop() {};

module.exports = {
  launchTerminal,
  launchJupyter,
  getDefaultTerminal,
  getConnectionCommand,
  _joinCommands,
  _getDarwinCommand,
  _getLinuxCommand,
  _getWindowsCommand,
  _getCmderCommand,
  _getPowershellCommand,
  _getCmdCommand,
};