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

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

Issue 2526013002: [DevTools] Added inline breakpoints (Closed)
Patch Set: 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 13b5de4e4fd21e80c5f72eb25df571108d69d02f..be26a174d1c4247950056b45e38babdde924b5e0 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -211,13 +211,16 @@ 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._lineBreakpointDecorations(lineNumber).map(decoration => decoration.breakpoint);
+ var breakpoints = this._lineBreakpointDecorations(lineNumber)
+ .map(decoration => decoration.breakpoint)
+ .filter(breakpoint => !!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\u2026'), this._editBreakpointCondition.bind(this, lineNumber));
+ Common.UIString('Add conditional breakpoint\u2026'),
+ this._editBreakpointCondition.bind(this, lineNumber, null, null));
contextMenu.appendItem(
Common.UIString('Never pause here'), this._createNewBreakpoint.bind(this, lineNumber, 'false', true));
} else {
@@ -228,7 +231,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
if (hasOneBreakpoint) {
contextMenu.appendItem(
Common.UIString('Edit breakpoint\u2026'),
- this._editBreakpointCondition.bind(this, lineNumber, breakpoints[0]));
+ this._editBreakpointCondition.bind(this, lineNumber, breakpoints[0], null));
}
var hasEnabled = breakpoints.some(breakpoint => breakpoint.enabled());
if (hasEnabled) {
@@ -348,6 +351,9 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
var decorations = Array.from(this._breakpointDecorations);
this._breakpointDecorations.clear();
for (var decoration of decorations) {
+ decoration.hide();
+ if (!decoration.breakpoint)
+ continue;
decoration.breakpoint.remove();
var location = decoration.handle.resolve();
if (location)
@@ -490,9 +496,10 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
/**
* @param {number} lineNumber
- * @param {!Bindings.BreakpointManager.Breakpoint=} breakpoint
+ * @param {?Bindings.BreakpointManager.Breakpoint} breakpoint
+ * @param {?{lineNumber: number, columnNumber: number}} location
*/
- _editBreakpointCondition(lineNumber, breakpoint) {
+ _editBreakpointCondition(lineNumber, breakpoint, location) {
this._conditionElement = this._createConditionElement(lineNumber);
this.textEditor.addDecoration(this._conditionElement, lineNumber);
@@ -508,6 +515,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
if (breakpoint)
breakpoint.setCondition(newText);
+ else if (location)
+ this._setBreakpoint(location.lineNumber, location.columnNumber, newText, true);
else
this._createNewBreakpoint(lineNumber, newText, true);
}
@@ -758,20 +767,79 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
continue;
lineNumbers.add(location.lineNumber);
}
+ var promises = [];
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)
+ if (!decorations.some(decoration => !!decoration.breakpoint)) {
+ for (var decoration of decorations) {
+ decoration.hide();
+ this._breakpointDecorations.delete(decoration);
+ }
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);
+ if (Runtime.experiments.isEnabled('inlineBreakpoints')) {
+ promises.push(
+ this._breakpointManager
+ .possibleBreakpoints(this.uiSourceCode(), new Common.TextRange(lineNumber, 0, lineNumber + 1, 0))
+ .then(
+ locations => this._textEditor.operation(addInlineDecorations.bind(this, lineNumber, locations))));
+ }
}
delete this._scheduledBreakpointDecorationUpdates;
- this._breakpointDecorationsUpdatedForTest();
+ if (!promises.length)
+ this._breakpointDecorationsUpdatedForTest();
+ else
+ Promise.all(promises).then(() => this._breakpointDecorationsUpdatedForTest());
+ }
+
+ /**
+ * @this {Sources.JavaScriptSourceFrame}
+ * @param {number} lineNumber
+ * @param {!Array<!Workspace.UILocation>} possibleLocations
+ */
+ function addInlineDecorations(lineNumber, possibleLocations) {
+ var decorations = this._lineBreakpointDecorations(lineNumber);
+ // Hide all inline decoration, remove decoration if decoration doesn't have a breakpoint.
+ for (var decoration of decorations) {
+ decoration.hide();
+ if (!decoration.breakpoint)
+ this._breakpointDecorations.delete(decoration);
+ }
+ decorations = decorations.filter(decoration => !!decoration.breakpoint);
+ // If less then two locations or no real breakpoints in this line - don't show any inline decorations.
+ if (possibleLocations.length <= 1 || !decorations.length)
+ return;
+ // Add missing decorations for possible locations without breakpoint.
+ /** @type {!Set<number>} */
+ var columns = new Set();
+ for (var decoration of decorations) {
+ var location = decoration.handle.resolve();
+ if (location)
+ columns.add(location.columnNumber);
+ }
+ for (var location of possibleLocations) {
+ if (columns.has(location.columnNumber))
+ continue;
+ var handle = this._textEditor.textEditorPositionHandle(location.lineNumber, location.columnNumber);
+ var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration(handle, '', false, null);
+ this._breakpointDecorations.add(decoration);
+ decorations.push(decoration);
+ }
+ // Render inline decorations.
+ for (var decoration of decorations) {
+ var element = decoration.show(this._textEditor);
+ if (!element)
+ continue;
+ element.addEventListener('click', this._inlineBreakpointClick.bind(this, decoration), true);
+ element.addEventListener('contextmenu', this._inlineBreakpointContextMenu.bind(this, decoration), true);
+ }
}
}
@@ -779,6 +847,50 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
}
/**
+ * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration
+ * @param {!Event} event
+ */
+ _inlineBreakpointClick(decoration, event) {
+ event.consume(true);
+ if (decoration.breakpoint) {
+ if (event.shiftKey)
+ decoration.breakpoint.setEnabled(!decoration.breakpoint.enabled());
+ else
+ decoration.breakpoint.remove();
+ } else {
+ var location = decoration.handle.resolve();
+ if (!location)
+ return;
+ this._setBreakpoint(location.lineNumber, location.columnNumber, decoration.condition, true);
+ }
+ }
+
+ /**
+ * @param {!Sources.JavaScriptSourceFrame.BreakpointDecoration} decoration
+ * @param {!Event} event
+ */
+ _inlineBreakpointContextMenu(decoration, event) {
+ event.consume(true);
+ var location = decoration.handle.resolve();
+ if (!location)
+ return;
+ var contextMenu = new UI.ContextMenu(event);
+ if (decoration.breakpoint) {
+ contextMenu.appendItem(
+ Common.UIString('Edit breakpoint\u2026'),
+ this._editBreakpointCondition.bind(this, location.lineNumber, decoration.breakpoint, null));
+ } else {
+ contextMenu.appendItem(
+ Common.UIString('Add conditional breakpoint\u2026'),
+ this._editBreakpointCondition.bind(this, location.lineNumber, null, location));
+ contextMenu.appendItem(
+ Common.UIString('Never pause here'),
+ this._setBreakpoint.bind(this, location.lineNumber, location.columnNumber, 'false', true));
+ }
+ contextMenu.show();
+ }
+
+ /**
* @param {!Common.Event} event
* @return {boolean}
*/
@@ -807,7 +919,8 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
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);
- var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration(handle, breakpoint);
+ var decoration = new Sources.JavaScriptSourceFrame.BreakpointDecoration(
+ handle, breakpoint.condition(), breakpoint.enabled(), breakpoint);
this._breakpointDecorations.add(decoration);
breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol] = decoration;
this._updateBreakpointDecoration(decoration);
@@ -824,6 +937,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
if (!decoration)
return;
this._breakpointDecorations.delete(decoration);
+ decoration.hide();
delete breakpoint[Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol];
this._updateBreakpointDecoration(decoration);
}
@@ -973,7 +1087,7 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
return;
}
var hasDisabled = this._textEditor.hasLineClass(lineNumber, 'cm-breakpoint-disabled');
- var breakpoints = decorations.map(decoration => decoration.breakpoint);
+ var breakpoints = decorations.map(decoration => decoration.breakpoint).filter(breakpoint => !!breakpoint);
for (var breakpoint of breakpoints) {
if (onlyDisable)
breakpoint.setEnabled(hasDisabled);
@@ -1098,13 +1212,18 @@ Sources.JavaScriptSourceFrame = class extends Sources.UISourceCodeFrame {
Sources.JavaScriptSourceFrame.BreakpointDecoration = class {
lushnikov 2016/11/23 21:54:39 What is BreakpointDecoration? It used to be a gutt
kozy 2016/11/23 23:08:47 BreakpointDecoration represents decoration for bre
/**
* @param {!TextEditor.TextEditorPositionHandle} handle
- * @param {!Bindings.BreakpointManager.Breakpoint} breakpoint
+ * @param {string} condition
+ * @param {boolean} enabled
+ * @param {?Bindings.BreakpointManager.Breakpoint} breakpoint
*/
- constructor(handle, breakpoint) {
+ constructor(handle, condition, enabled, breakpoint) {
lushnikov 2016/11/23 21:54:39 let's make decoration texteditor-aware: construct
kozy 2016/11/23 23:08:47 Done.
this.handle = handle;
- this.condition = breakpoint.condition();
- this.enabled = breakpoint.enabled();
+ this.condition = condition;
+ this.enabled = enabled;
this.breakpoint = breakpoint;
+
+ /** @type {?TextEditor.TextEditorBookMark} */
+ this._bookmark = null;
}
/**
@@ -1119,6 +1238,35 @@ Sources.JavaScriptSourceFrame.BreakpointDecoration = class {
return decoration1.enabled ? -1 : 1;
return 0;
}
+
+ /**
+ * @param {!TextEditor.CodeMirrorTextEditor} textEditor
+ * @return {?Element}
+ */
+ show(textEditor) {
+ if (this._bookmark)
+ return null;
+ var location = this.handle.resolve();
+ if (!location)
+ return null;
+ var inlineBreakpoint = createElementWithClass('div', 'cm-inline-breakpoint');
+ inlineBreakpoint.classList.toggle('cm-inline-conditional', !!this.condition);
+ inlineBreakpoint.classList.toggle('cm-inline-disabled', !this.enabled);
+ this._bookmark = textEditor.addBookmark(
+ location.lineNumber, location.columnNumber, inlineBreakpoint,
+ Sources.JavaScriptSourceFrame.BreakpointDecoration._bookmarkSymbol);
+ this._bookmark[Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest] = inlineBreakpoint;
+ return inlineBreakpoint;
+ }
+
+ hide() {
+ if (!this._bookmark)
+ return;
+ this._bookmark.clear();
+ this._bookmark = null;
+ }
};
Sources.JavaScriptSourceFrame.BreakpointDecoration._decorationSymbol = Symbol('decoration');
+Sources.JavaScriptSourceFrame.BreakpointDecoration._bookmarkSymbol = Symbol('bookmark');
+Sources.JavaScriptSourceFrame.BreakpointDecoration._elementSymbolForTest = Symbol('element');

Powered by Google App Engine
This is Rietveld 408576698