commands.js (3991B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import { 6 getSelectedFrame, 7 getCurrentThread, 8 getIsCurrentThreadPaused, 9 getIsPaused, 10 } from "../../selectors/index"; 11 const { 12 PROMISE, 13 } = require("resource://devtools/client/shared/redux/middleware/promise.js"); 14 import { evaluateExpressions } from "../expressions"; 15 import { selectLocation } from "../sources/index"; 16 import { fetchScopes } from "./fetchScopes"; 17 import { fetchFrames } from "./fetchFrames"; 18 import { recordEvent } from "../../utils/telemetry"; 19 import { validateFrame } from "../../utils/context"; 20 21 export function selectThread(thread) { 22 return async ({ dispatch, getState }) => { 23 if (getCurrentThread(getState()) === thread) { 24 return; 25 } 26 dispatch({ type: "SELECT_THREAD", thread }); 27 if (getCurrentThread(getState()) !== thread) { 28 throw new Error("The thread wasn't selected"); 29 } 30 31 const selectedFrame = getSelectedFrame(getState()); 32 33 const serverRequests = []; 34 // Update the watched expressions as we may never have evaluated them against this thread 35 // Note that selectedFrame may be null if the thread isn't paused. 36 serverRequests.push(dispatch(evaluateExpressions(selectedFrame))); 37 38 // If we were paused on the newly selected thread, ensure: 39 // - select the source where we are paused, 40 // - fetching the paused stackframes, 41 // - fetching the paused scope, so that variable preview are working on the selected source. 42 // (frames and scopes is supposed to be fetched on pause, 43 // but if two threads pause concurrently, it might be cancelled) 44 if (selectedFrame) { 45 serverRequests.push(dispatch(selectLocation(selectedFrame.location))); 46 serverRequests.push(dispatch(fetchFrames(thread))); 47 48 serverRequests.push(dispatch(fetchScopes())); 49 } 50 51 await Promise.all(serverRequests); 52 }; 53 } 54 55 /** 56 * Debugger commands like stepOver, stepIn, stepOut, resume 57 * 58 * @param string type 59 */ 60 export function command(type) { 61 return async ({ dispatch, getState, client }) => { 62 if (!type) { 63 return null; 64 } 65 // For now, all commands are by default against the currently selected thread 66 const thread = getCurrentThread(getState()); 67 68 const frame = getSelectedFrame(getState()); 69 70 return dispatch({ 71 type: "COMMAND", 72 command: type, 73 thread, 74 [PROMISE]: client[type](thread, frame?.id), 75 }); 76 }; 77 } 78 79 /** 80 * StepIn 81 * 82 * @returns {Function} {@link command} 83 */ 84 export function stepIn() { 85 return ({ dispatch, getState }) => { 86 if (!getIsCurrentThreadPaused(getState())) { 87 return null; 88 } 89 return dispatch(command("stepIn")); 90 }; 91 } 92 93 /** 94 * stepOver 95 * 96 * @returns {Function} {@link command} 97 */ 98 export function stepOver() { 99 return ({ dispatch, getState }) => { 100 if (!getIsCurrentThreadPaused(getState())) { 101 return null; 102 } 103 return dispatch(command("stepOver")); 104 }; 105 } 106 107 /** 108 * stepOut 109 * 110 * @returns {Function} {@link command} 111 */ 112 export function stepOut() { 113 return ({ dispatch, getState }) => { 114 if (!getIsCurrentThreadPaused(getState())) { 115 return null; 116 } 117 return dispatch(command("stepOut")); 118 }; 119 } 120 121 /** 122 * resume 123 * 124 * @returns {Function} {@link command} 125 */ 126 export function resume() { 127 return ({ dispatch, getState }) => { 128 if (!getIsCurrentThreadPaused(getState())) { 129 return null; 130 } 131 recordEvent("continue"); 132 return dispatch(command("resume")); 133 }; 134 } 135 136 /** 137 * restart frame 138 */ 139 export function restart(frame) { 140 return async ({ dispatch, getState, client }) => { 141 if (!getIsPaused(getState(), frame.thread)) { 142 return null; 143 } 144 validateFrame(getState(), frame); 145 return dispatch({ 146 type: "COMMAND", 147 command: "restart", 148 thread: frame.thread, 149 [PROMISE]: client.restart(frame.thread, frame.id), 150 }); 151 }; 152 }