Commit 098da25c authored by Erik Luo's avatar Erik Luo Committed by Commit Bot

DevTools: introduce basic logpoint experiment

Behind an experiment, a new context menu option in the Sources gutter
allows adding a logpoint. Future CLs will tackle editing a breakpoint
type and UI changes.

Logpoints `console.log` a message instead of pausing.

Bug: 700519
Change-Id: Ib33c1a84de4fbc06b6fde6e2e3dd7628e3896d64
Reviewed-on: https://chromium-review.googlesource.com/c/1330079
Commit-Queue: Erik Luo <luoe@chromium.org>
Reviewed-by: default avatarJoel Einbinder <einbinder@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613223}
parent 1c59d48c
......@@ -119,6 +119,7 @@ Main.Main = class {
Runtime.experiments.register('protocolMonitor', 'Protocol Monitor');
Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
Runtime.experiments.register('sourceDiff', 'Source diff');
Runtime.experiments.register('sourcesLogpoints', 'Sources: logpoints');
Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel');
Runtime.experiments.register(
'stepIntoAsync', 'Introduce separate step action, stepInto becomes powerful enough to go inside async call');
......
......@@ -8,9 +8,10 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
/**
* @param {number} editorLineNumber
* @param {string} oldCondition
* @param {boolean} preferLogpoint
* @param {function({committed: boolean, condition: string})} onFinish
*/
constructor(editorLineNumber, oldCondition, onFinish) {
constructor(editorLineNumber, oldCondition, preferLogpoint, onFinish) {
super(true);
this.registerRequiredCSS('sources/breakpointEditDialog.css');
this._onFinish = onFinish;
......@@ -18,10 +19,18 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
/** @type {?UI.TextEditor} */
this._editor = null;
const logpointPrefix = Sources.BreakpointEditDialog._LogpointPrefix;
const logpointSuffix = Sources.BreakpointEditDialog._LogpointSuffix;
this._isLogpoint = oldCondition.startsWith(logpointPrefix) && oldCondition.endsWith(logpointSuffix);
if (this._isLogpoint)
oldCondition = oldCondition.substring(logpointPrefix.length, oldCondition.length - logpointSuffix.length);
this._isLogpoint = this._isLogpoint || preferLogpoint;
const labelElement = this.contentElement.createChild('label', 'source-frame-breakpoint-message');
labelElement.htmlFor = 'source-frame-breakpoint-condition';
labelElement.createTextChild(
Common.UIString('The breakpoint on line %d will stop only if this expression is true:', editorLineNumber + 1));
const labelText = this._isLogpoint ? ls`On line ${editorLineNumber + 1}, log to the Console:` : ls
`The breakpoint on line ${editorLineNumber + 1} will stop only if this expression is true:`;
labelElement.createTextChild(labelText);
self.runtime.extension(UI.TextEditorFactory).instance().then(factory => {
this._editor =
......@@ -41,6 +50,14 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
});
}
/**
* @param {string} condition
* @return {string}
*/
static _conditionForLogpoint(condition) {
return `${Sources.BreakpointEditDialog._LogpointPrefix}${condition}${Sources.BreakpointEditDialog._LogpointSuffix}`;
}
/**
* @param {boolean} committed
*/
......@@ -49,7 +66,9 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
return;
this._finished = true;
this._editor.widget().detach();
const condition = this._editor.text();
let condition = this._editor.text();
if (this._isLogpoint)
condition = Sources.BreakpointEditDialog._conditionForLogpoint(condition);
this._onFinish({committed, condition});
}
......@@ -69,3 +88,6 @@ Sources.BreakpointEditDialog = class extends UI.Widget {
this._finishEditing(false);
}
};
Sources.BreakpointEditDialog._LogpointPrefix = '/** DEVTOOLS_LOGPOINT */ console.log(';
Sources.BreakpointEditDialog._LogpointSuffix = ')';
......@@ -253,6 +253,11 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
contextMenu.debugSection().appendItem(
Common.UIString('Add conditional breakpoint\u2026'),
this._editBreakpointCondition.bind(this, editorLineNumber, null, null));
if (Runtime.experiments.isEnabled('sourcesLogpoints')) {
contextMenu.debugSection().appendItem(
ls`Add logpoint\u2026`,
this._editBreakpointCondition.bind(this, editorLineNumber, null, null, true /* preferLogpoint */));
}
contextMenu.debugSection().appendItem(
Common.UIString('Never pause here'), this._createNewBreakpoint.bind(this, editorLineNumber, 'false', true));
} else {
......@@ -632,11 +637,12 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
* @param {number} editorLineNumber
* @param {?Bindings.BreakpointManager.Breakpoint} breakpoint
* @param {?{lineNumber: number, columnNumber: number}} location
* @param {boolean=} preferLogpoint
*/
async _editBreakpointCondition(editorLineNumber, breakpoint, location) {
async _editBreakpointCondition(editorLineNumber, breakpoint, location, preferLogpoint) {
const oldCondition = breakpoint ? breakpoint.condition() : '';
const decorationElement = createElement('div');
const dialog = new Sources.BreakpointEditDialog(editorLineNumber, oldCondition, result => {
const dialog = new Sources.BreakpointEditDialog(editorLineNumber, oldCondition, !!preferLogpoint, result => {
dialog.detach();
this._textEditor.removeDecoration(decorationElement, editorLineNumber);
if (!result.committed)
......@@ -1210,6 +1216,12 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
contextMenu.debugSection().appendItem(
Common.UIString('Add conditional breakpoint\u2026'),
this._editBreakpointCondition.bind(this, editorLocation.lineNumber, null, editorLocation));
if (Runtime.experiments.isEnabled('sourcesLogpoints')) {
contextMenu.debugSection().appendItem(
ls`Add logpoint\u2026`,
this._editBreakpointCondition.bind(
this, editorLocation.lineNumber, null, editorLocation, true /* preferLogpoint */));
}
contextMenu.debugSection().appendItem(
Common.UIString('Never pause here'), this._setBreakpoint.bind(this, location[0], location[1], 'false', true));
}
......
Tests setting logpoints.
Running: testSetLogpoint
Script source was shown.
Set timer for test function.
Test function finished.
Breakpoint sidebar pane
set-breakpoint.html:15 return x;
Message count: 1
VM:1 x is 3.1622776601683795
Breakpoints removed.
Breakpoint sidebar pane
No breakpoints
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function() {
TestRunner.addResult(`Tests setting logpoints.\n`);
await TestRunner.loadModule('console_test_runner');
await TestRunner.loadModule('sources_test_runner');
await TestRunner.showPanel('sources');
await TestRunner.navigatePromise('resources/set-breakpoint.html');
var currentSourceFrame;
SourcesTestRunner.setQuiet(true);
SourcesTestRunner.runDebuggerTestSuite([
function testSetLogpoint(next) {
SourcesTestRunner.showScriptSource(
'set-breakpoint.html', didShowScriptSource);
function didShowScriptSource(sourceFrame) {
currentSourceFrame = sourceFrame;
TestRunner.addResult('Script source was shown.');
const condition = Sources.BreakpointEditDialog._conditionForLogpoint(`"x is", x`);
SourcesTestRunner
.createNewBreakpoint(currentSourceFrame, 14, condition, true)
.then(() => SourcesTestRunner.waitBreakpointSidebarPane())
.then(() => SourcesTestRunner.runTestFunction())
.then(testFunctionFinished);
}
async function testFunctionFinished(callFrames) {
TestRunner.addResult('Test function finished.');
SourcesTestRunner.dumpBreakpointSidebarPane();
await ConsoleTestRunner.waitForConsoleMessagesPromise(1);
ConsoleTestRunner.dumpConsoleMessages();
SourcesTestRunner.waitBreakpointSidebarPane().then(breakpointRemoved);
SourcesTestRunner.removeBreakpoint(currentSourceFrame, 14);
}
function breakpointRemoved() {
TestRunner.addResult('Breakpoints removed.');
SourcesTestRunner.dumpBreakpointSidebarPane();
next();
}
},
]);
})();
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment