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); |
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 |