summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/content/reducers/breakpoints.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/content/reducers/breakpoints.js')
-rw-r--r--devtools/client/debugger/content/reducers/breakpoints.js153
1 files changed, 153 insertions, 0 deletions
diff --git a/devtools/client/debugger/content/reducers/breakpoints.js b/devtools/client/debugger/content/reducers/breakpoints.js
new file mode 100644
index 000000000..7e42098e8
--- /dev/null
+++ b/devtools/client/debugger/content/reducers/breakpoints.js
@@ -0,0 +1,153 @@
+/* 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/. */
+"use strict";
+
+const constants = require("../constants");
+const Immutable = require("devtools/client/shared/vendor/seamless-immutable");
+const { mergeIn, setIn, deleteIn } = require("../utils");
+const { makeLocationId } = require("../queries");
+
+const initialState = Immutable({
+ breakpoints: {}
+});
+
+// Return the first argument that is a string, or null if nothing is a
+// string.
+function firstString(...args) {
+ for (var arg of args) {
+ if (typeof arg === "string") {
+ return arg;
+ }
+ }
+ return null;
+}
+
+function update(state = initialState, action, emitChange) {
+ switch (action.type) {
+ case constants.ADD_BREAKPOINT: {
+ const id = makeLocationId(action.breakpoint.location);
+
+ if (action.status === "start") {
+ const existingBp = state.breakpoints[id];
+ const bp = existingBp || Immutable(action.breakpoint);
+
+ state = setIn(state, ["breakpoints", id], bp.merge({
+ disabled: false,
+ loading: true,
+ // We want to do an OR here, but we can't because we need
+ // empty strings to be truthy, i.e. an empty string is a valid
+ // condition.
+ condition: firstString(action.condition, bp.condition)
+ }));
+
+ emitChange(existingBp ? "breakpoint-enabled" : "breakpoint-added",
+ state.breakpoints[id]);
+ return state;
+ }
+ else if (action.status === "done") {
+ const { actor, text } = action.value;
+ let { actualLocation } = action.value;
+
+ // If the breakpoint moved, update the map
+ if (actualLocation) {
+ // XXX Bug 1227417: The `setBreakpoint` RDP request rdp
+ // request returns an `actualLocation` field that doesn't
+ // conform to the regular { actor, line } location shape, but
+ // it has a `source` field. We should fix that.
+ actualLocation = { actor: actualLocation.source.actor,
+ line: actualLocation.line };
+
+ state = deleteIn(state, ["breakpoints", id]);
+
+ const movedId = makeLocationId(actualLocation);
+ const currentBp = state.breakpoints[movedId] || Immutable(action.breakpoint);
+ const prevLocation = action.breakpoint.location;
+ const newBp = currentBp.merge({ location: actualLocation });
+ state = setIn(state, ["breakpoints", movedId], newBp);
+
+ emitChange("breakpoint-moved", {
+ breakpoint: newBp,
+ prevLocation: prevLocation
+ });
+ }
+
+ const finalLocation = (
+ actualLocation ? actualLocation : action.breakpoint.location
+ );
+ const finalLocationId = makeLocationId(finalLocation);
+ state = mergeIn(state, ["breakpoints", finalLocationId], {
+ disabled: false,
+ loading: false,
+ actor: actor,
+ text: text
+ });
+ emitChange("breakpoint-updated", state.breakpoints[finalLocationId]);
+ return state;
+ }
+ else if (action.status === "error") {
+ // Remove the optimistic update
+ emitChange("breakpoint-removed", state.breakpoints[id]);
+ return deleteIn(state, ["breakpoints", id]);
+ }
+ break;
+ }
+
+ case constants.REMOVE_BREAKPOINT: {
+ if (action.status === "done") {
+ const id = makeLocationId(action.breakpoint.location);
+ const bp = state.breakpoints[id];
+
+ if (action.disabled) {
+ state = mergeIn(state, ["breakpoints", id],
+ { loading: false, disabled: true });
+ emitChange("breakpoint-disabled", state.breakpoints[id]);
+ return state;
+ }
+
+ state = deleteIn(state, ["breakpoints", id]);
+ emitChange("breakpoint-removed", bp);
+ return state;
+ }
+ break;
+ }
+
+ case constants.SET_BREAKPOINT_CONDITION: {
+ const id = makeLocationId(action.breakpoint.location);
+ const bp = state.breakpoints[id];
+ emitChange("breakpoint-condition-updated", bp);
+
+ if (!action.status) {
+ // No status means that it wasn't a remote request. Just update
+ // the condition locally.
+ return mergeIn(state, ["breakpoints", id], {
+ condition: action.condition
+ });
+ }
+ else if (action.status === "start") {
+ return mergeIn(state, ["breakpoints", id], {
+ loading: true,
+ condition: action.condition
+ });
+ }
+ else if (action.status === "done") {
+ return mergeIn(state, ["breakpoints", id], {
+ loading: false,
+ condition: action.condition,
+ // Setting a condition creates a new breakpoint client as of
+ // now, so we need to update the actor
+ actor: action.value.actor
+ });
+ }
+ else if (action.status === "error") {
+ emitChange("breakpoint-removed", bp);
+ return deleteIn(state, ["breakpoints", id]);
+ }
+
+ break;
+ }}
+
+ return state;
+}
+
+module.exports = update;