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

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

Issue 2505413002: [DevTools] Prepare JavaScriptSourceFrame for multiple breakpoints per line (Closed)
Patch Set: addressed comments 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 92d12feccc8e3e5fb83f395040a00282b5ad826d..13b5de4e4fd21e80c5f72eb25df571108d69d02f 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -67,6 +67,9 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
this.uiSourceCode().addEventListener(
Workspace.UISourceCode.Events.TitleChanged, this._showBlackboxInfobarIfNeeded, this);
+ /** @type {!Set<!Sources.JavaScriptSourceFrame.BreakpointDecoration>} */
+ this._breakpointDecorations = new Set();
+
/** @type {!Map.<!SDK.Target, !Bindings.ResourceScriptFile>}*/
this._scriptFileForTarget = new Map();
var targets = SDK.targetManager.targets();
@@ -182,7 +185,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
* @override
*/
onUISourceCodeContentChanged() {
- this._removeAllBreakpoints();
+ for (var decoration of this._breakpointDecorations)
+ decoration.breakpoint.remove();
super.onUISourceCodeContentChanged();
}
@@ -207,26 +211,37 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
function populate(resolve, reject) {
var uiLocation = new Workspace.UILocation(this.uiSourceCode(), lineNumber, 0);
this._scriptsPanel.appendUILocationItems(contextMenu, uiLocation);
- var breakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), lineNumber);
+ var breakpoints = this._lineBreakpointDecorations(lineNumber).map(decoration => decoration.breakpoint);
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(
- Common.UIString('Add conditional breakpoint…'), this._editBreakpointCondition.bind(this, lineNumber));
+ Common.UIString('Add conditional breakpoint\u2026'), this._editBreakpointCondition.bind(this, lineNumber));
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 ? Common.UIString('Remove breakpoint') : Common.UIString('Remove all breakpoints in line');
+ contextMenu.appendItem(removeTitle, () => breakpoints.map(breakpoint => breakpoint.remove()));
+ if (hasOneBreakpoint) {
+ contextMenu.appendItem(
+ Common.UIString('Edit breakpoint\u2026'),
+ this._editBreakpointCondition.bind(this, lineNumber, breakpoints[0]));
+ }
+ var hasEnabled = breakpoints.some(breakpoint => breakpoint.enabled());
+ if (hasEnabled) {
+ var title = hasOneBreakpoint ? Common.UIString('Disable breakpoint') :
+ Common.UIString('Disable all breakpoints in line');
+ contextMenu.appendItem(title, () => breakpoints.map(breakpoint => breakpoint.setEnabled(false)));
+ }
+ var hasDisabled = breakpoints.some(breakpoint => !breakpoint.enabled());
+ if (hasDisabled) {
+ var title = hasOneBreakpoint ? Common.UIString('Enable breakpoint') :
+ Common.UIString('Enabled all breakpoints in line');
+ contextMenu.appendItem(title, () => breakpoints.map(breakpoint => breakpoint.setEnabled(true)));
+ }
}
resolve();
}
@@ -309,15 +324,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
_muteBreakpointsWhileEditing() {
if (this._muted)
return;
- for (var lineNumber = 0; lineNumber < this._textEditor.linesCount; ++lineNumber) {
- var breakpointDecoration = this._textEditor.getAttribute(lineNumber, 'breakpoint');
- if (!breakpointDecoration)
- continue;
- this._removeBreakpointDecoration(lineNumber);
- this._addBreakpointDecoration(
- lineNumber, breakpointDecoration.columnNumber, breakpointDecoration.condition, breakpointDecoration.enabled,
- true);
- }
+ for (var decoration of this._breakpointDecorations)
+ this._updateBreakpointDecoration(decoration);
this._muted = true;
}
@@ -337,34 +345,14 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
_restoreBreakpointsAfterEditing() {
delete this._muted;
- var breakpoints = {};
- // 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);
- }
+ var decorations = Array.from(this._breakpointDecorations);
+ this._breakpointDecorations.clear();
+ for (var decoration of decorations) {
+ decoration.breakpoint.remove();
+ var location = decoration.handle.resolve();
+ if (location)
+ this._setBreakpoint(location.lineNumber, location.columnNumber, decoration.condition, decoration.enabled);
}
-
- // 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);
- }
- }
-
- _removeAllBreakpoints() {
- var breakpoints = this._breakpointManager.breakpointsForUISourceCode(this.uiSourceCode());
- for (var i = 0; i < breakpoints.length; ++i)
- breakpoints[i].remove();
}
/**
@@ -491,27 +479,6 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
delete this._popoverAnchorBox;
}
- /**
- * @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};
-
- this.textEditor.setAttribute(lineNumber, 'breakpoint', breakpoint);
-
- var disabled = !enabled || mutedWhileEditing;
- this.textEditor.addBreakpoint(lineNumber, disabled, !!condition);
- }
-
- _removeBreakpointDecoration(lineNumber) {
- this.textEditor.removeAttribute(lineNumber, 'breakpoint');
- this.textEditor.removeBreakpoint(lineNumber);
- }
-
_onKeyDown(event) {
if (event.key === 'Escape') {
if (this._popoverHelper.isPopoverVisible()) {
@@ -761,9 +728,64 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
}
/**
+ * @param {number} lineNumber
+ * @return {!Array<!Sources.JavaScriptSourceFrame.BreakpointDecoration>}
+ */
+ _lineBreakpointDecorations(lineNumber) {
+ return Array.from(this._breakpointDecorations)
+ .filter(decoration => (decoration.handle.resolve() || {}).lineNumber === lineNumber);
+ }
+
+ /**
+ * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration
+ */
+ _updateBreakpointDecoration(decoration) {
+ if (!this._scheduledBreakpointDecorationUpdates) {
+ /** @type {!Set<!Sources.JavaScriptSourceFrame.BreakpointDecoration>} */
+ this._scheduledBreakpointDecorationUpdates = new Set();
+ setImmediate(() => this.textEditor.operation(update.bind(this)));
+ }
+ this._scheduledBreakpointDecorationUpdates.add(decoration);
+
+ /**
+ * @this {Sources.JavaScriptSourceFrame}
+ */
+ function update() {
+ var lineNumbers = new Set();
+ for (var decoration of this._scheduledBreakpointDecorationUpdates) {
+ var location = decoration.handle.resolve();
+ if (!location)
+ continue;
+ lineNumbers.add(location.lineNumber);
+ }
+ for (var lineNumber of lineNumbers) {
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint', false);
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-disabled', false);
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-conditional', false);
+ var decorations = this._lineBreakpointDecorations(lineNumber);
+ if (!decorations.length)
+ continue;
+ decorations.sort(Sources.JavaScriptSourceFrame.BreakpointDecoration.mostSpecificFirst);
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint', true);
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-disabled', !decorations[0].enabled || this._muted);
+ this.textEditor.toggleLineClass(lineNumber, 'cm-breakpoint-conditional', !!decorations[0].condition);
+ }
+ delete this._scheduledBreakpointDecorationUpdates;
+ this._breakpointDecorationsUpdatedForTest();
+ }
+ }
+
+ _breakpointDecorationsUpdatedForTest() {
+ }
+
+ /**
+ * @param {!Common.Event} event
* @return {boolean}
*/
- _shouldIgnoreExternalBreakpointEvents() {
+ _shouldIgnoreExternalBreakpointEvents(event) {
+ var uiLocation = /** @type {!Workspace.UILocation} */ (event.data.uiLocation);
+ if (uiLocation.uiSourceCode !== this.uiSourceCode() || !this.loaded)
+ return true;
if (this._supportsEnabledBreakpointsWhileEditing())
return false;
if (this._muted)
@@ -776,30 +798,34 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
return false;
}
+ /**
+ * @param {!Common.Event} event
+ */
_breakpointAdded(event) {
- var uiLocation = /** @type {!Workspace.UILocation} */ (event.data.uiLocation);
- if (uiLocation.uiSourceCode !== this.uiSourceCode())
+ if (this._shouldIgnoreExternalBreakpointEvents(event))
return;
- if (this._shouldIgnoreExternalBreakpointEvents())
- return;
-
+ var uiLocation = /** @type {!Workspace.UILocation} */ (event.data.uiLocation);
+ var handle = this._textEditor.textEditorPositionHandle(uiLocation.lineNumber, uiLocation.columnNumber);
var breakpoint = /** @type {!Bindings.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
- if (this.loaded) {
- this._addBreakpointDecoration(
- uiLocation.lineNumber, uiLocation.columnNumber, breakpoint.condition(), breakpoint.enabled(), false);
- }
+ var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration(handle, breakpoint);
+ this._breakpointDecorations.add(decoration);
+ breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol] = decoration;
+ this._updateBreakpointDecoration(decoration);
}
+ /**
+ * @param {!Common.Event} event
+ */
_breakpointRemoved(event) {
- var uiLocation = /** @type {!Workspace.UILocation} */ (event.data.uiLocation);
- if (uiLocation.uiSourceCode !== this.uiSourceCode())
+ if (this._shouldIgnoreExternalBreakpointEvents(event))
return;
- if (this._shouldIgnoreExternalBreakpointEvents())
+ var breakpoint = /** @type {!Bindings.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
+ var decoration = breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol];
+ if (!decoration)
return;
-
- var remainingBreakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), uiLocation.lineNumber);
- if (!remainingBreakpoints.length && this.loaded)
- this._removeBreakpointDecoration(uiLocation.lineNumber);
+ this._breakpointDecorations.delete(decoration);
+ delete breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol];
+ this._updateBreakpointDecoration(decoration);
}
/**
@@ -870,7 +896,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
var breakpointLocations = this._breakpointManager.breakpointLocationsForUISourceCode(this.uiSourceCode());
for (var i = 0; i < breakpointLocations.length; ++i)
- this._breakpointAdded({data: breakpointLocations[i]});
+ this._breakpointAdded(/** @type {!Common.Event} */ ({data: breakpointLocations[i]}));
var scriptFiles = this._scriptFileForTarget.valuesArray();
for (var i = 0; i < scriptFiles.length; ++i)
@@ -941,14 +967,18 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
* @param {boolean} onlyDisable
*/
_toggleBreakpoint(lineNumber, onlyDisable) {
- var breakpoints = this._breakpointManager.findBreakpoints(this.uiSourceCode(), lineNumber);
- if (breakpoints.length) {
+ var decorations = this._lineBreakpointDecorations(lineNumber);
+ if (!decorations.length) {
+ this._createNewBreakpoint(lineNumber, '', true);
+ return;
+ }
+ var hasDisabled = this._textEditor.hasLineClass(lineNumber, 'cm-breakpoint-disabled');
+ var breakpoints = decorations.map(decoration => decoration.breakpoint);
+ for (var breakpoint of breakpoints) {
if (onlyDisable)
- breakpoints[0].setEnabled(!breakpoints[0].enabled());
+ breakpoint.setEnabled(hasDisabled);
else
- breakpoints[0].remove();
- } else {
- this._createNewBreakpoint(lineNumber, '', true);
+ breakpoint.remove();
}
}
@@ -960,7 +990,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
_createNewBreakpoint(lineNumber, condition, enabled) {
findPossibleBreakpoints.call(this, lineNumber)
.then(checkNextLineIfNeeded.bind(this, lineNumber, 4))
- .then(setBreakpoint.bind(this));
+ .then(setBreakpoint.bind(this, condition, enabled));
/**
* @this {!Sources.JavaScriptSourceFrame}
@@ -994,9 +1024,11 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
/**
* @this {!Sources.JavaScriptSourceFrame}
+ * @param {string} condition
+ * @param {boolean} enabled
* @param {?Array<!Workspace.UILocation>} locations
*/
- function setBreakpoint(locations) {
+ function setBreakpoint(condition, enabled, locations) {
if (!locations || !locations.length)
this._setBreakpoint(lineNumber, 0, condition, enabled);
else
@@ -1059,3 +1091,34 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
super.dispose();
}
};
+
+/**
+ * @unrestricted
+ */
+Sources.JavaScriptSourceFrame.BreakpointDecoration = class {
+ /**
+ * @param {!TextEditor.TextEditorPositionHandle} handle
+ * @param {!Bindings.BreakpointManager.Breakpoint} breakpoint
+ */
+ constructor(handle, breakpoint) {
+ this.handle = handle;
+ this.condition = breakpoint.condition();
+ this.enabled = breakpoint.enabled();
+ this.breakpoint = breakpoint;
+ }
+
+ /**
+ * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration1
+ * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration2
+ * @return {number}
+ */
+ static mostSpecificFirst(decoration1, decoration2) {
+ if (!!decoration1.condition !== !!decoration2.condition)
+ return !!decoration1.condition ? -1 : 1;
+ if (decoration1.enabled !== decoration2.enabled)
+ return decoration1.enabled ? -1 : 1;
+ return 0;
+ }
+};
+
+Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol = Symbol('decoration');

Powered by Google App Engine
This is Rietveld 408576698