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'; ...@@ -201,6 +201,11 @@ Coverage.CoverageDecorationManager._decoratorType = 'coverage';
* @implements {SourceFrame.LineDecorator} * @implements {SourceFrame.LineDecorator}
*/ */
Coverage.CoverageView.LineDecorator = class { Coverage.CoverageView.LineDecorator = class {
constructor() {
/** @type {!WeakMap<!TextEditor.CodeMirrorTextEditor, function(!Common.Event)>} */
this._listeners = new WeakMap();
}
/** /**
* @override * @override
* @param {!Workspace.UISourceCode} uiSourceCode * @param {!Workspace.UISourceCode} uiSourceCode
...@@ -209,31 +214,78 @@ Coverage.CoverageView.LineDecorator = class { ...@@ -209,31 +214,78 @@ Coverage.CoverageView.LineDecorator = class {
decorate(uiSourceCode, textEditor) { decorate(uiSourceCode, textEditor) {
const decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecorationManager._decoratorType); const decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecorationManager._decoratorType);
if (!decorations || !decorations.size) { if (!decorations || !decorations.size) {
textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType); this._uninstallGutter(textEditor);
return; return;
} }
const decorationManager = const decorationManager =
/** @type {!Coverage.CoverageDecorationManager} */ (decorations.values().next().value.data()); /** @type {!Coverage.CoverageDecorationManager} */ (decorations.values().next().value.data());
decorationManager.usageByLine(uiSourceCode).then(lineUsage => { 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 {!TextEditor.CodeMirrorTextEditor} textEditor
* @param {!Array<boolean>} lineUsage * @param {!Array<boolean>} lineUsage
*/ */
_innerDecorate(textEditor, lineUsage) { _innerDecorate(uiSourceCode, textEditor, lineUsage) {
const gutterType = Coverage.CoverageView.LineDecorator._gutterType; const gutterType = Coverage.CoverageView.LineDecorator._gutterType;
textEditor.uninstallGutter(gutterType); this._uninstallGutter(textEditor);
if (lineUsage.length) if (lineUsage.length)
textEditor.installGutter(gutterType, false); this._installGutter(textEditor, uiSourceCode.url());
for (let line = 0; line < lineUsage.length; ++line) { for (let line = 0; line < lineUsage.length; ++line) {
// Do not decorate the line if we don't have data. // Do not decorate the line if we don't have data.
if (typeof lineUsage[line] !== 'boolean') if (typeof lineUsage[line] !== 'boolean')
continue; continue;
const className = lineUsage[line] ? 'text-editor-coverage-used-marker' : 'text-editor-coverage-unused-marker'; 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 { ...@@ -99,6 +99,15 @@ Coverage.CoverageListView = class extends UI.VBox {
this._sortingChanged(); this._sortingChanged();
} }
selectByUrl(url) {
for (const [info, node] of this._nodeForCoverageInfo.entries()) {
if (info.url() === url) {
node.revealAndSelect();
break;
}
}
}
_onOpenedNode() { _onOpenedNode() {
this._revealSourceForSelectedNode(); this._revealSourceForSelectedNode();
} }
......
...@@ -239,6 +239,10 @@ Coverage.CoverageView = class extends UI.VBox { ...@@ -239,6 +239,10 @@ Coverage.CoverageView = class extends UI.VBox {
return; return;
this._model.exportReport(fos); this._model.exportReport(fos);
} }
selectCoverageItemByUrl(url) {
this._listView.selectByUrl(url);
}
}; };
Coverage.CoverageView._extensionBindingsURLPrefix = 'extensions::'; Coverage.CoverageView._extensionBindingsURLPrefix = 'extensions::';
......
...@@ -46,7 +46,7 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor { ...@@ -46,7 +46,7 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
this._tokenHighlighter = new SourceFrame.SourcesTextEditor.TokenHighlighter(this, this.codeMirror()); this._tokenHighlighter = new SourceFrame.SourcesTextEditor.TokenHighlighter(this, this.codeMirror());
/** @type {!Array<string>} */ /** @type {!Array<string>} */
this._gutters = ['CodeMirror-linenumbers']; this._gutters = [SourceFrame.SourcesTextEditor.lineNumbersGutterType];
this.codeMirror().setOption('gutters', this._gutters.slice()); this.codeMirror().setOption('gutters', this._gutters.slice());
this.codeMirror().setOption('electricChars', false); this.codeMirror().setOption('electricChars', false);
...@@ -323,11 +323,8 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor { ...@@ -323,11 +323,8 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor {
return classNames.indexOf(className) !== -1; return classNames.indexOf(className) !== -1;
} }
_gutterClick(instance, lineNumber, gutter, event) { _gutterClick(instance, lineNumber, gutterType, event) {
if (gutter !== 'CodeMirror-linenumbers') this.dispatchEventToListeners(SourceFrame.SourcesTextEditor.Events.GutterClick, {gutterType, lineNumber, event});
return;
this.dispatchEventToListeners(
SourceFrame.SourcesTextEditor.Events.GutterClick, {lineNumber: lineNumber, event: event});
} }
_contextMenu(event) { _contextMenu(event) {
...@@ -634,7 +631,7 @@ SourceFrame.SourcesTextEditor = class extends TextEditor.CodeMirrorTextEditor { ...@@ -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; SourceFrame.SourcesTextEditor.GutterClickEventData;
/** @enum {symbol} */ /** @enum {symbol} */
...@@ -935,3 +932,4 @@ SourceFrame.SourcesTextEditor.TokenHighlighter = class { ...@@ -935,3 +932,4 @@ SourceFrame.SourcesTextEditor.TokenHighlighter = class {
SourceFrame.SourcesTextEditor.LinesToScanForIndentationGuessing = 1000; SourceFrame.SourcesTextEditor.LinesToScanForIndentationGuessing = 1000;
SourceFrame.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan = 16; SourceFrame.SourcesTextEditor.MaximumNumberOfWhitespacesPerSingleSpan = 16;
SourceFrame.SourcesTextEditor.lineNumbersGutterType = 'CodeMirror-linenumbers';
...@@ -1453,6 +1453,8 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin { ...@@ -1453,6 +1453,8 @@ Sources.DebuggerPlugin = class extends Sources.UISourceCodeFrame.Plugin {
return; return;
const eventData = /** @type {!SourceFrame.SourcesTextEditor.GutterClickEventData} */ (event.data); const eventData = /** @type {!SourceFrame.SourcesTextEditor.GutterClickEventData} */ (event.data);
if (eventData.gutterType !== SourceFrame.SourcesTextEditor.lineNumbersGutterType)
return;
const editorLineNumber = eventData.lineNumber; const editorLineNumber = eventData.lineNumber;
const eventObject = eventData.event; const eventObject = eventData.event;
......
...@@ -54,7 +54,8 @@ ...@@ -54,7 +54,8 @@
SourcesTestRunner.debuggerPlugin(sourceFrame)._handleGutterClick({ SourcesTestRunner.debuggerPlugin(sourceFrame)._handleGutterClick({
data: { data: {
lineNumber: lineNumberClicked, lineNumber: lineNumberClicked,
event: {button: 0, shiftKey: shiftKey, consume: () => true} event: {button: 0, shiftKey: shiftKey, consume: () => true},
gutterType: SourceFrame.SourcesTextEditor.lineNumbersGutterType
} }
}); });
return promise; 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