summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/actions/sources/select.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/actions/sources/select.js')
-rw-r--r--devtools/client/debugger/src/actions/sources/select.js139
1 files changed, 100 insertions, 39 deletions
diff --git a/devtools/client/debugger/src/actions/sources/select.js b/devtools/client/debugger/src/actions/sources/select.js
index 63200a398a..f25267374b 100644
--- a/devtools/client/debugger/src/actions/sources/select.js
+++ b/devtools/client/debugger/src/actions/sources/select.js
@@ -63,6 +63,11 @@ export const clearSelectedLocation = () => ({
type: "CLEAR_SELECTED_LOCATION",
});
+export const setDefaultSelectedLocation = shouldSelectOriginalLocation => ({
+ type: "SET_DEFAULT_SELECTED_LOCATION",
+ shouldSelectOriginalLocation,
+});
+
/**
* Deterministically select a source that has a given URL. This will
* work regardless of the connection status or if the source exists
@@ -105,6 +110,76 @@ export function selectSource(source, sourceActor) {
}
/**
+ * Helper for `selectLocation`.
+ * Based on `keepContext` argument passed to `selectLocation`,
+ * this will automatically select the related mapped source (original or generated).
+ *
+ * @param {Object} location
+ * The location to select.
+ * @param {Boolean} keepContext
+ * If true, will try to select a mapped source.
+ * @param {Object} thunkArgs
+ * @return {Object}
+ * Object with two attributes:
+ * - `shouldSelectOriginalLocation`, to know if we should keep trying to select the original location
+ * - `newLocation`, for the final location to select
+ */
+async function mayBeSelectMappedSource(location, keepContext, thunkArgs) {
+ const { getState, dispatch } = thunkArgs;
+ // Preserve the current source map context (original / generated)
+ // when navigating to a new location.
+ // i.e. if keepContext isn't manually overriden to false,
+ // we will convert the source we want to select to either
+ // original/generated in order to match the currently selected one.
+ // If the currently selected source is original, we will
+ // automatically map `location` to refer to the original source,
+ // even if that used to refer only to the generated source.
+ let shouldSelectOriginalLocation = getShouldSelectOriginalLocation(
+ getState()
+ );
+ if (keepContext) {
+ // Pretty print source may not be registered yet and getRelatedMapLocation may not return it.
+ // Wait for the pretty print source to be fully processed.
+ if (
+ !location.source.isOriginal &&
+ shouldSelectOriginalLocation &&
+ hasPrettyTab(getState(), location.source)
+ ) {
+ // Note that prettyPrintAndSelectSource has already been called a bit before when this generated source has been added
+ // but it is a slow operation and is most likely not resolved yet.
+ // prettyPrintAndSelectSource uses memoization to avoid doing the operation more than once, while waiting from both callsites.
+ await dispatch(prettyPrintAndSelectSource(location.source));
+ }
+ if (shouldSelectOriginalLocation != location.source.isOriginal) {
+ // Only try to map if the source is mapped. i.e. is original source or a bundle with a valid source map comment
+ if (
+ location.source.isOriginal ||
+ isSourceActorWithSourceMap(getState(), location.sourceActor.id)
+ ) {
+ // getRelatedMapLocation will convert to the related generated/original location.
+ // i.e if the original location is passed, the related generated location will be returned and vice versa.
+ location = await getRelatedMapLocation(location, thunkArgs);
+ }
+ // Note that getRelatedMapLocation may return the exact same location.
+ // For example, if the source-map is half broken, it may return a generated location
+ // while we were selecting original locations. So we may be seeing bundles intermittently
+ // when stepping through broken source maps. And we will see original sources when stepping
+ // through functional original sources.
+ }
+ } else if (
+ location.source.isOriginal ||
+ isSourceActorWithSourceMap(getState(), location.sourceActor.id)
+ ) {
+ // Only update this setting if the source is mapped. i.e. don't update if we select a regular source.
+ // The source is mapped when it is either:
+ // - an original source,
+ // - a bundle with a source map comment referencing a source map URL.
+ shouldSelectOriginalLocation = location.source.isOriginal;
+ }
+ return { shouldSelectOriginalLocation, newLocation: location };
+}
+
+/**
* Select a new location.
* This will automatically select the source in the source tree (if visible)
* and open the source (a new tab and the source editor)
@@ -144,47 +219,28 @@ export function selectLocation(
return;
}
- // Preserve the current source map context (original / generated)
- // when navigating to a new location.
- // i.e. if keepContext isn't manually overriden to false,
- // we will convert the source we want to select to either
- // original/generated in order to match the currently selected one.
- // If the currently selected source is original, we will
- // automatically map `location` to refer to the original source,
- // even if that used to refer only to the generated source.
- let shouldSelectOriginalLocation = getShouldSelectOriginalLocation(
- getState()
- );
- if (keepContext) {
- // Pretty print source may not be registered yet and getRelatedMapLocation may not return it.
- // Wait for the pretty print source to be fully processed.
- if (
- !location.source.isOriginal &&
- shouldSelectOriginalLocation &&
- hasPrettyTab(getState(), location.source)
- ) {
- // Note that prettyPrintAndSelectSource has already been called a bit before when this generated source has been added
- // but it is a slow operation and is most likely not resolved yet.
- // prettyPrintAndSelectSource uses memoization to avoid doing the operation more than once, while waiting from both callsites.
- await dispatch(prettyPrintAndSelectSource(location.source));
- }
- if (shouldSelectOriginalLocation != location.source.isOriginal) {
- // getRelatedMapLocation will convert to the related generated/original location.
- // i.e if the original location is passed, the related generated location will be returned and vice versa.
- location = await getRelatedMapLocation(location, thunkArgs);
- // Note that getRelatedMapLocation may return the exact same location.
- // For example, if the source-map is half broken, it may return a generated location
- // while we were selecting original locations. So we may be seeing bundles intermittently
- // when stepping through broken source maps. And we will see original sources when stepping
- // through functional original sources.
+ let sourceActor = location.sourceActor;
+ if (!sourceActor) {
+ sourceActor = getFirstSourceActorForGeneratedSource(
+ getState(),
+ source.id
+ );
+ location = createLocation({ ...location, sourceActor });
+ }
- source = location.source;
- }
- } else {
- shouldSelectOriginalLocation = location.source.isOriginal;
+ const lastSelectedLocation = getSelectedLocation(getState());
+ const { shouldSelectOriginalLocation, newLocation } =
+ await mayBeSelectMappedSource(location, keepContext, thunkArgs);
+
+ // Ignore the request if another location was selected while we were waiting for mayBeSelectMappedSource async completion
+ if (getSelectedLocation(getState()) != lastSelectedLocation) {
+ return;
}
- let sourceActor = location.sourceActor;
+ // Update all local variables after mapping
+ location = newLocation;
+ source = location.source;
+ sourceActor = location.sourceActor;
if (!sourceActor) {
sourceActor = getFirstSourceActorForGeneratedSource(
getState(),
@@ -351,11 +407,16 @@ export function jumpToMappedLocation(location) {
// Map to either an original or a generated source location
const pairedLocation = await getRelatedMapLocation(location, thunkArgs);
+ // If we are on a non-mapped source, this will return the same location
+ // so ignore the request.
+ if (pairedLocation == location) {
+ return null;
+ }
+
return dispatch(selectSpecificLocation(pairedLocation));
};
}
-// This is only used by tests
export function jumpToMappedSelectedLocation() {
return async function ({ dispatch, getState }) {
const location = getSelectedLocation(getState());