diff options
Diffstat (limited to 'devtools/client/debugger/content/reducers/breakpoints.js')
-rw-r--r-- | devtools/client/debugger/content/reducers/breakpoints.js | 153 |
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; |