Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 Coverage.CoverageView = class extends UI.VBox { | 5 Coverage.CoverageView = class extends UI.VBox { |
| 6 constructor() { | 6 constructor() { |
| 7 super(true); | 7 super(true); |
| 8 | 8 |
| 9 /** @type {?Coverage.CoverageModel} */ | 9 /** @type {?Coverage.CoverageModel} */ |
| 10 this._model = null; | 10 this._model = null; |
| 11 /** @type {number|undefined} */ | |
| 12 this._pollTimer; | |
| 13 /** @type {?Coverage.CoverageDecorationManager} */ | |
| 14 this._decorationManager = null; | |
| 15 | |
| 11 this.registerRequiredCSS('coverage/coverageView.css'); | 16 this.registerRequiredCSS('coverage/coverageView.css'); |
| 12 | 17 |
| 13 var toolbarContainer = this.contentElement.createChild('div', 'coverage-tool bar-container'); | 18 var toolbarContainer = this.contentElement.createChild('div', 'coverage-tool bar-container'); |
| 14 var topToolbar = new UI.Toolbar('coverage-toolbar', toolbarContainer); | 19 var topToolbar = new UI.Toolbar('coverage-toolbar', toolbarContainer); |
| 15 | 20 |
| 16 this._toggleRecordAction = | 21 this._toggleRecordAction = |
| 17 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.toggle-rec ording')); | 22 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.toggle-rec ording')); |
| 18 this._toggleRecordButton = UI.Toolbar.createActionButton(this._toggleRecordA ction); | 23 this._toggleRecordButton = UI.Toolbar.createActionButton(this._toggleRecordA ction); |
| 19 topToolbar.appendToolbarItem(this._toggleRecordButton); | 24 topToolbar.appendToolbarItem(this._toggleRecordButton); |
| 20 | 25 |
| 21 var startWithReloadAction = | 26 var startWithReloadAction = |
| 22 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.start-with -reload')); | 27 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.start-with -reload')); |
| 23 this._startWithReloadButton = UI.Toolbar.createActionButton(startWithReloadA ction); | 28 this._startWithReloadButton = UI.Toolbar.createActionButton(startWithReloadA ction); |
| 24 topToolbar.appendToolbarItem(this._startWithReloadButton); | 29 topToolbar.appendToolbarItem(this._startWithReloadButton); |
| 25 | 30 |
| 26 this._clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'larg eicon-clear'); | 31 this._clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'larg eicon-clear'); |
| 27 this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._rese t.bind(this)); | 32 this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._rese t.bind(this)); |
| 28 topToolbar.appendToolbarItem(this._clearButton); | 33 topToolbar.appendToolbarItem(this._clearButton); |
| 29 | 34 |
| 30 this._coverageResultsElement = this.contentElement.createChild('div', 'cover age-results'); | 35 this._coverageResultsElement = this.contentElement.createChild('div', 'cover age-results'); |
| 31 this._progressElement = this._coverageResultsElement.createChild('div', 'pro gress-view'); | 36 this._progressElement = this._coverageResultsElement.createChild('div', 'pro gress-view'); |
| 32 this._listView = new Coverage.CoverageListView(); | 37 this._listView = new Coverage.CoverageListView(); |
| 33 | 38 |
| 34 this._statusToolbarElement = this.contentElement.createChild('div', 'coverag e-toolbar-summary'); | 39 this._statusToolbarElement = this.contentElement.createChild('div', 'coverag e-toolbar-summary'); |
| 35 this._statusMessageElement = this._statusToolbarElement.createChild('div', ' coverage-message'); | 40 this._statusMessageElement = this._statusToolbarElement.createChild('div', ' coverage-message'); |
| 36 this._showHelpScreen(); | 41 this._showHelpScreen(); |
| 37 } | 42 } |
| 38 | 43 |
| 39 _reset() { | 44 _reset() { |
| 40 Workspace.workspace.uiSourceCodes().forEach( | 45 if (this._decorationManager) { |
| 41 uiSourceCode => uiSourceCode.removeDecorationsForType(Coverage.CoverageV iew.LineDecorator.type)); | 46 this._decorationManager.dispose(); |
| 42 | 47 this._decorationManager = null; |
| 48 } | |
| 49 this._listView.reset(); | |
| 43 this._listView.detach(); | 50 this._listView.detach(); |
| 44 this._coverageResultsElement.removeChildren(); | 51 this._coverageResultsElement.removeChildren(); |
| 45 this._showHelpScreen(); | 52 this._showHelpScreen(); |
| 46 | 53 |
| 47 this._statusMessageElement.textContent = ''; | 54 this._statusMessageElement.textContent = ''; |
| 48 } | 55 } |
| 49 | 56 |
| 50 _showHelpScreen() { | 57 _showHelpScreen() { |
| 51 this._coverageResultsElement.appendChild(this._progressElement); | 58 this._coverageResultsElement.appendChild(this._progressElement); |
| 52 this._progressElement.removeChildren(); | 59 this._progressElement.removeChildren(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 _startRecording() { | 91 _startRecording() { |
| 85 this._reset(); | 92 this._reset(); |
| 86 var mainTarget = SDK.targetManager.mainTarget(); | 93 var mainTarget = SDK.targetManager.mainTarget(); |
| 87 if (!mainTarget) | 94 if (!mainTarget) |
| 88 return; | 95 return; |
| 89 console.assert(!this._model, 'Attempting to start coverage twice'); | 96 console.assert(!this._model, 'Attempting to start coverage twice'); |
| 90 var model = new Coverage.CoverageModel(mainTarget); | 97 var model = new Coverage.CoverageModel(mainTarget); |
| 91 if (!model.start()) | 98 if (!model.start()) |
| 92 return; | 99 return; |
| 93 this._model = model; | 100 this._model = model; |
| 101 this._decorationManager = new Coverage.CoverageDecorationManager(model); | |
| 94 this._toggleRecordAction.setToggled(true); | 102 this._toggleRecordAction.setToggled(true); |
| 95 this._clearButton.setEnabled(false); | 103 this._clearButton.setEnabled(false); |
| 96 this._startWithReloadButton.setEnabled(false); | 104 this._startWithReloadButton.setEnabled(false); |
| 97 this._progressElement.textContent = Common.UIString('Recording...'); | 105 this._coverageResultsElement.removeChildren(); |
| 106 this._listView.show(this._coverageResultsElement); | |
| 107 this._poll(); | |
| 108 } | |
| 109 | |
| 110 async _poll() { | |
| 111 delete this._pollTimer; | |
| 112 var updates = await this._model.poll(); | |
| 113 this._updateViews(updates); | |
| 114 this._pollTimer = setTimeout(() => this._poll(), 700); | |
|
dgozman
2017/05/05 19:21:19
Would throttler help here?
| |
| 98 } | 115 } |
| 99 | 116 |
| 100 async _stopRecording() { | 117 async _stopRecording() { |
| 118 if (this._pollTimer) { | |
| 119 clearTimeout(this._pollTimer); | |
| 120 delete this._pollTimer; | |
| 121 } | |
| 122 var updatedEntries = await this._model.stop(); | |
| 123 this._updateViews(updatedEntries); | |
| 124 this._model = null; | |
| 101 this._toggleRecordAction.setToggled(false); | 125 this._toggleRecordAction.setToggled(false); |
| 102 this._progressElement.textContent = Common.UIString('Fetching results...'); | |
| 103 | |
| 104 var coverageInfo = await this._model.stop(); | |
| 105 this._model = null; | |
| 106 await this._updateViews(coverageInfo); | |
| 107 this._startWithReloadButton.setEnabled(true); | 126 this._startWithReloadButton.setEnabled(true); |
| 108 this._clearButton.setEnabled(true); | 127 this._clearButton.setEnabled(true); |
| 109 } | 128 } |
| 110 | 129 |
| 111 /** | 130 /** |
| 112 * @param {!Array<!Coverage.URLCoverageInfo>} coverageInfo | 131 * @param {!Array<!Coverage.CoverageInfo>} updatedEntries |
| 113 */ | 132 */ |
| 114 async _updateViews(coverageInfo) { | 133 async _updateViews(updatedEntries) { |
| 115 this._updateStats(coverageInfo); | 134 var urlEntries = this._model.entries(); |
| 116 this._coverageResultsElement.removeChildren(); | 135 this._updateStats(urlEntries); |
| 117 this._listView.update(coverageInfo); | 136 this._listView.update(urlEntries); |
| 118 this._listView.show(this._coverageResultsElement); | 137 this._decorationManager.update(updatedEntries); |
| 119 await Promise.all(coverageInfo.map(entry => Coverage.CoverageView._updateGut ter(entry))); | |
| 120 } | 138 } |
| 121 | 139 |
| 122 /** | 140 /** |
| 123 * @param {!Array<!Coverage.URLCoverageInfo>} coverageInfo | 141 * @param {!Array<!Coverage.URLCoverageInfo>} coverageInfo |
| 124 */ | 142 */ |
| 125 _updateStats(coverageInfo) { | 143 _updateStats(coverageInfo) { |
| 126 var total = 0; | 144 var total = 0; |
| 127 var unused = 0; | 145 var unused = 0; |
| 128 for (var info of coverageInfo) { | 146 for (var info of coverageInfo) { |
| 129 total += info.size(); | 147 total += info.size(); |
| 130 unused += info.unusedSize(); | 148 unused += info.unusedSize(); |
| 131 } | 149 } |
| 132 | 150 |
| 133 var percentUnused = total ? Math.round(100 * unused / total) : 0; | 151 var percentUnused = total ? Math.round(100 * unused / total) : 0; |
| 134 this._statusMessageElement.textContent = Common.UIString( | 152 this._statusMessageElement.textContent = Common.UIString( |
| 135 '%s of %s bytes are not used. (%d%%)', Number.bytesToString(unused), Num ber.bytesToString(total), | 153 '%s of %s bytes are not used. (%d%%)', Number.bytesToString(unused), Num ber.bytesToString(total), |
| 136 percentUnused); | 154 percentUnused); |
| 137 } | 155 } |
| 138 | |
| 139 /** | |
| 140 * @param {!Coverage.URLCoverageInfo} coverageInfo | |
| 141 */ | |
| 142 static async _updateGutter(coverageInfo) { | |
| 143 var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(coverageInfo.url() ); | |
| 144 if (!uiSourceCode) | |
| 145 return; | |
| 146 // FIXME: gutter should be set in terms of offsets and therefore should not require contents. | |
| 147 var ranges = await coverageInfo.buildTextRanges(); | |
| 148 for (var r of ranges) | |
| 149 uiSourceCode.addDecoration(r.range, Coverage.CoverageView.LineDecorator.ty pe, r.count); | |
| 150 } | |
| 151 }; | 156 }; |
| 152 | 157 |
| 153 /** | 158 /** |
| 154 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator} | |
| 155 */ | |
| 156 Coverage.CoverageView.LineDecorator = class { | |
| 157 /** | |
| 158 * @override | |
| 159 * @param {!Workspace.UISourceCode} uiSourceCode | |
| 160 * @param {!TextEditor.CodeMirrorTextEditor} textEditor | |
| 161 */ | |
| 162 decorate(uiSourceCode, textEditor) { | |
| 163 var gutterType = 'CodeMirror-gutter-coverage'; | |
| 164 | |
| 165 var decorations = uiSourceCode.decorationsForType(Coverage.CoverageView.Line Decorator.type); | |
| 166 textEditor.uninstallGutter(gutterType); | |
| 167 if (!decorations || !decorations.size) | |
| 168 return; | |
| 169 | |
| 170 textEditor.installGutter(gutterType, false); | |
| 171 var lastLine = 0; | |
| 172 var lastData = undefined; | |
| 173 for (var decoration of decorations) { | |
| 174 var range = decoration.range(); | |
| 175 var startLine = range.startLine; | |
| 176 if (lastLine && lastLine === startLine && lastData !== !!decoration.data() ) { | |
| 177 var element = createElementWithClass('div', 'text-editor-coverage-mixed- marker'); | |
| 178 textEditor.setGutterDecoration(startLine, gutterType, element); | |
| 179 startLine++; | |
| 180 } else { | |
| 181 startLine = Math.max(startLine, lastLine); | |
| 182 } | |
| 183 lastLine = range.endLine; | |
| 184 lastData = !!decoration.data(); | |
| 185 var className = lastData ? 'text-editor-coverage-used-marker' : 'text-edit or-coverage-unused-marker'; | |
| 186 for (var line = startLine; line <= lastLine; ++line) { | |
| 187 var element = createElementWithClass('div', className); | |
| 188 textEditor.setGutterDecoration(line, gutterType, element); | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 }; | |
| 193 | |
| 194 Coverage.CoverageView.LineDecorator.type = 'coverage'; | |
| 195 | |
| 196 /** | |
| 197 * @implements {UI.ActionDelegate} | 159 * @implements {UI.ActionDelegate} |
| 198 */ | 160 */ |
| 199 Coverage.CoverageView.ActionDelegate = class { | 161 Coverage.CoverageView.ActionDelegate = class { |
| 200 /** | 162 /** |
| 201 * @override | 163 * @override |
| 202 * @param {!UI.Context} context | 164 * @param {!UI.Context} context |
| 203 * @param {string} actionId | 165 * @param {string} actionId |
| 204 * @return {boolean} | 166 * @return {boolean} |
| 205 */ | 167 */ |
| 206 handleAction(context, actionId) { | 168 handleAction(context, actionId) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 222 coverageView._toggleRecording(); | 184 coverageView._toggleRecording(); |
| 223 break; | 185 break; |
| 224 case 'coverage.start-with-reload': | 186 case 'coverage.start-with-reload': |
| 225 coverageView._startWithReload(); | 187 coverageView._startWithReload(); |
| 226 break; | 188 break; |
| 227 default: | 189 default: |
| 228 console.assert(false, `Unknown action: ${actionId}`); | 190 console.assert(false, `Unknown action: ${actionId}`); |
| 229 } | 191 } |
| 230 } | 192 } |
| 231 }; | 193 }; |
| OLD | NEW |