diff --git a/devtools/client/debugger/content/reducers/breakpoints.js b/devtools/client/debugger/content/reducers/breakpoints.js index 3346f585dc6..f5b9fd07923 100644 --- a/devtools/client/debugger/content/reducers/breakpoints.js +++ b/devtools/client/debugger/content/reducers/breakpoints.js @@ -101,6 +101,7 @@ function update(state = initialState, action, emitChange) { case constants.SET_BREAKPOINT_CONDITION: { const id = makeLocationId(action.breakpoint.location); const bp = state.breakpoints[id]; + emitChange("breakpoint-condition-updated", bp); if (action.status === 'start') { return mergeIn(state, ['breakpoints', id], { @@ -117,8 +118,10 @@ function update(state = initialState, action, emitChange) { }); } else if (action.status === 'error') { + emitChange("breakpoint-removed", bp); return deleteIn(state, ['breakpoints', id]); } + break; }} diff --git a/devtools/client/debugger/debugger-view.js b/devtools/client/debugger/debugger-view.js index dfcc380b2d6..a113aae2423 100644 --- a/devtools/client/debugger/debugger-view.js +++ b/devtools/client/debugger/debugger-view.js @@ -99,6 +99,7 @@ var DebuggerView = { "breakpoint-enabled": this.addEditorBreakpoint, "breakpoint-disabled": this.removeEditorBreakpoint, "breakpoint-removed": this.removeEditorBreakpoint, + "breakpoint-condition-updated": this.renderEditorBreakpointCondition, "breakpoint-moved": ({ breakpoint, prevLocation }) => { const selectedSource = queries.getSelectedSource(getState()); const { location } = breakpoint; @@ -353,13 +354,13 @@ var DebuggerView = { }, addEditorBreakpoint: function(breakpoint) { - const { location } = breakpoint; + const { location, condition } = breakpoint; const source = queries.getSelectedSource(this.controller.getState()); if (source && source.actor === location.actor && !breakpoint.disabled) { - this.editor.addBreakpoint(location.line - 1); + this.editor.addBreakpoint(location.line - 1, condition); } }, @@ -372,6 +373,19 @@ var DebuggerView = { } }, + renderEditorBreakpointCondition: function (breakpoint) { + const { location, condition } = breakpoint; + const source = queries.getSelectedSource(this.controller.getState()); + + if (source && source.actor === location.actor) { + if (condition) { + this.editor.setBreakpointCondition(location.line - 1); + } else { + this.editor.removeBreakpointCondition(location.line - 1); + } + } + }, + /** * Display the source editor. */ diff --git a/devtools/client/sourceeditor/codemirror/mozilla.css b/devtools/client/sourceeditor/codemirror/mozilla.css index 0e92ee21334..c8ca1c8b066 100644 --- a/devtools/client/sourceeditor/codemirror/mozilla.css +++ b/devtools/client/sourceeditor/codemirror/mozilla.css @@ -6,12 +6,14 @@ --breakpoint-background: url("chrome://devtools/skin/images/breakpoint.svg#light"); --breakpoint-hover-background: url("chrome://devtools/skin/images/breakpoint.svg#light-hover"); --breakpoint-active-background: url("chrome://devtools/skin/images/breakpoint.svg#light-active"); + --breakpoint-conditional-background: url("chrome://devtools/skin/images/breakpoint.svg#light-conditional"); } .theme-dark:root { --breakpoint-background: url("chrome://devtools/skin/images/breakpoint.svg#dark"); --breakpoint-hover-background: url("chrome://devtools/skin/images/breakpoint.svg#dark-hover"); --breakpoint-active-background: url("chrome://devtools/skin/images/breakpoint.svg#dark-active"); + --breakpoint-conditional-background: url("chrome://devtools/skin/images/breakpoint.svg#dark-conditional"); } .errors { @@ -64,6 +66,14 @@ background-image: var(--breakpoint-background) !important; } +.conditional .CodeMirror-linenumber { + background-image: var(--breakpoint-conditional-background) !important; +} + +.conditional .CodeMirror-line { + background-color: rgba(217,126,0,.15); +} + .debug-line .CodeMirror-linenumber { background-image: var(--breakpoint-active-background) !important; } diff --git a/devtools/client/sourceeditor/debugger.js b/devtools/client/sourceeditor/debugger.js index 29408dd7a9a..0a142c1b2e3 100644 --- a/devtools/client/sourceeditor/debugger.js +++ b/devtools/client/sourceeditor/debugger.js @@ -151,6 +151,9 @@ function addBreakpoint(ctx, line, cond) { meta.breakpoints[info.line] = null; }); + if (cond) { + setBreakpointCondition(ctx, line); + } ed.emit("breakpointAdded", line); deferred.resolve(); } @@ -185,6 +188,7 @@ function removeBreakpoint(ctx, line) { meta.breakpoints[info.line] = null; ed.removeLineClass(info.line, "breakpoint"); + ed.removeLineClass(info.line, "conditional"); ed.emit("breakpointRemoved", line); } @@ -198,6 +202,26 @@ function moveBreakpoint(ctx, fromLine, toLine) { ed.addBreakpoint(toLine); } +function setBreakpointCondition(ctx, line) { + let { ed, cm } = ctx; + let info = cm.lineInfo(line); + + // The line does not exist in the editor. This is harmless, the + // architecture calling this assumes the editor will handle this + // gracefully, and make sure breakpoints exist when they need to. + if (!info) { + return; + } + + ed.addLineClass(line, "conditional"); +} + +function removeBreakpointCondition(ctx, line) { + let { ed, cm } = ctx; + + ed.removeLineClass(line, "conditional"); +} + /** * Returns a list of all breakpoints in the current Editor. */ @@ -278,7 +302,8 @@ function findPrev(ctx, query) { // Export functions [ - initialize, hasBreakpoint, addBreakpoint, removeBreakpoint, - moveBreakpoint, getBreakpoints, setDebugLocation, getDebugLocation, - clearDebugLocation, find, findNext, findPrev + initialize, hasBreakpoint, addBreakpoint, removeBreakpoint, moveBreakpoint, + setBreakpointCondition, removeBreakpointCondition, getBreakpoints, + setDebugLocation, getDebugLocation, clearDebugLocation, find, findNext, + findPrev ].forEach(func => module.exports[func.name] = func);