Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(840)

Unified Diff: third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js

Issue 2500493003: [DevTools] make breakpoints better (Closed)
Patch Set: fixed context menu items for gutter Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index 13de635127018497c6d13123c4da6abc652c2562..5c4a06a5fe445513a81da3bb7c0361c3cfb8512b 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -253,7 +253,6 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
this._scriptsPanel.appendUILocationItems(contextMenu, uiLocation);
var breakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), lineNumber);
if (!breakpoints.length) {
- // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint.
contextMenu.appendItem(
Common.UIString('Add breakpoint'), this._createNewBreakpoint.bind(this, lineNumber, '', true));
contextMenu.appendItem(
@@ -261,16 +260,24 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
contextMenu.appendItem(
Common.UIString('Never pause here'), this._createNewBreakpoint.bind(this, lineNumber, 'false', true));
} else {
- var breakpoint = breakpoints[0];
-
- // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable.
- contextMenu.appendItem(Common.UIString('Remove breakpoint'), breakpoint.remove.bind(breakpoint));
- contextMenu.appendItem(
- Common.UIString('Edit breakpoint…'), this._editBreakpointCondition.bind(this, lineNumber, breakpoint));
- if (breakpoint.enabled())
- contextMenu.appendItem(Common.UIString('Disable breakpoint'), breakpoint.setEnabled.bind(breakpoint, false));
- else
- contextMenu.appendItem(Common.UIString('Enable breakpoint'), breakpoint.setEnabled.bind(breakpoint, true));
+ var hasOneBreakpoint = breakpoints.length === 1;
+ var removeTitle = hasOneBreakpoint ? 'Remove breakpoint' : 'Remove all breakpoints in line';
+ contextMenu.appendItem(Common.UIString(removeTitle), () => breakpoints.map(breakpoint => breakpoint.remove()));
+ if (hasOneBreakpoint) {
+ contextMenu.appendItem(
+ Common.UIString('Edit breakpoint\u2026'),
+ this._editBreakpointCondition.bind(this, lineNumber, breakpoints[0]));
+ }
+ if (breakpoints.some(breakpoint => breakpoint.enabled())) {
+ var disableTitle = hasOneBreakpoint ? 'Disable breakpoint' : 'Disable all breakpoints in line';
+ contextMenu.appendItem(
+ Common.UIString(disableTitle), () => breakpoints.map(breakpoint => breakpoint.setEnabled(false)));
dgozman 2016/11/15 23:35:13 Always wrap a literal in Common.UIString() instead
+ }
+ if (breakpoints.some(breakpoint => !breakpoint.enabled())) {
+ var enableTitle = hasOneBreakpoint ? 'Enable breakpoint' : 'Enable all breakpoints in line';
+ contextMenu.appendItem(
+ Common.UIString(enableTitle), () => breakpoints.map(breakpoint => breakpoint.setEnabled(true)));
+ }
}
resolve();
}
@@ -356,13 +363,9 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
if (this._muted)
return;
for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
- var breakpointDecoration = this._textEditor.getAttribute(lineNumber, 'breakpoint');
- if (!breakpointDecoration)
+ if (!this.textEditor.hasLineClass(lineNumber, 'cm-breakpoint'))
continue;
- this._removeBreakpointDecoration(lineNumber);
- this._addBreakpointDecoration(
- lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled,
- true);
+ this._updateBreakpointDecoration(lineNumber);
}
this._muted = true;
}
@@ -403,28 +406,25 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
_restoreBreakpointsAfterEditing() {
delete this._muted;
- var breakpoints = {};
+ /** @type {!Map<number, !{enabled: boolean, condition: string, lineNumber: number}>} */
+ var linesWithBreakpoints = new Map();
// Save and remove muted breakpoint decorations.
for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
- var breakpointDecoration = this._textEditor.getAttribute(lineNumber, 'breakpoint');
- if (breakpointDecoration) {
- breakpoints[lineNumber] = breakpointDecoration;
- this._removeBreakpointDecoration(lineNumber);
+ if (this.textEditor.hasLineClass(lineNumber, 'cm-breakpoint')) {
+ var breakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), lineNumber);
+ breakpoints = breakpoints.filter(breakpoint => breakpoint.enabled());
+ var condition = breakpoints.length ? breakpoints[0].condition() : '';
+ linesWithBreakpoints.set(lineNumber,
+ {enabled: !!breakpoints.length, condition: condition, lineNumber: lineNumber});
}
}
// Remove all breakpoints.
this._removeAllBreakpoints();
- // Restore all breakpoints from saved decorations.
- for (var lineNumberString in breakpoints) {
- var lineNumber = parseInt(lineNumberString, 10);
- if (isNaN(lineNumber))
- continue;
- var breakpointDecoration = breakpoints[lineNumberString];
- this._setBreakpoint(
- lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled);
- }
+ // Restore first in line breakpoints from saved decorations.
+ for (var breakpoint of linesWithBreakpoints.valuesArray())
+ this._createNewBreakpoint(breakpoint.lineNumber, breakpoint.condition, breakpoint.enabled);
}
_removeAllBreakpoints() {
@@ -559,23 +559,113 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
/**
* @param {number} lineNumber
- * @param {number} columnNumber
- * @param {string} condition
- * @param {boolean} enabled
- * @param {boolean} mutedWhileEditing
*/
- _addBreakpointDecoration(lineNumber, columnNumber, condition, enabled, mutedWhileEditing) {
- var breakpoint = {condition: condition, enabled: enabled, columnNumber: columnNumber};
+ _updateBreakpointDecoration(lineNumber) {
lushnikov 2016/11/15 22:42:33 _updateBreakpointDecorations
+ if (!this._scheduledBreakpointDecorationUpdates)
+ this._scheduledBreakpointDecorationUpdates = /** @type {!Set<number>} */(new Set());
+
+ if (this._scheduledBreakpointDecorationUpdates.has(lineNumber))
+ return;
+ if (!this._scheduledBreakpointDecorationUpdates.size)
+ setImmediate(() => this.textEditor.operation(update.bind(this)));
+ this._scheduledBreakpointDecorationUpdates.add(lineNumber);
+
+ /**
+ * @this {!Sources.JavaScriptSourceFrame}
+ */
+ function update() {
+ for (var lineNumber of this._scheduledBreakpointDecorationUpdates) {
+ if (lineNumber >= this.textEditor.linesCount)
+ continue;
+ var lineRange = new Common.TextRange(lineNumber, 0, lineNumber, this.textEditor.line(lineNumber).length);
+ var bookmarks = this.textEditor.bookmarks(lineRange, Sources.JavaScriptSourceFrame._inlineBreakpointSymbol);
+ for (var bookmark of bookmarks)
+ bookmark.clear();
+
+ var breakpointLocations = this._breakpointManager.breakpontLocationsForLineNumber(this.uiSourceCode(), lineNumber);
+ var breakpoints = breakpointLocations.map(location => location.breakpoint);
+ var hasBreakpoints = !!breakpoints.length;
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint', hasBreakpoints);
+ var hasEnabled = breakpoints.some(breakpoint => breakpoint.enabled()) && !this._muted;
+ var hasConditional = breakpoints.some(breakpoint => !!breakpoint.condition());
+ var hasEnabledConditional = breakpoints.some(breakpoint => !!breakpoint.condition() && breakpoint.enabled());
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-disabled', !hasEnabled && hasBreakpoints);
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-conditional', hasBreakpoints && (hasEnabledConditional || (!hasEnabled && hasConditional)));
+
+ if (hasBreakpoints)
+ this.addBreakpointForTest(lineNumber, hasEnabled);
+ else
+ this.removeBreakpointForTest(lineNumber);
+
+ if (hasBreakpoints && Runtime.experiments.isEnabled('inlineBreakpoints')) {
+ this._breakpointManager.possibleBreakpoints(this.uiSourceCode(), new Common.TextRange(lineNumber, 0, lineNumber + 1, 0))
+ .then(addMissingBreakpoints.bind(this, lineNumber));
lushnikov 2016/11/17 04:31:50 what if during this asynchronous code the breakpoi
+ }
+
+ if (breakpoints.length <= 1 || this._muted || !Runtime.experiments.isEnabled('inlineBreakpoints'))
+ continue;
+
+ for (let i = 0; i < breakpointLocations.length; ++i) {
+ var breakpoint = breakpointLocations[i].breakpoint;
+ var inlineBreakpoint = createElementWithClass('div', 'cm-inline-breakpoint');
+ inlineBreakpoint.classList.toggle('cm-inline-conditional', !!breakpoints[i].condition());
+ inlineBreakpoint.classList.toggle('cm-inline-disabled', !breakpoints[i].enabled());
+ inlineBreakpoint.addEventListener('click', () => breakpoints[i].setEnabled(!breakpoints[i].enabled()), true);
+ inlineBreakpoint.addEventListener('contextmenu', this._populateInlineBreakpointContextMenu.bind(this, breakpoints[i]));
+ this.textEditor.addBookmark(lineNumber, breakpointLocations[i].uiLocation.columnNumber, inlineBreakpoint, Sources.JavaScriptSourceFrame._inlineBreakpointSymbol);
+ }
+ }
+ this._scheduledBreakpointDecorationUpdates.clear();
+ }
+
+ /**
+ * @this {!Sources.JavaScriptSourceFrame}
+ * @param {number} lineNumber
+ * @param {!Array<!Workspace.UILocation>} locations
+ */
+ function addMissingBreakpoints(lineNumber, locations) {
lushnikov 2016/11/17 04:31:50 addInlineBreakpoints
+ var breakpoints = this._breakpointManager.breakpontLocationsForLineNumber(this.uiSourceCode(), lineNumber);
+ if (!breakpoints.length)
+ return;
+ var columns = new Set(breakpoints.map(breakpoint => breakpoint.uiLocation.columnNumber));
+ locations = locations.filter(location => !columns.has(location.columnNumber));
+ for (var location of locations)
+ this._setBreakpoint(location.lineNumber, location.columnNumber, '', false);
+ }
+ }
- this.textEditor.setAttribute(lineNumber, 'breakpoint', breakpoint);
+ /**
+ * @param {number} lineNumber
+ * @param {boolean} disabled
+ */
+ addBreakpointForTest(lineNumber, disabled) {
+ }
- var disabled = !enabled || mutedWhileEditing;
- this.textEditor.addBreakpoint(lineNumber, disabled, !!condition);
+ /**
+ * @param {number} lineNumber
+ */
+ removeBreakpointForTest(lineNumber) {
}
- _removeBreakpointDecoration(lineNumber) {
- this.textEditor.removeAttribute(lineNumber, 'breakpoint');
- this.textEditor.removeBreakpoint(lineNumber);
+ /**
+ * @param {!Bindings.BreakpointManager.Breakpoint} breakpoint
+ * @param {!Event} event
+ */
+ _populateInlineBreakpointContextMenu(breakpoint, event) {
+ var contextMenu = new UI.ContextMenu(event);
+ if (!breakpoint.enabled()) {
+ contextMenu.appendItem(
+ Common.UIString('Add conditional breakpoint…'), this._editBreakpointCondition.bind(this, breakpoint.lineNumber(), breakpoint));
lushnikov 2016/11/17 04:31:50 nit: let's use \u... for the ellipsis
+ contextMenu.appendItem(
+ Common.UIString('Never pause here'),
+ () => { breakpoint.setCondition('false'); breakpoint.setEnabled(true); });
lushnikov 2016/11/17 04:31:50 It would be easier for me to read if the function
+ } else {
+ contextMenu.appendItem(
+ Common.UIString('Edit breakpoint…'),
lushnikov 2016/11/17 04:31:50 let's use \u... for the ellipsis
+ this._editBreakpointCondition.bind(this, breakpoint.lineNumber(), breakpoint));
+ }
+ contextMenu.show();
+ event.consume();
}
_onKeyDown(event) {
@@ -605,10 +695,12 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
if (!committed)
return;
- if (breakpoint)
+ if (breakpoint) {
breakpoint.setCondition(newText);
- else
+ breakpoint.setEnabled(true);
+ } else {
this._createNewBreakpoint(lineNumber, newText, true);
+ }
}
var config = new UI.InplaceEditor.Config(finishEditing.bind(this, true), finishEditing.bind(this, false));
@@ -848,12 +940,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
return;
if (this._shouldIgnoreExternalBreakpointEvents())
return;
-
- var breakpoint = /** @type {!Bindings.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
- if (this.loaded) {
- this._addBreakpointDecoration(
- uiLocation.lineNumber, uiLocation.columnNumber, breakpoint.condition(), breakpoint.enabled(), false);
- }
+ if (this.loaded)
+ this._updateBreakpointDecoration(uiLocation.lineNumber);
}
_breakpointRemoved(event) {
@@ -862,10 +950,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
return;
if (this._shouldIgnoreExternalBreakpointEvents())
return;
-
- var remainingBreakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), uiLocation.lineNumber);
- if (!remainingBreakpoints.length && this.loaded)
- this._removeBreakpointDecoration(uiLocation.lineNumber);
+ if (this.loaded)
+ this._updateBreakpointDecoration(uiLocation.lineNumber);
}
/**
@@ -1010,13 +1096,15 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
*/
_toggleBreakpoint(lineNumber, onlyDisable) {
var breakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), lineNumber);
- if (breakpoints.length) {
+ if (!breakpoints.length) {
+ this._createNewBreakpoint(lineNumber, '', true);
+ return;
+ }
+ for (var breakpoint of breakpoints) {
if (onlyDisable)
- breakpoints[0].setEnabled(!breakpoints[0].enabled());
+ breakpoint.setEnabled(false);
else
- breakpoints[0].remove();
- } else {
- this._createNewBreakpoint(lineNumber, '', true);
+ breakpoint.remove();
}
}
@@ -1065,10 +1153,13 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
* @param {?Array<!Workspace.UILocation>} locations
*/
function setBreakpoint(locations) {
- if (!locations || !locations.length)
+ if (!locations || !locations.length) {
this._setBreakpoint(lineNumber, 0, condition, enabled);
- else
- this._setBreakpoint(locations[0].lineNumber, locations[0].columnNumber, condition, enabled);
+ } else {
+ var maximumBreakpointsAmount = Runtime.experiments.isEnabled('inlineBreakpoints') ? locations.length : 1;
lushnikov 2016/11/17 04:31:50 let's make the experiment check simpler: if (Runt
+ for (var i = 0; i < locations.length && i < maximumBreakpointsAmount; ++i)
+ this._setBreakpoint(locations[i].lineNumber, locations[i].columnNumber, i === 0 ? condition : '', i === 0 && enabled);
+ }
Host.userMetrics.actionTaken(Host.UserMetrics.Action.ScriptsBreakpointSet);
}
}
@@ -1127,3 +1218,5 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
super.dispose();
}
};
+
+Sources.JavaScriptSourceFrame._inlineBreakpointSymbol = Symbol('inline-breakpoint');

Powered by Google App Engine
This is Rietveld 408576698