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

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

Issue 2865573003: DevTools: support live coverage (Closed)
Patch Set: minor polish on corner cases 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 entry of updatedEntries) {
43 for (var uiSourceCode of this._uiSourceCodeByContentProvider.get(entry.con tentProvider())) {
44 uiSourceCode.removeDecorationsForType(Coverage.CoverageDecorationManager ._decoratorType);
45 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._de coratorType, this);
46 }
47 }
48 }
49
50 /**
51 * @param {!Workspace.UISourceCode} uiSourceCode
52 * @return {!Promise<!Array<boolean>>}
53 */
54 async usageByLine(uiSourceCode) {
55 var result = [];
56 var sourceText = new TextUtils.Text(uiSourceCode.content() || '');
57 await this._updateTexts(uiSourceCode, sourceText);
58 var lineEndings = sourceText.lineEndings();
59 for (var line = 0; line < sourceText.lineCount(); ++line) {
60 var lineLength = lineEndings[line] - (line ? lineEndings[line - 1] : 0) - 1;
61 if (!lineLength) {
62 result.push(false);
63 continue;
64 }
65 var startLocations = this._rawLocationsForSourceLocation(uiSourceCode, lin e, 0);
66 var endLocations = this._rawLocationsForSourceLocation(uiSourceCode, line, lineLength);
67 var used = false;
68 for (var startIndex = 0, endIndex = 0; startIndex < startLocations.length; ++startIndex) {
69 var start = startLocations[startIndex];
70 while (endIndex < endLocations.length &&
71 Coverage.CoverageDecorationManager._compareLocations(start, endLo cations[endIndex]) >= 0)
72 ++endIndex;
73 if (endIndex >= endLocations.length || endLocations[endIndex].id !== sta rt.id)
74 continue;
75 var end = endLocations[endIndex++];
76 var text = this._textByProvider.get(end.contentProvider);
77 if (!text)
78 continue;
79 var textValue = text.value();
80 var startOffset = text.offsetFromPosition(start.line, start.column);
81 var endOffset = text.offsetFromPosition(end.line, end.column);
82 while (startOffset <= endOffset && /\s/.test(textValue[startOffset]))
83 ++startOffset;
84 while (startOffset <= endOffset && /\s/.test(textValue[endOffset]))
85 --endOffset;
86 used =
87 startOffset <= endOffset && this._coverageModel.usageForRange(end.co ntentProvider, startOffset, endOffset);
88 if (used)
89 break;
90 }
91 result.push(used);
92 }
93 return result;
94 }
95
96 /**
97 * @param {!Workspace.UISourceCode} uiSourceCode
98 * @param {!TextUtils.Text} text
99 * @return {!Promise}
100 */
101 _updateTexts(uiSourceCode, text) {
102 var promises = [];
103 for (var line = 0; line < text.lineCount(); ++line) {
104 for (var entry of this._rawLocationsForSourceLocation(uiSourceCode, line, 0)) {
105 if (this._textByProvider.has(entry.contentProvider))
106 continue;
107 this._textByProvider.set(entry.contentProvider, null);
108 this._uiSourceCodeByContentProvider.set(entry.contentProvider, uiSourceC ode);
109 promises.push(this._updateTextForProvider(entry.contentProvider));
110 }
111 }
112 return Promise.all(promises);
113 }
114
115 /**
116 * @param {!Common.ContentProvider} contentProvider
117 * @return {!Promise}
118 */
119 async _updateTextForProvider(contentProvider) {
120 var content = await contentProvider.requestContent();
121 this._textByProvider.set(contentProvider, new TextUtils.Text(content));
122 }
123
124 /**
125 * @param {!Workspace.UISourceCode} uiSourceCode
126 * @param {number} line
127 * @param {number} column
128 * @return {!Array<!Coverage.RawLocation>}
129 */
130 _rawLocationsForSourceLocation(uiSourceCode, line, column) {
131 var result = [];
132 var contentType = uiSourceCode.contentType();
133 if (contentType.hasScripts()) {
134 var location = Bindings.debuggerWorkspaceBinding.uiLocationToRawLocation(u iSourceCode, line, column);
135 if (location && location.script()) {
136 result.push({
137 id: `js:${location.scriptId}`,
138 contentProvider: location.script(),
139 line: location.lineNumber,
140 column: location.columnNumber
141 });
142 }
143 }
144 if (contentType.isStyleSheet() || contentType.isDocument()) {
145 var rawStyleLocations =
146 Bindings.cssWorkspaceBinding.uiLocationToRawLocations(new Workspace.UI Location(uiSourceCode, line, column));
147 for (var location of rawStyleLocations) {
148 if (!location.header())
149 continue;
150 result.push({
151 id: `css:${location.styleSheetId}`,
152 contentProvider: location.header(),
153 line: location.lineNumber,
154 column: location.columnNumber
155 });
156 }
157 }
158 result.sort(Coverage.CoverageDecorationManager._compareLocations);
159 return result;
160 }
161
162 /**
163 * @param {!Coverage.RawLocation} a
164 * @param {!Coverage.RawLocation} b
165 */
166 static _compareLocations(a, b) {
167 return a.id.localeCompare(b.id) || a.line - b.line || a.column - b.column;
168 }
169
170 /**
171 * @param {!Common.Event} event
172 */
173 _onUISourceCodeAdded(event) {
174 var uiSourceCode = /** @type !Workspace.UISourceCode */ (event.data);
175 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._decora torType, this);
176 }
177 };
178
179 Coverage.CoverageDecorationManager._decoratorType = 'coverage';
180
181 /**
182 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator}
183 */
184 Coverage.CoverageView.LineDecorator = class {
185 /**
186 * @override
187 * @param {!Workspace.UISourceCode} uiSourceCode
188 * @param {!TextEditor.CodeMirrorTextEditor} textEditor
189 */
190 decorate(uiSourceCode, textEditor) {
191 var decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecoratio nManager._decoratorType);
192 if (!decorations.size) {
193 textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType );
194 return;
195 }
196 var decorationManager =
197 /** @type {!Coverage.CoverageDecorationManager} */ (decorations.values() .next().value.data());
198 decorationManager.usageByLine(uiSourceCode).then(lineUsage => {
199 textEditor.operation(() => this._innerDecorate(textEditor, lineUsage));
200 });
201 }
202
203 /**
204 * @param {!TextEditor.CodeMirrorTextEditor} textEditor
205 * @param {!Array<boolean>} lineUsage
206 */
207 _innerDecorate(textEditor, lineUsage) {
208 var gutterType = Coverage.CoverageView.LineDecorator._gutterType;
209 textEditor.uninstallGutter(gutterType);
210 textEditor.installGutter(gutterType, false);
211 for (var line = 0; line < lineUsage.length; ++line) {
212 var className = lineUsage[line] ? 'text-editor-coverage-used-marker' : 'te xt-editor-coverage-unused-marker';
213 textEditor.setGutterDecoration(line, gutterType, createElementWithClass('d iv', className));
214 }
215 }
216 };
217
218 Coverage.CoverageView.LineDecorator._gutterType = 'CodeMirror-gutter-coverage';
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/BUILD.gn ('k') | third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698