microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.5.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/commandPaletteHandler.ts

320lines · modeblame

bef522ffMeena Kunnathur Balakrishnan10 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
6e179583digeff10 years ago4import * as vscode from "vscode";
5import * as Q from "q";
0a68f8dbArtem Egorov8 years ago6import * as XDL from "./exponent/xdlInterface";
df4bce40digeff10 years ago7import {SettingsHelper} from "./settingsHelper";
0a68f8dbArtem Egorov8 years ago8import {OutputChannelLogger} from "./log/OutputChannelLogger";
1c32fe84Patricio Beltran9 years ago9import {Packager, PackagerRunAs} from "../common/packager";
0a68f8dbArtem Egorov8 years ago10import {AndroidPlatform} from "./android/androidPlatform";
11import {IOSPlatform} from "./ios/iOSPlatform";
2e432a9eArtem Egorov8 years ago12import {PackagerStatus} from "./packagerStatusIndicator";
b0061ac6Meena Kunnathur Balakrishnan10 years ago13import {ReactNativeProjectHelper} from "../common/reactNativeProjectHelper";
aeaf46bcMeena Kunnathur Balakrishnan10 years ago14import {TargetPlatformHelper} from "../common/targetPlatformHelper";
d976d077Meena Kunnathur Balakrishnan10 years ago15import {TelemetryHelper} from "../common/telemetryHelper";
0a68f8dbArtem Egorov8 years ago16import {ExponentHelper} from "./exponent/exponentHelper";
4edcda70Artem Egorov8 years ago17import {ReactDirManager} from "./reactDirManager";
18import {ExtensionServer} from "./extensionServer";
bef522ffMeena Kunnathur Balakrishnan10 years ago19
4edcda70Artem Egorov8 years ago20interface IReactNativeStuff {
21packager: Packager;
2e432a9eArtem Egorov8 years ago22exponentHelper: ExponentHelper;
4edcda70Artem Egorov8 years ago23reactDirManager: ReactDirManager;
24extensionServer: ExtensionServer;
25}
26interface IReactNativeProject extends IReactNativeStuff {
2e432a9eArtem Egorov8 years ago27workspaceFolder: vscode.WorkspaceFolder;
28}
29
e1c05e69dlebu10 years ago30export class CommandPaletteHandler {
4edcda70Artem Egorov8 years ago31private static projectsCache: {[key: string]: IReactNativeProject} = {};
2e432a9eArtem Egorov8 years ago32private static logger: OutputChannelLogger = OutputChannelLogger.getMainChannel();
33
4edcda70Artem Egorov8 years ago34public static addFolder(workspaceFolder: vscode.WorkspaceFolder, stuff: IReactNativeStuff): void {
35this.projectsCache[workspaceFolder.uri.fsPath] = {
36...stuff,
2e432a9eArtem Egorov8 years ago37workspaceFolder,
38};
39}
bef522ffMeena Kunnathur Balakrishnan10 years ago40
4edcda70Artem Egorov8 years ago41public static getFolder(workspaceFolder: vscode.WorkspaceFolder): IReactNativeProject {
42return this.projectsCache[workspaceFolder.uri.fsPath];
2e432a9eArtem Egorov8 years ago43}
44
4edcda70Artem Egorov8 years ago45public static delFolder(workspaceFolder: vscode.WorkspaceFolder): void {
46delete this.projectsCache[workspaceFolder.uri.fsPath];
bef522ffMeena Kunnathur Balakrishnan10 years ago47}
48
0904a0d7Meena Kunnathur Balakrishnan10 years ago49/**
50* Starts the React Native packager
51*/
2e432a9eArtem Egorov8 years ago52public static startPackager(): Q.Promise<void> {
53return this.selectProject()
54.then((project: IReactNativeProject) => {
55return this.executeCommandInContext("startPackager", project.workspaceFolder, () =>
4edcda70Artem Egorov8 years ago56project.packager.isRunning()
2e432a9eArtem Egorov8 years ago57.then((running) => {
4edcda70Artem Egorov8 years ago58return running ? project.packager.stop() : Q.resolve(void 0);
2e432a9eArtem Egorov8 years ago59})
60)
61.then(() => this.runStartPackagerCommandAndUpdateStatus(project));
62});
1c32fe84Patricio Beltran9 years ago63}
64
65/**
66* Starts the Exponent packager
67*/
2e432a9eArtem Egorov8 years ago68public static startExponentPackager(): Q.Promise<void> {
69return this.selectProject()
70.then((project: IReactNativeProject) => {
71return this.executeCommandInContext("startExponentPackager", project.workspaceFolder, () =>
4edcda70Artem Egorov8 years ago72project.packager.isRunning()
2e432a9eArtem Egorov8 years ago73.then((running) => {
4edcda70Artem Egorov8 years ago74return running ? project.packager.stop() : Q.resolve(void 0);
2e432a9eArtem Egorov8 years ago75})
76).then(() =>
77project.exponentHelper.configureExponentEnvironment()
78).then(() => this.runStartPackagerCommandAndUpdateStatus(project, PackagerRunAs.EXPONENT));
79});
bef522ffMeena Kunnathur Balakrishnan10 years ago80}
81
0904a0d7Meena Kunnathur Balakrishnan10 years ago82/**
83* Kills the React Native packager invoked by the extension's packager
84*/
2e432a9eArtem Egorov8 years ago85public static stopPackager(): Q.Promise<void> {
86return this.selectProject()
87.then((project: IReactNativeProject) => {
4edcda70Artem Egorov8 years ago88return this.executeCommandInContext("stopPackager", project.workspaceFolder, () => project.packager.stop())
89.then(() => project.packager.statusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STOPPED));
2e432a9eArtem Egorov8 years ago90});
3194e9afMeena Kunnathur Balakrishnan10 years ago91}
92
4edcda70Artem Egorov8 years ago93public static stopAllPackagers(): Q.Promise<void> {
94let keys = Object.keys(this.projectsCache);
95let promises: Q.Promise<void>[] = [];
96keys.forEach((key) => {
97let project = this.projectsCache[key];
98promises.push(this.executeCommandInContext("stopPackager", project.workspaceFolder, () => project.packager.stop())
99.then(() => project.packager.statusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STOPPED)));
100});
101
102return Q.all(promises).then(() => {});
103}
104
f2a58eefBret Johnson9 years ago105/**
106* Restarts the React Native packager
107*/
2e432a9eArtem Egorov8 years ago108public static restartPackager(): Q.Promise<void> {
109return this.selectProject()
110.then((project: IReactNativeProject) => {
111return this.executeCommandInContext("restartPackager", project.workspaceFolder, () =>
112this.runRestartPackagerCommandAndUpdateStatus(project));
113});
f2a58eefBret Johnson9 years ago114}
115
7893fb7eJimmy Thomson9 years ago116/**
117* Execute command to publish to exponent host.
118*/
2e432a9eArtem Egorov8 years ago119public static publishToExpHost(): Q.Promise<void> {
120return this.selectProject()
121.then((project: IReactNativeProject) => {
122return this.executeCommandInContext("publishToExpHost", project.workspaceFolder, () => {
123return this.executePublishToExpHost(project).then((didPublish) => {
124if (!didPublish) {
125CommandPaletteHandler.logger.warning("Publishing was unsuccessful. Please make sure you are logged in Exponent and your project is a valid Exponentjs project");
126}
127});
128});
7893fb7eJimmy Thomson9 years ago129});
130}
131
3194e9afMeena Kunnathur Balakrishnan10 years ago132/**
133* Executes the 'react-native run-android' command
134*/
2e432a9eArtem Egorov8 years ago135public static runAndroid(target: "device" | "simulator" = "simulator"): Q.Promise<void> {
2d8b9177Daniel Lebu10 years ago136TargetPlatformHelper.checkTargetPlatformSupport("android");
2e432a9eArtem Egorov8 years ago137return this.selectProject()
138.then((project: IReactNativeProject) => {
139return this.executeCommandInContext("runAndroid", project.workspaceFolder, () => this.executeWithPackagerRunning(project, () => {
a41f5c68Artem Egorov8 years ago140const packagerPort = SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath);
4edcda70Artem Egorov8 years ago141const runArgs = SettingsHelper.getRunArgs("android", target, project.workspaceFolder.uri);
a41f5c68Artem Egorov8 years ago142const platform = new AndroidPlatform({ platform: "android", workspaceRoot: project.workspaceFolder.uri.fsPath, projectRoot: project.workspaceFolder.uri.fsPath, packagerPort: packagerPort, runArguments: runArgs }, {
4edcda70Artem Egorov8 years ago143packager: project.packager,
2e432a9eArtem Egorov8 years ago144});
145return platform.runApp(/*shouldLaunchInAllDevices*/true)
146.then(() => {
147return platform.disableJSDebuggingMode();
148});
149}));
0a68f8dbArtem Egorov8 years ago150});
3194e9afMeena Kunnathur Balakrishnan10 years ago151}
152
153/**
154* Executes the 'react-native run-ios' command
155*/
2e432a9eArtem Egorov8 years ago156public static runIos(target: "device" | "simulator" = "simulator"): Q.Promise<void> {
6e7f90d8Daniel Lebu10 years ago157TargetPlatformHelper.checkTargetPlatformSupport("ios");
2e432a9eArtem Egorov8 years ago158return this.selectProject()
159.then((project: IReactNativeProject) => {
160return this.executeCommandInContext("runIos", project.workspaceFolder, () => this.executeWithPackagerRunning(project, () => {
a41f5c68Artem Egorov8 years ago161const packagerPort = SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath);
4edcda70Artem Egorov8 years ago162const runArgs = SettingsHelper.getRunArgs("ios", target, project.workspaceFolder.uri);
163const platform = new IOSPlatform({ platform: "ios", workspaceRoot: project.workspaceFolder.uri.fsPath, projectRoot: project.workspaceFolder.uri.fsPath, packagerPort, runArguments: runArgs }, { packager: project.packager });
2e432a9eArtem Egorov8 years ago164
165// Set the Debugging setting to disabled, because in iOS it's persisted across runs of the app
166return platform.disableJSDebuggingMode()
167.catch(() => { }) // If setting the debugging mode fails, we ignore the error and we run the run ios command anyways
168.then(() => {
169return platform.runApp();
170});
171}));
172});
3194e9afMeena Kunnathur Balakrishnan10 years ago173}
174
2e432a9eArtem Egorov8 years ago175public static showDevMenu(): Q.Promise<void> {
a41f5c68Artem Egorov8 years ago176return this.selectProject()
177.then((project: IReactNativeProject) => {
178AndroidPlatform.showDevMenu()
179.catch(() => { }); // Ignore any errors
4edcda70Artem Egorov8 years ago180IOSPlatform.showDevMenu(project.workspaceFolder.uri.fsPath)
a41f5c68Artem Egorov8 years ago181.catch(() => { }); // Ignore any errors
182return Q.resolve(void 0);
183});
7daed3fcArtem Egorov8 years ago184}
185
2e432a9eArtem Egorov8 years ago186public static reloadApp(): Q.Promise<void> {
a41f5c68Artem Egorov8 years ago187return this.selectProject()
188.then((project: IReactNativeProject) => {
189AndroidPlatform.reloadApp()
190.catch(() => { }); // Ignore any errors
4edcda70Artem Egorov8 years ago191IOSPlatform.reloadApp(project.workspaceFolder.uri.fsPath)
a41f5c68Artem Egorov8 years ago192.catch(() => { }); // Ignore any errors
193return Q.resolve(void 0);
194});
7daed3fcArtem Egorov8 years ago195}
196
2e432a9eArtem Egorov8 years ago197private static runRestartPackagerCommandAndUpdateStatus(project: IReactNativeProject): Q.Promise<void> {
4edcda70Artem Egorov8 years ago198return project.packager.restart(SettingsHelper.getPackagerPort(project.workspaceFolder.uri.fsPath))
199.then(() => project.packager.statusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STARTED));
f2a58eefBret Johnson9 years ago200}
201
1c32fe84Patricio Beltran9 years ago202/**
203* Helper method to run packager and update appropriate configurations
204*/
2e432a9eArtem Egorov8 years ago205private static runStartPackagerCommandAndUpdateStatus(project: IReactNativeProject, startAs: PackagerRunAs = PackagerRunAs.REACT_NATIVE): Q.Promise<any> {
1c32fe84Patricio Beltran9 years ago206if (startAs === PackagerRunAs.EXPONENT) {
2e432a9eArtem Egorov8 years ago207return this.loginToExponent(project)
7059d307Patricio Beltran9 years ago208.then(() =>
4edcda70Artem Egorov8 years ago209project.packager.startAsExponent()
7059d307Patricio Beltran9 years ago210).then(exponentUrl => {
4edcda70Artem Egorov8 years ago211project.packager.statusIndicator.updatePackagerStatus(PackagerStatus.EXPONENT_PACKAGER_STARTED);
2e432a9eArtem Egorov8 years ago212CommandPaletteHandler.logger.info("Application is running on Exponent.");
280c0746Patricio Beltran9 years ago213const exponentOutput = `Open your exponent app at ${exponentUrl}`;
2e432a9eArtem Egorov8 years ago214CommandPaletteHandler.logger.info(exponentOutput);
e23fa745Vladimir Kotikov9 years ago215vscode.commands.executeCommand("vscode.previewHtml", vscode.Uri.parse(exponentUrl), 1, "Expo QR code");
1c32fe84Patricio Beltran9 years ago216});
217}
4edcda70Artem Egorov8 years ago218return project.packager.startAsReactNative()
219.then(() => project.packager.statusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STARTED));
5e651f3edigeff10 years ago220}
221
52f3873ddigeff10 years ago222/**
223* Executes a lambda function after starting the packager
224* {lambda} The lambda function to be executed
225*/
2e432a9eArtem Egorov8 years ago226private static executeWithPackagerRunning(project: IReactNativeProject, lambda: () => Q.Promise<void>): Q.Promise<void> {
ec6e115dMeena Kunnathur Balakrishnan10 years ago227// Start the packager before executing the React-Native command
2e432a9eArtem Egorov8 years ago228CommandPaletteHandler.logger.info("Attempting to start the React Native packager");
229return this.runStartPackagerCommandAndUpdateStatus(project).then(lambda);
3194e9afMeena Kunnathur Balakrishnan10 years ago230}
b3a793eeNisheet Jain10 years ago231
232/**
233* Ensures that we are in a React Native project and then executes the operation
234* Otherwise, displays an error message banner
235* {operation} - a function that performs the expected operation
236*/
2e432a9eArtem Egorov8 years ago237private static executeCommandInContext(rnCommand: string, workspaceFolder: vscode.WorkspaceFolder, operation: () => Q.Promise<void>): Q.Promise<void> {
10873e11digeff10 years ago238return TelemetryHelper.generate("RNCommand", (generator) => {
8512ccfeMeena Kunnathur Balakrishnan10 years ago239generator.add("command", rnCommand, false);
a41f5c68Artem Egorov8 years ago240return ReactNativeProjectHelper.isReactNativeProject(workspaceFolder.uri.fsPath).then(isRNProject => {
0633e07bMeena Kunnathur Balakrishnan10 years ago241generator.add("isRNProject", isRNProject, false);
8512ccfeMeena Kunnathur Balakrishnan10 years ago242if (isRNProject) {
cf138e34Meena Kunnathur Balakrishnan10 years ago243// Bring the log channel to focus
2e432a9eArtem Egorov8 years ago244CommandPaletteHandler.logger.setFocusOnLogChannel();
cf138e34Meena Kunnathur Balakrishnan10 years ago245
246// Execute the operation
8512ccfeMeena Kunnathur Balakrishnan10 years ago247return operation();
248} else {
249vscode.window.showErrorMessage("Current workspace is not a React Native project.");
3c172a05Artem Egorov8 years ago250return;
8512ccfeMeena Kunnathur Balakrishnan10 years ago251}
252});
10873e11digeff10 years ago253});
b3a793eeNisheet Jain10 years ago254}
7893fb7eJimmy Thomson9 years ago255
256/**
257* Publish project to exponent server. In order to do this we need to make sure the user is logged in exponent and the packager is running.
258*/
2e432a9eArtem Egorov8 years ago259private static executePublishToExpHost(project: IReactNativeProject): Q.Promise<boolean> {
260CommandPaletteHandler.logger.info("Publishing app to Exponent server. This might take a moment.");
261return this.loginToExponent(project)
7059d307Patricio Beltran9 years ago262.then(user => {
2e432a9eArtem Egorov8 years ago263CommandPaletteHandler.logger.debug(`Publishing as ${user.username}...`);
7059d307Patricio Beltran9 years ago264return this.startExponentPackager()
265.then(() =>
a41f5c68Artem Egorov8 years ago266XDL.publish(project.workspaceFolder.uri.fsPath))
7059d307Patricio Beltran9 years ago267.then(response => {
268if (response.err || !response.url) {
269return false;
270}
271const publishedOutput = `App successfully published to ${response.url}`;
2e432a9eArtem Egorov8 years ago272CommandPaletteHandler.logger.info(publishedOutput);
7059d307Patricio Beltran9 years ago273vscode.window.showInformationMessage(publishedOutput);
274return true;
275});
276}).catch(() => {
2e432a9eArtem Egorov8 years ago277CommandPaletteHandler.logger.warning("An error has occured. Please make sure you are logged in to exponent, your project is setup correctly for publishing and your packager is running as exponent.");
7893fb7eJimmy Thomson9 years ago278return false;
7059d307Patricio Beltran9 years ago279});
280}
281
2e432a9eArtem Egorov8 years ago282private static loginToExponent(project: IReactNativeProject): Q.Promise<XDL.IUser> {
283return project.exponentHelper.loginToExponent(
5c8365a6Artem Egorov8 years ago284(message, password) => {
285return Q.Promise((resolve, reject) => {
286vscode.window.showInputBox({ placeHolder: message, password: password })
2e432a9eArtem Egorov8 years ago287.then(login => {
288resolve(login || "");
289}, reject);
5c8365a6Artem Egorov8 years ago290});
291},
292(message) => {
293return Q.Promise((resolve, reject) => {
294vscode.window.showInformationMessage(message)
2e432a9eArtem Egorov8 years ago295.then(password => {
296resolve(password || "");
297}, reject);
5c8365a6Artem Egorov8 years ago298});
299}
7059d307Patricio Beltran9 years ago300);
7893fb7eJimmy Thomson9 years ago301}
2e432a9eArtem Egorov8 years ago302
303private static selectProject(): Q.Promise<IReactNativeProject> {
304let keys = Object.keys(this.projectsCache);
305if (keys.length > 1) {
306return Q.Promise((resolve, reject) => {
307vscode.window.showQuickPick(keys)
308.then((selected) => {
309if (selected) {
310resolve(this.projectsCache[selected]);
311}
312}, reject);
313});
314} else if (keys.length === 1) {
315return Q.resolve(this.projectsCache[keys[0]]);
316} else {
317return Q.reject();
318}
319}
bef522ffMeena Kunnathur Balakrishnan10 years ago320}