Commit 0d3d3638 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[devtools] Open coverage drawer when coverage gutter is clicked

Bug: chromium:1004203
Change-Id: I5079a1b7096fc03ed51aa23014c403f9931dbf29
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1803295Reviewed-by: default avatarYang Guo <yangguo@chromium.org>
Reviewed-by: default avatarMichael Hablich <hablich@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699329}
parent 21ed43fb
......@@ -201,6 +201,11 @@ Coverage.CoverageDecorationManager._decoratorType = 'coverage';
* @implements {SourceFrame.LineDecorator}
*/
Coverage.CoverageView.LineDecorator = class {
constructor() {
/** @type {!WeakMap<!TextEditor.CodeMirrorTextEditor, function(!Common.Event)>} */
this._listeners = new WeakMap();
}
/**
* @override
* @param {!Workspace.UISourceCode} uiSourceCode
......@@ -209,31 +214,78 @@ Coverage.CoverageView.LineDecorator = class {
decorate(uiSourceCode, textEditor) {
const decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecorationManager._decoratorType);
if (!decorations || !decorations.size) {
textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType);
this._uninstallGutter(textEditor);
return;
}
const decorationManager =
/** @type {!Coverage.CoverageDecorationManager} */ (decorations.values().next().value.data());
decorationManager.usageByLine(uiSourceCode).then(lineUsage => {
textEditor.operation(() => this._innerDecorate(textEditor, lineUsage));
textEditor.operation(() => this._innerDecorate(uiSourceCode, textEditor, lineUsage));
});
}
/**
* @param {!Workspace.UISourceCode} uiSourceCode
* @param {!TextEditor.CodeMirrorTextEditor} textEditor
* @param {!Array<boolean>} lineUsage
*/
_innerDecorate(textEditor, lineUsage) {
_innerDecorate(uiSourceCode, textEditor, lineUsage) {
const gutterType = Coverage.CoverageView.LineDecorator._gutterType;
textEditor.uninstallGutter(gutterType);
this._uninstallGutter(textEditor);
if (lineUsage.length)
textEditor.installGutter(gutterType, false);
this._installGutter(textEditor, uiSourceCode.url());
for (let line = 0; line < lineUsage.length; ++line) {
// Do not decorate the line if we don't have data.
if (typeof lineUsage[line] !== 'boolean')
continue;
const className = lineUsage[line] ? 'text-editor-coverage-used-marker' : 'text-editor-coverage-unused-marker';
textEditor.setGutterDecoration(line, gutterType, createElementWithClass('div', className));
const gutterElement = createElementWithClass('div', className);
textEditor.setGutterDecoration(line, gutterType, gutterElement);
}
}
/**
* @param {string} url - the url of the file this click handler will select in the coverage drawer
* @return {function(!Common.Event)}
*/
makeGutterClickHandler(url) {
function handleGutterClick(event) {
const eventData = /** @type {!SourceFrame.SourcesTextEditor.GutterClickEventData} */ (event.data);
if (eventData.gutterType !== Coverage.CoverageView.LineDecorator._gutterType)
return;
const coverageViewId = 'coverage';
UI.viewManager.showView(coverageViewId).then(() => UI.viewManager.view(coverageViewId).widget()).then(widget => {
const matchFormattedSuffix = url.match(/(.*):formatted$/);
const urlWithoutFormattedSuffix = (matchFormattedSuffix && matchFormattedSuffix[1]) || url;
widget.selectCoverageItemByUrl(urlWithoutFormattedSuffix);
});
}
return handleGutterClick;
}
/**
* @param {!TextEditor.CodeMirrorTextEditor} textEditor - the text editor to install the gutter on
* @param {string} url - the url of the file in the text editor
*/
_installGutter(textEditor, url) {
let listener = this._listeners.get(textEditor);
if (!listener) {
listener = this.makeGutterClickHandler(url);
this._listeners.set(textEditor, listener);
}
textEditor.installGutter(Coverage.CoverageView.LineDecorator._gutterType, false);
textEditor.addEventListener(SourceFrame.SourcesTextEditor.Events.GutterClick, listener, this);
}
/**
* @param {!TextEditor.CodeMirrorTextEditor} textEditor - the text editor to uninstall the gutter from
*/
_uninstallGutter(textEditor) {
textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType);
const listener = this._listeners.get(textEditor);
if (listener) {
textEditor.removeEventListener(SourceFrame.SourcesTextEditor.Events.GutterClick, listener, this);
this._listeners.delete(textEditor);
}
}
};
......
......@@ -99,6 +99,15 @@ Coverage.CoverageListView = class extends UI.VBox {
this._sortingChanged();
}
selectByUrl(url) {
for (const [info, node] of this._nodeForCoverageInfo.entries()) {
if (info.url() === url) {
node.revealAndSelect();
break;
}
}
}
_onOpenedNode() {
this._revealSourceForSelectedNode();
}
......
......@@ -239,6 +239,10 @@ Coverage.CoverageView = class extends UI.VBox {
return;
this._model.exportReport(fos);
}
selectCoverageItemByUrl(url) {
this._listView.selectByUrl(url);
}
};
Coverage.CoverageView._extensionBindingsURLPrefix = 'extensions::';
......
......@@ -46,7 +46,7 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
this._tokenHighlighter = new SourceFrame.SourcesTextEditor.TokenHighlighter(this, this.codeMirror());
/** @type {!Array<string>} */
this._gutters = ['CodeMirror-linenumbers'];
this._gutters = [SourceFrame.SourcesTextEditor.lineNumbersGutterType];
this.codeMirror().setOption('gutters', this._gutters.slice());
this.codeMirror().setOption('electricChars', false);
......@@ -323,11 +323,8 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
return classNames.indexOf(className) !== -1;
}
_gutterClick(instance, lineNumber, gutter, event) {
if (gutter !== 'CodeMirror-linenumbers')
return;
this.dispatchEventToListeners(
SourceFrame.SourcesTextEditor.Events.GutterClick, {lineNumber: lineNumber, event: event});
_gutterClick(instance, lineNumber, gutterType, event) {
this.dispatchEventToListeners(SourceFrame.SourcesTextEditor.Events.GutterClick, {gutterType, lineNumber, event});
}
_contextMenu(event) {
......@@ -634,7 +631,7 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
}
};
/** @typedef {{lineNumber: number, event: !Event}} */
/** @typedef {{gutterType: string, lineNumber: number, event: !Event}} */
SourceFrame.SourcesTextEditor.GutterClickEventData;
/** @enum {symbol} */
......@@ -935,3 +932,4 @@ SourceFrame.SourcesTextEditor.TokenHighlighter = class {
SourceFrame.SourcesTextEditor.LinesToScanForIndentationGuessing = 1000;
SourceFrame.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan = 16;
SourceFrame.SourcesTextEditor.lineNumbersGutterType = 'CodeMirror-linenumbers';
......@@ -1453,6 +1453,8 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
return;
const eventData = /** @type {!SourceFrame.SourcesTextEditor.GutterClickEventData} */ (event.data);
if (eventData.gutterType !== SourceFrame.SourcesTextEditor.lineNumbersGutterType)
return;
const editorLineNumber = eventData.lineNumber;
const eventObject = eventData.event;
......
......@@ -54,7 +54,8 @@
SourcesTestRunner.debuggerPlugin(sourceFrame)._handleGutterClick({
data: {
lineNumber: lineNumberClicked,
event: {button: 0, shiftKey: shiftKey, consume: () => true}
event: {button: 0, shiftKey: shiftKey, consume: () => true},
gutterType: SourceFrame.SourcesTextEditor.lineNumbersGutterType
}
});
return promise;
......
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