microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
df4bce4041caa61af1460ef87f2380820508a455

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/commandPaletteHandler.ts

134lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as vscode from "vscode";
5import * as Q from "q";
6import {CommandExecutor} from "../common/commandExecutor";
7import {SettingsHelper} from "./settingsHelper";
8import {DeviceHelper, IDevice} from "../common/android/deviceHelper";
9import {Log} from "../common/log/log";
10import {Packager} from "../common/packager";
11import {Package} from "../common/node/package";
12import {PackageNameResolver} from "../common/android/packageNameResolver";
13import {PackagerStatus, PackagerStatusIndicator} from "./packagerStatusIndicator";
14import {ReactNativeProjectHelper} from "../common/reactNativeProjectHelper";
15import {TelemetryHelper} from "../common/telemetryHelper";
16import {IOSDebugModeManager} from "../common/ios/iOSDebugModeManager";
17
18export class CommandPaletteHandler {
19 private reactNativePackager: Packager;
20 private reactNativePackageStatusIndicator: PackagerStatusIndicator;
21 private workspaceRoot: string;
22
23 constructor(workspaceRoot: string, reactNativePackager: Packager, packagerStatusIndicator: PackagerStatusIndicator) {
24 this.workspaceRoot = workspaceRoot;
25 this.reactNativePackager = reactNativePackager;
26 this.reactNativePackageStatusIndicator = packagerStatusIndicator;
27 }
28
29 /**
30 * Starts the React Native packager
31 */
32 public startPackager(): Q.Promise<void> {
33 return this.executeCommandInContext("startPackager", () =>
34 this.runStartPackagerCommandAndUpdateStatus());
35 }
36
37 /**
38 * Kills the React Native packager invoked by the extension's packager
39 */
40 public stopPackager(): Q.Promise<void> {
41 return this.executeCommandInContext("stopPackager", () => this.reactNativePackager.stop())
42 .then(() => this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STOPPED));
43 }
44
45 /**
46 * Executes the 'react-native run-android' command
47 */
48 public runAndroid(): Q.Promise<void> {
49 /* If there are multiple devices available, the run-android command will install the application on each and then print a warning.
50 The command will succeed but the application will not be launched on any device.
51 We fix this behavior by checking if there are more than one devices available and running the application on each. */
52 return this.executeCommandInContext("runAndroid", () => this.executeReactNativeRunCommand("run-android"))
53 .then(() => {
54 let deviceHelper = new DeviceHelper();
55 let pkg = new Package(this.workspaceRoot);
56
57 return Q.all<any>([
58 pkg.name().then((appName) => new PackageNameResolver(appName).resolvePackageName(this.workspaceRoot)),
59 deviceHelper.getConnectedDevices(),
60 ]).spread<any>((packagName: string, devices: IDevice[]) => {
61 if (devices.length > 1) {
62 let result = Q<void>(void 0);
63 /* if we have more than one device, launch the application on each */
64 devices.forEach((device: IDevice) => {
65 if (device.isOnline) {
66 result = result.then(() => deviceHelper.launchApp(this.workspaceRoot, packagName, device.id));
67 }
68 });
69 return result;
70 } else {
71 return Q.resolve(void 0);
72 }
73 });
74 });
75 }
76
77 /**
78 * Executes the 'react-native run-ios' command
79 */
80 public runIos(): Q.Promise<void> {
81 return this.executeCommandInContext("runIos", () => {
82 // Set the Debugging setting to disabled, because in iOS it's persisted across runs of the app
83 return new IOSDebugModeManager(this.workspaceRoot).setSimulatorJSDebuggingModeSetting(/*enable=*/ false)
84 .catch(() => { }) // If setting the debugging mode fails, we ignore the error and we run the run ios command anyways
85 .then(() => this.executeReactNativeRunCommand("run-ios"));
86 });
87 }
88
89 private runStartPackagerCommandAndUpdateStatus(): Q.Promise<void> {
90 return this.reactNativePackager.start(SettingsHelper.getPackagerPort())
91 .then(() => this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STARTED));
92 }
93
94 /**
95 * Executes a react-native command passed after starting the packager
96 * {command} The command to be executed
97 * {args} The arguments to be passed to the command
98 */
99 private executeReactNativeRunCommand(command: string, args?: string[]): Q.Promise<void> {
100 // Start the packager before executing the React-Native command
101 Log.logMessage("Attempting to start the React Native packager");
102
103 return this.runStartPackagerCommandAndUpdateStatus()
104 .then(() => {
105 return new CommandExecutor(this.workspaceRoot).spawnReactCommand(command, args, null);
106 }).then(() => {
107 return Q.resolve<void>(void 0);
108 });
109 }
110
111 /**
112 * Ensures that we are in a React Native project and then executes the operation
113 * Otherwise, displays an error message banner
114 * {operation} - a function that performs the expected operation
115 */
116 private executeCommandInContext(rnCommand: string, operation: () => Q.Promise<void> | void): Q.Promise<void> {
117 let reactNativeProjectHelper = new ReactNativeProjectHelper(vscode.workspace.rootPath);
118 return TelemetryHelper.generate("RNCommand", (generator) => {
119 generator.add("command", rnCommand, false);
120 return reactNativeProjectHelper.isReactNativeProject().then(isRNProject => {
121 generator.add("isRNProject", isRNProject, false);
122 if (isRNProject) {
123 // Bring the log channel to focus
124 Log.setFocusOnLogChannel();
125
126 // Execute the operation
127 return operation();
128 } else {
129 vscode.window.showErrorMessage("Current workspace is not a React Native project.");
130 }
131 });
132 });
133 }
134}
135