diff options
Diffstat (limited to 'devtools/client/debugger/src/selectors/pause.js')
-rw-r--r-- | devtools/client/debugger/src/selectors/pause.js | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/selectors/pause.js b/devtools/client/debugger/src/selectors/pause.js new file mode 100644 index 0000000000..a1bccda7c4 --- /dev/null +++ b/devtools/client/debugger/src/selectors/pause.js @@ -0,0 +1,293 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +import { getThreadPauseState } from "../reducers/pause"; +import { getSelectedSource, getSelectedLocation } from "./sources"; +import { getBlackBoxRanges } from "./source-blackbox"; + +// eslint-disable-next-line +import { getSelectedLocation as _getSelectedLocation } from "../utils/selected-location"; +import { isFrameBlackBoxed } from "../utils/source"; +import { createSelector } from "devtools/client/shared/vendor/reselect"; + +export const getSelectedFrame = createSelector( + (state, thread) => state.pause.threads[thread], + threadPauseState => { + if (!threadPauseState) return null; + const { selectedFrameId, frames } = threadPauseState; + if (frames) { + return frames.find(frame => frame.id == selectedFrameId); + } + return null; + } +); + +export const getVisibleSelectedFrame = createSelector( + getSelectedLocation, + state => getSelectedFrame(state, getCurrentThread(state)), + (selectedLocation, selectedFrame) => { + if (!selectedFrame) { + return null; + } + + const { id, displayName } = selectedFrame; + + return { + id, + displayName, + location: _getSelectedLocation(selectedFrame, selectedLocation), + }; + } +); + +export function getContext(state) { + return state.pause.cx; +} + +export function getThreadContext(state) { + return state.pause.threadcx; +} + +export function getNavigateCounter(state) { + return state.pause.threadcx.navigateCounter; +} + +export function getPauseReason(state, thread) { + return getThreadPauseState(state.pause, thread).why; +} + +export function getShouldBreakpointsPaneOpenOnPause(state, thread) { + return getThreadPauseState(state.pause, thread) + .shouldBreakpointsPaneOpenOnPause; +} + +export function getPauseCommand(state, thread) { + return getThreadPauseState(state.pause, thread).command; +} + +export function isStepping(state, thread) { + return ["stepIn", "stepOver", "stepOut"].includes( + getPauseCommand(state, thread) + ); +} + +export function getCurrentThread(state) { + return getThreadContext(state).thread; +} + +export function getIsPaused(state, thread) { + return getThreadPauseState(state.pause, thread).isPaused; +} + +export function getIsCurrentThreadPaused(state) { + return getIsPaused(state, getCurrentThread(state)); +} + +export function isEvaluatingExpression(state, thread) { + return getThreadPauseState(state.pause, thread).command === "expression"; +} + +export function getIsWaitingOnBreak(state, thread) { + return getThreadPauseState(state.pause, thread).isWaitingOnBreak; +} + +export function getShouldPauseOnDebuggerStatement(state) { + return state.pause.shouldPauseOnDebuggerStatement; +} + +export function getShouldPauseOnExceptions(state) { + return state.pause.shouldPauseOnExceptions; +} + +export function getShouldPauseOnCaughtExceptions(state) { + return state.pause.shouldPauseOnCaughtExceptions; +} + +export function getFrames(state, thread) { + const { frames, framesLoading } = getThreadPauseState(state.pause, thread); + return framesLoading ? null : frames; +} + +export const getCurrentThreadFrames = createSelector( + state => { + const { frames, framesLoading } = getThreadPauseState( + state.pause, + getCurrentThread(state) + ); + if (framesLoading) { + return []; + } + return frames; + }, + getBlackBoxRanges, + (frames, blackboxedRanges) => { + return frames.filter(frame => !isFrameBlackBoxed(frame, blackboxedRanges)); + } +); + +function getGeneratedFrameId(frameId) { + if (frameId.includes("-originalFrame")) { + // The mapFrames can add original stack frames -- get generated frameId. + return frameId.substr(0, frameId.lastIndexOf("-originalFrame")); + } + return frameId; +} + +export function getGeneratedFrameScope(state, frame) { + if (!frame) { + return null; + } + return getFrameScopes(state, frame.thread).generated[ + getGeneratedFrameId(frame.id) + ]; +} + +export function getOriginalFrameScope(state, frame) { + if (!frame) { + return null; + } + // Only compute original scope if we are currently showing an original source. + const source = getSelectedSource(state); + if (!source || !source.isOriginal) { + return null; + } + + const original = getFrameScopes(state, frame.thread).original[ + getGeneratedFrameId(frame.id) + ]; + + if (original && (original.pending || original.scope)) { + return original; + } + + return null; +} + +// This is only used by tests +export function getFrameScopes(state, thread) { + return getThreadPauseState(state.pause, thread).frameScopes; +} + +export function getSelectedFrameBindings(state, thread) { + const scopes = getFrameScopes(state, thread); + const selectedFrameId = getSelectedFrameId(state, thread); + if (!scopes || !selectedFrameId) { + return null; + } + + const frameScope = scopes.generated[selectedFrameId]; + if (!frameScope || frameScope.pending) { + return null; + } + + let currentScope = frameScope.scope; + let frameBindings = []; + while (currentScope && currentScope.type != "object") { + if (currentScope.bindings) { + const bindings = Object.keys(currentScope.bindings.variables); + const args = [].concat( + ...currentScope.bindings.arguments.map(argument => + Object.keys(argument) + ) + ); + + frameBindings = [...frameBindings, ...bindings, ...args]; + } + currentScope = currentScope.parent; + } + + return frameBindings; +} + +function getFrameScope(state, frame) { + return ( + getOriginalFrameScope(state, frame) || getGeneratedFrameScope(state, frame) + ); +} + +// This is only used by tests +export function getSelectedScope(state, thread) { + const frame = getSelectedFrame(state, thread); + + const frameScope = getFrameScope(state, frame); + if (!frameScope) { + return null; + } + + return frameScope.scope || null; +} + +export function getSelectedOriginalScope(state, thread) { + const frame = getSelectedFrame(state, thread); + return getOriginalFrameScope(state, frame); +} + +export function getSelectedScopeMappings(state, thread) { + const frameId = getSelectedFrameId(state, thread); + if (!frameId) { + return null; + } + + return getFrameScopes(state, thread).mappings[frameId]; +} + +export function getSelectedFrameId(state, thread) { + return getThreadPauseState(state.pause, thread).selectedFrameId; +} + +export function isTopFrameSelected(state, thread) { + const selectedFrameId = getSelectedFrameId(state, thread); + const topFrame = getTopFrame(state, thread); + return selectedFrameId == topFrame?.id; +} + +export function getTopFrame(state, thread) { + const frames = getFrames(state, thread); + return frames?.[0]; +} + +// getTopFrame wouldn't return the top frame if the frames are still being fetched +export function getCurrentlyFetchedTopFrame(state, thread) { + const { frames } = getThreadPauseState(state.pause, thread); + return frames?.[0]; +} + +export function hasFrame(state, frame) { + // Don't use getFrames as it returns null when the frames are still loading + const { frames } = getThreadPauseState(state.pause, frame.thread); + if (!frames) { + return false; + } + // Compare IDs and not frame objects as they get cloned during mapping + return frames.some(f => f.id == frame.id); +} + +export function getSkipPausing(state) { + return state.pause.skipPausing; +} + +export function isMapScopesEnabled(state) { + return state.pause.mapScopes; +} + +export function getInlinePreviews(state, thread, frameId) { + return getThreadPauseState(state.pause, thread).inlinePreview[ + getGeneratedFrameId(frameId) + ]; +} + +// This is only used by tests +export function getSelectedInlinePreviews(state) { + const thread = getCurrentThread(state); + const frameId = getSelectedFrameId(state, thread); + if (!frameId) { + return null; + } + + return getInlinePreviews(state, thread, frameId); +} + +export function getLastExpandedScopes(state, thread) { + return getThreadPauseState(state.pause, thread).lastExpandedScopes; +} |