Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/coverage/CoverageDecorationManager.js

Issue 2865573003: DevTools: support live coverage (Closed)
Patch Set: Review comments addressed Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @typedef {!{
7 * id: string,
8 * contentProvider: !Common.ContentProvider,
9 * line: number,
10 * column: number
11 * }}
12 */
13 Coverage.RawLocation;
14
15 Coverage.CoverageDecorationManager = class {
16 /**
17 * @param {!Coverage.CoverageModel} coverageModel
18 */
19 constructor(coverageModel) {
20 this._coverageModel = coverageModel;
21 /** @type {!Map<!Common.ContentProvider, ?TextUtils.Text>} */
22 this._textByProvider = new Map();
23 /** @type {!Multimap<!Common.ContentProvider, !Workspace.UISourceCode>} */
24 this._uiSourceCodeByContentProvider = new Multimap();
25
26 for (var uiSourceCode of Workspace.workspace.uiSourceCodes())
27 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._deco ratorType, this);
28 Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCode Added, this._onUISourceCodeAdded, this);
29 }
30
31 dispose() {
32 for (var uiSourceCode of Workspace.workspace.uiSourceCodes())
33 uiSourceCode.removeDecorationsForType(Coverage.CoverageDecorationManager._ decoratorType);
34 Workspace.workspace.removeEventListener(
35 Workspace.Workspace.Events.UISourceCodeAdded, this._onUISourceCodeAdded, this);
36 }
37
38 /**
39 * @param {!Array<!Coverage.CoverageInfo>} updatedEntries
40 */
41 update(updatedEntries) {
42 for (var uiSourceCode of Workspace.workspace.uiSourceCodes()) {
43 uiSourceCode.removeDecorationsForType(Coverage.CoverageDecorationManager._ decoratorType);
44 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._deco ratorType, this);
45 }
46 }
47
48 /**
49 * @param {!Workspace.UISourceCode} uiSourceCode
50 * @return {!Promise<!Array<boolean>>}
51 */
52 async usageByLine(uiSourceCode) {
53 var result = [];
54 var sourceText = new TextUtils.Text(uiSourceCode.content() || '');
55 await this._updateTexts(uiSourceCode, sourceText);
56 var lineEndings = sourceText.lineEndings();
57 for (var line = 0; line < sourceText.lineCount(); ++line) {
58 var lineLength = lineEndings[line] - (line ? lineEndings[line - 1] : 0);
59 var startLocations = this._rawLocationsForSourceLocation(uiSourceCode, lin e, 0);
60 var endLocations = this._rawLocationsForSourceLocation(uiSourceCode, line, lineLength - 1);
61 var used = false;
62 for (var startIndex = 0, endIndex = 0; startIndex < startLocations.length; ++startIndex) {
63 var start = startLocations[startIndex];
64 while (endIndex < endLocations.length &&
65 Coverage.CoverageDecorationManager._compareLocations(start, endLo cations[endIndex]) >= 0)
alph 2017/05/05 22:50:36 Shouldn't be ">" instead? start === endLocations[e
66 ++endIndex;
67 if (endIndex >= endLocations.length || endLocations[endIndex].id !== sta rt.id)
alph 2017/05/05 22:50:36 hmm. How come "endLocations[endIndex].id !== start
68 continue;
69 var end = endLocations[endIndex];
70 var text = this._textByProvider.get(end.contentProvider);
71 if (!text)
72 continue;
73 var textValue = text.value();
74 var startOffset = text.offsetFromPosition(start.line, start.column);
75 var endOffset = text.offsetFromPosition(end.line, end.column);
76 while (startOffset <= endOffset && /\s/.test(textValue[startOffset]))
77 ++startOffset;
78 while (startOffset <= endOffset && /\s/.test(textValue[endOffset]))
79 --endOffset;
80 used =
81 startOffset <= endOffset && this._coverageModel.usageForRange(end.co ntentProvider, startOffset, endOffset);
82 if (used)
83 break;
84 }
85 result.push(used);
86 }
87 return result;
88 }
89
90 /**
91 * @param {!Workspace.UISourceCode} uiSourceCode
92 * @param {!TextUtils.Text} text
93 * @return {!Promise}
94 */
95 _updateTexts(uiSourceCode, text) {
96 var promises = [];
97 for (var line = 0; line < text.lineCount(); ++line) {
98 for (var entry of this._rawLocationsForSourceLocation(uiSourceCode, line, 0)) {
99 if (this._textByProvider.has(entry.contentProvider))
100 continue;
101 this._textByProvider.set(entry.contentProvider, null);
102 this._uiSourceCodeByContentProvider.set(entry.contentProvider, uiSourceC ode);
103 promises.push(this._updateTextForProvider(entry.contentProvider));
104 }
105 }
106 return Promise.all(promises);
107 }
108
109 /**
110 * @param {!Common.ContentProvider} contentProvider
111 * @return {!Promise}
112 */
113 async _updateTextForProvider(contentProvider) {
114 var content = await contentProvider.requestContent();
115 this._textByProvider.set(contentProvider, new TextUtils.Text(content));
116 }
117
118 /**
119 * @param {!Workspace.UISourceCode} uiSourceCode
120 * @param {number} line
121 * @param {number} column
122 * @return {!Array<!Coverage.RawLocation>}
123 */
124 _rawLocationsForSourceLocation(uiSourceCode, line, column) {
125 var result = [];
126 var contentType = uiSourceCode.contentType();
127 if (contentType.hasScripts()) {
128 var location = Bindings.debuggerWorkspaceBinding.uiLocationToRawLocation(u iSourceCode, line, column);
129 if (location && location.script()) {
130 result.push({
131 id: `js:${location.scriptId}`,
132 contentProvider: location.script(),
133 line: location.lineNumber,
134 column: location.columnNumber
135 });
136 }
137 }
138 if (contentType.isStyleSheet() || contentType.isDocument()) {
139 var rawStyleLocations =
140 Bindings.cssWorkspaceBinding.uiLocationToRawLocations(new Workspace.UI Location(uiSourceCode, line, column));
141 for (var location of rawStyleLocations) {
142 if (!location.header())
143 continue;
144 result.push({
145 id: `css:${location.styleSheetId}`,
146 contentProvider: location.header(),
147 line: location.lineNumber,
148 column: location.columnNumber
149 });
150 }
151 }
152 result.sort(Coverage.CoverageDecorationManager._compareLocations);
153 return result;
154 }
155
156 /**
157 * @param {!Coverage.RawLocation} a
158 * @param {!Coverage.RawLocation} b
alph 2017/05/05 22:50:36 @return
159 */
160 static _compareLocations(a, b) {
161 return a.id.localeCompare(b.id) || a.line - b.line || a.column - b.column;
162 }
163
164 /**
165 * @param {!Common.Event} event
166 */
167 _onUISourceCodeAdded(event) {
168 var uiSourceCode = /** @type !Workspace.UISourceCode */ (event.data);
169 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._decora torType, this);
170 }
171 };
172
173 Coverage.CoverageDecorationManager._decoratorType = 'coverage';
174
175 /**
176 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator}
177 */
178 Coverage.CoverageView.LineDecorator = class {
179 /**
180 * @override
181 * @param {!Workspace.UISourceCode} uiSourceCode
182 * @param {!TextEditor.CodeMirrorTextEditor} textEditor
183 */
184 decorate(uiSourceCode, textEditor) {
185 var decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecoratio nManager._decoratorType);
186 if (!decorations.size) {
187 textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType );
188 return;
189 }
190 var decorationManager =
191 /** @type {!Coverage.CoverageDecorationManager} */ (decorations.values() .next().value.data());
192 decorationManager.usageByLine(uiSourceCode).then(lineUsage => {
193 textEditor.operation(() => this._innerDecorate(textEditor, lineUsage));
194 });
195 }
196
197 /**
198 * @param {!TextEditor.CodeMirrorTextEditor} textEditor
199 * @param {!Array<boolean>} lineUsage
200 */
201 _innerDecorate(textEditor, lineUsage) {
202 var gutterType = Coverage.CoverageView.LineDecorator._gutterType;
203 textEditor.uninstallGutter(gutterType);
204 textEditor.installGutter(gutterType, false);
205 for (var line = 0; line < lineUsage.length; ++line) {
206 var className = lineUsage[line] ? 'text-editor-coverage-used-marker' : 'te xt-editor-coverage-unused-marker';
207 textEditor.setGutterDecoration(line, gutterType, createElementWithClass('d iv', className));
208 }
209 }
210 };
211
212 Coverage.CoverageView.LineDecorator._gutterType = 'CodeMirror-gutter-coverage';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698