diff --git a/src/LiveDevelopment/Inspector/Inspector.js b/src/LiveDevelopment/Inspector/Inspector.js index 12508db23..1087af45d 100644 --- a/src/LiveDevelopment/Inspector/Inspector.js +++ b/src/LiveDevelopment/Inspector/Inspector.js @@ -330,7 +330,8 @@ define(function Inspector(require, exports, module) { var i, page; for (i in response) { page = response[i]; - if (page.webSocketDebuggerUrl && page.url.indexOf(url) === 0) { + if (page.webSocketDebuggerUrl && + (page.url.indexOf(url) === 0 || page.url.endsWith("/LiveDevelopment/launch.html"))) { connect(page.webSocketDebuggerUrl); // _connectDeferred may be resolved by onConnect or rejected by onError return; diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js index 22e677ae3..ca60015df 100644 --- a/src/LiveDevelopment/LiveDevelopment.js +++ b/src/LiveDevelopment/LiveDevelopment.js @@ -198,11 +198,11 @@ define(function LiveDevelopment(require, exports, module) { * Handles of registered servers */ var _regServers = []; - + PreferencesManager.definePreference("livedev.wsPort", "number", 8125, { description: Strings.DESCRIPTION_LIVEDEV_WEBSOCKET_PORT }); - + PreferencesManager.definePreference("livedev.enableReverseInspect", "boolean", true, { description: Strings.DESCRIPTION_LIVEDEV_ENABLE_REVERSE_INSPECT }); @@ -1136,10 +1136,9 @@ define(function LiveDevelopment(require, exports, module) { _openDeferred.reject(); } - function _openInterstitialPage() { + function _establishConnection() { var browserStarted = false, retryCount = 0; - // Open the live browser if the connection fails, retry 3 times Inspector.connectToURL(launcherUrl).fail(function onConnectFail(err) { if (err === "CANCEL") { @@ -1203,34 +1202,6 @@ define(function LiveDevelopment(require, exports, module) { } retryCount++; - if (!browserStarted && exports.status !== STATUS_ERROR) { - NativeApp.openLiveBrowser( - launcherUrl, - true // enable remote debugging - ) - .done(function () { - browserStarted = true; - }) - .fail(function (err) { - var message; - - _setStatus(STATUS_ERROR); - if (err === FileSystemError.NOT_FOUND) { - message = Strings.ERROR_CANT_FIND_CHROME; - } else { - message = StringUtils.format(Strings.ERROR_LAUNCHING_BROWSER, err); - } - - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_LAUNCHING_BROWSER_TITLE, - _makeTroubleshootingMessage(message) - ); - - _openDeferred.reject("OPEN_LIVE_BROWSER"); - }); - } - if (exports.status !== STATUS_ERROR) { window.setTimeout(function retryConnect() { Inspector.connectToURL(launcherUrl).fail(onConnectFail); @@ -1239,6 +1210,23 @@ define(function LiveDevelopment(require, exports, module) { }); } + function _openInterstitialPage() { + NativeApp.openLiveBrowser(launcherUrl) + .done(_establishConnection) + .fail((err)=>{ + var message; + _setStatus(STATUS_ERROR); + message = StringUtils.format(Strings.ERROR_LAUNCHING_BROWSER, err); + Dialogs.showModalDialog( + DefaultDialogs.DIALOG_ID_ERROR, + Strings.ERROR_LAUNCHING_BROWSER_TITLE, + _makeTroubleshootingMessage(message) + ); + + _openDeferred.reject("OPEN_LIVE_BROWSER"); + }); + } + // helper function that actually does the launch once we are sure we have // a doc and the server for that doc is up and running. function _doLaunchAfterServerReady(initialDoc) { @@ -1383,7 +1371,7 @@ define(function LiveDevelopment(require, exports, module) { .done(function () { var reverseInspectPref = PreferencesManager.get("livedev.enableReverseInspect"), wsPort = PreferencesManager.get("livedev.wsPort"); - + if (wsPort && reverseInspectPref) { WebSocketTransport.createWebSocketServer(wsPort); } diff --git a/src/LiveDevelopment/MultiBrowserImpl/launchers/Launcher.js b/src/LiveDevelopment/MultiBrowserImpl/launchers/Launcher.js index 0d7c452c2..b0301beb8 100644 --- a/src/LiveDevelopment/MultiBrowserImpl/launchers/Launcher.js +++ b/src/LiveDevelopment/MultiBrowserImpl/launchers/Launcher.js @@ -43,7 +43,12 @@ define(function (require, exports, module) { _nodeDomain.exec("launch", url); } + function launchChromeWithRDP(url) { + return _nodeDomain.exec("launchChromeWithRDP", url); + } + // Exports exports.launch = launch; + exports.launchChromeWithRDP = launchChromeWithRDP; }); diff --git a/src/LiveDevelopment/MultiBrowserImpl/launchers/node/LauncherDomain.js b/src/LiveDevelopment/MultiBrowserImpl/launchers/node/LauncherDomain.js index f1d202253..9171ca032 100644 --- a/src/LiveDevelopment/MultiBrowserImpl/launchers/node/LauncherDomain.js +++ b/src/LiveDevelopment/MultiBrowserImpl/launchers/node/LauncherDomain.js @@ -25,7 +25,102 @@ /*jslint node: true */ "use strict"; -var open = require("opn"); +var path = require('path'); +var childProcess = require('child_process'); +var objectAssign = require('object-assign'); +var Promise = require('pinkie-promise'); + +function open(target, opts) { + if (typeof target !== 'string') { + return Promise.reject(new Error('Expected a `target`')); + } + + opts = objectAssign({wait: true}, opts); + + var cmd; + var appArgs = []; + var args = []; + var cpOpts = {}; + + if (Array.isArray(opts.app)) { + appArgs = opts.app.slice(1); + opts.app = opts.app[0]; + } + + if (process.platform === 'darwin') { + cmd = 'open'; + + if (opts.wait) { + args.push('-W'); + } + + if (opts.app) { + args.push('-n'); + args.push('-a', opts.app); + } + } else if (process.platform === 'win32') { + cmd = 'cmd'; + args.push('/c', 'start', '""'); + target = target.replace(/&/g, '^&'); + + if (opts.wait) { + args.push('/wait'); + } + + if (opts.app) { + args.push(opts.app); + } + + if (appArgs.length > 0) { + args = args.concat(appArgs); + } + } else { + if (opts.app) { + cmd = opts.app; + } else { + cmd = path.join(__dirname, 'xdg-open'); + } + + if (appArgs.length > 0) { + args = args.concat(appArgs); + } + + if (!opts.wait) { + // xdg-open will block the process unless + // stdio is ignored even if it's unref'd + cpOpts.stdio = 'ignore'; + } + } + + args.push(target); + + if (process.platform === 'darwin' && appArgs.length > 0) { + args.push('--args'); + args = args.concat(appArgs); + } + + var cp = childProcess.spawn(cmd, args, cpOpts); + + if (opts.wait) { + return new Promise(function (resolve, reject) { + cp.once('error', reject); + + cp.once('close', function (code) { + if (code > 0) { + reject(new Error('Exited with code ' + code)); + return; + } + + resolve(cp); + }); + }); + } + + cp.unref(); + + return Promise.resolve(cp); +}; + /** * @private @@ -43,6 +138,31 @@ function _cmdLaunch(url) { open(url); } +function _launchChromeWithRDP(url, enableRemoteDebugging) { + if (process.platform === 'darwin') { + open(url, {app: ['Google Chrome', + "--disk-cache-size=250000000", + "--no-first-run", + "--no-default-browser-check", + "--disable-default-apps", + "--allow-file-access-from-files", + "--remote-debugging-port=9222", + "--user-data-dir=/tmp/BracketsChromeProfile", + "--remote-allow-origins=*" + ]}); + return; + } + open(url, {app: ['chrome', + "--disk-cache-size=250000000", + "--no-first-run", + "--no-default-browser-check", + "--disable-default-apps", + "--allow-file-access-from-files", + "--remote-debugging-port=9222", + "--user-data-dir=%appdata%/lp", + "--remote-allow-origins=*" + ]}); +} /** * Initializes the domain and registers commands. @@ -65,6 +185,19 @@ function init(domainManager) { ], [] ); + + domainManager.registerCommand( + "launcher", // domain name + "launchChromeWithRDP", // command name + _launchChromeWithRDP, // command handler function + false, // this command is synchronous in Node + "Launches a given HTML file in the browser for live development", + [ + { name: "url", type: "string", description: "file:// url to the HTML file" }, + { name: "enableRemoteDebugging", type: "string", description: "enable remote debugging or not"} + ], + [] + ); } exports.init = init; diff --git a/src/utils/NativeApp.js b/src/utils/NativeApp.js index 66f9bdee0..711e8311e 100644 --- a/src/utils/NativeApp.js +++ b/src/utils/NativeApp.js @@ -25,7 +25,8 @@ define(function (require, exports, module) { "use strict"; var Async = require("utils/Async"), - FileSystemError = require("filesystem/FileSystemError"); + FileSystemError = require("filesystem/FileSystemError"), + DefaultLauncher = require("LiveDevelopment/MultiBrowserImpl/launchers/Launcher"); /** * @private @@ -45,25 +46,10 @@ define(function (require, exports, module) { /** openLiveBrowser * Open the given URL in the user's system browser, optionally enabling debugging. * @param {string} url The URL to open. - * @param {boolean=} enableRemoteDebugging Whether to turn on remote debugging. Default false. * @return {$.Promise} */ - function openLiveBrowser(url, enableRemoteDebugging) { - var result = new $.Deferred(); - - brackets.app.openLiveBrowser(url, !!enableRemoteDebugging, function onRun(err, pid) { - if (!err) { - // Undefined ids never get removed from list, so don't push them on - if (pid !== undefined) { - liveBrowserOpenedPIDs.push(pid); - } - result.resolve(pid); - } else { - result.reject(_browserErrToFileError(err)); - } - }); - - return result.promise(); + function openLiveBrowser(url) { + return DefaultLauncher.launchChromeWithRDP(url); } /** closeLiveBrowser