OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | |
dgozman
2017/05/05 19:21:19
no (c)
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 Coverage.CoverageDecorationManager = class { | |
6 /** | |
7 * @param {!Coverage.CoverageModel} coverageModel | |
8 */ | |
9 constructor(coverageModel) { | |
10 this._coverageModel = coverageModel; | |
11 /** @type !Map<!Common.ContentProvider, ?TextUtils.Text> */ | |
12 this._textByProvider = new Map(); | |
13 /** @type !Multimap<!Common.ContentProvider, !Workspace.UISourceCode> */ | |
14 this._uiSourceCodeByContentProvider = new Multimap(); | |
15 | |
16 for (var project of Workspace.workspace.projects()) { | |
dgozman
2017/05/05 19:21:19
Use Workspace.uiSourceCodes().
| |
17 for (var uiSourceCode of project.uiSourceCodes()) | |
18 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._de coratorType, this); | |
19 } | |
20 Workspace.workspace.addEventListener(Workspace.Workspace.Events.UISourceCode Added, this._onUISourceCodeAdded, this); | |
21 } | |
22 | |
23 dispose() { | |
24 for (var project of Workspace.workspace.projects()) { | |
25 for (var uiSourceCode of project.uiSourceCodes()) | |
dgozman
2017/05/05 19:21:19
ditto
| |
26 uiSourceCode.removeDecorationsForType(Coverage.CoverageDecorationManager ._decoratorType); | |
27 } | |
28 Workspace.workspace.removeEventListener( | |
29 Workspace.Workspace.Events.UISourceCodeAdded, this._onUISourceCodeAdded, this); | |
30 } | |
31 | |
32 /** | |
33 * @param {!Array<!Coverage.CoverageInfo>} updatedEntries | |
34 */ | |
35 update(updatedEntries) { | |
36 for (var entry of updatedEntries) { | |
37 for (var uiSourceCode of this._uiSourceCodeByContentProvider.get(entry.con tentProvider())) { | |
38 uiSourceCode.removeDecorationsForType(Coverage.CoverageDecorationManager ._decoratorType); | |
39 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._de coratorType, this); | |
40 } | |
41 } | |
42 } | |
43 | |
44 /** | |
45 * @param {!Workspace.UISourceCode} uiSourceCode | |
46 * @return {!Promise<!Array<boolean>>} | |
47 */ | |
48 async usageByLine(uiSourceCode) { | |
49 var result = []; | |
50 var sourceText = new TextUtils.Text(uiSourceCode.content() || ''); | |
51 await this._updateTexts(uiSourceCode, sourceText); | |
52 var lineEndings = sourceText.lineEndings(); | |
53 for (var line = 0; line < sourceText.lineCount(); ++line) { | |
54 var lineLength = lineEndings[line] - (line ? lineEndings[line - 1] : 0); | |
55 var startLocations = this._rawLocationsForSourceLocation(uiSourceCode, lin e, 0); | |
56 var endLocations = this._rawLocationsForSourceLocation(uiSourceCode, line, lineLength - 1); | |
57 var startLocationsByProvider = new Map(startLocations.map(location => [loc ation.contentProvider, location])); | |
alph
2017/05/05 19:18:08
can it have several locations with he same provide
| |
58 var used = false; | |
59 for (var end of endLocations) { | |
alph
2017/05/05 19:18:08
nit: var used = endLocations.some(...);
;-)
| |
60 var start = startLocationsByProvider.get(end.contentProvider); | |
61 var text = this._textByProvider.get(end.contentProvider); | |
62 if (!start || !text) | |
63 continue; | |
64 var textValue = text.value(); | |
65 var startOffset = text.offsetFromPosition(start.line, start.column); | |
66 var endOffset = text.offsetFromPosition(end.line, end.column); | |
67 while (startOffset < endOffset && /\s/.test(textValue[startOffset])) | |
alph
2017/05/05 19:18:08
Have you considered using substr and match with /^
alph
2017/05/05 19:18:08
<=
| |
68 ++startOffset; | |
69 while (startOffset < endOffset && /\s/.test(textValue[endOffset])) | |
alph
2017/05/05 19:18:08
ditto
| |
70 --endOffset; | |
71 used = this._coverageModel.usageForRange(end.contentProvider, startOffse t, endOffset); | |
72 if (used) | |
73 break; | |
74 } | |
75 result.push(used); | |
76 } | |
77 return result; | |
78 } | |
79 | |
80 /** | |
81 * @param {!Workspace.UISourceCode} uiSourceCode | |
82 * @param {!TextUtils.Text} text | |
83 * @return !Promise | |
alph
2017/05/05 19:18:08
I'm ok with using the clean syntax, but I know cou
| |
84 */ | |
85 _updateTexts(uiSourceCode, text) { | |
86 var promises = []; | |
87 for (var line = 0; line < text.lineCount(); ++line) { | |
88 for (var entry of this._rawLocationsForSourceLocation(uiSourceCode, line, 0)) { | |
89 if (!this._textByProvider.has(entry.contentProvider)) { | |
alph
2017/05/05 19:18:08
if (...) continue;
| |
90 this._textByProvider.set(entry.contentProvider, null); | |
91 this._uiSourceCodeByContentProvider.set(entry.contentProvider, uiSourc eCode); | |
92 promises.push(this._updateTextForProvider(entry.contentProvider)); | |
93 } | |
94 } | |
95 } | |
96 return Promise.all(promises); | |
97 } | |
98 | |
99 /** | |
100 * @param {!Common.ContentProvider} contentProvider | |
alph
2017/05/05 19:18:08
@return
| |
101 */ | |
102 async _updateTextForProvider(contentProvider) { | |
103 var content = await contentProvider.requestContent(); | |
104 this._textByProvider.set(contentProvider, new TextUtils.Text(content)); | |
105 } | |
106 | |
107 /** | |
108 * @param {!Workspace.UISourceCode} uiSourceCode | |
109 * @param {number} line | |
110 * @param {number} column | |
111 * @return {!Array<!{contentProvider: !Common.ContentProvider, line: number, c olumn: number}>} | |
112 */ | |
113 _rawLocationsForSourceLocation(uiSourceCode, line, column) { | |
114 if (uiSourceCode.contentType().hasScripts()) { | |
115 var location = Bindings.debuggerWorkspaceBinding.uiLocationToRawLocation(u iSourceCode, line, column); | |
116 return location && location.script() ? | |
dgozman
2017/05/05 19:21:19
html file could have both css and js locations.
| |
117 [{contentProvider: location.script(), line: location.lineNumber, colum n: location.columnNumber}] : | |
118 []; | |
119 } | |
120 var rawStyleLocations = | |
121 Bindings.cssWorkspaceBinding.uiLocationToRawLocations(new Workspace.UILo cation(uiSourceCode, line, 0)); | |
122 var result = []; | |
123 for (var location of rawStyleLocations) { | |
124 if (!location.header()) | |
125 continue; | |
126 result.push({contentProvider: location.header(), line: location.lineNumber , column: location.columnNumber}); | |
127 } | |
128 return result; | |
129 } | |
130 | |
131 /** | |
132 * @param {!Common.Event} event | |
133 */ | |
134 _onUISourceCodeAdded(event) { | |
135 var uiSourceCode = /** @type !Workspace.UISourceCode */ (event.data); | |
136 uiSourceCode.addLineDecoration(0, Coverage.CoverageDecorationManager._decora torType, this); | |
137 } | |
138 }; | |
139 | |
140 Coverage.CoverageDecorationManager._decoratorType = 'coverage'; | |
141 | |
142 /** | |
143 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator} | |
144 */ | |
145 Coverage.CoverageView.LineDecorator = class { | |
146 /** | |
147 * @override | |
148 * @param {!Workspace.UISourceCode} uiSourceCode | |
149 * @param {!TextEditor.CodeMirrorTextEditor} textEditor | |
150 */ | |
151 decorate(uiSourceCode, textEditor) { | |
152 var decorations = uiSourceCode.decorationsForType(Coverage.CoverageDecoratio nManager._decoratorType); | |
153 if (!decorations.size) { | |
154 textEditor.uninstallGutter(Coverage.CoverageView.LineDecorator._gutterType ); | |
155 return; | |
156 } | |
157 var decorationManager = | |
158 /** @type {!Coverage.CoverageDecorationManager} */ (decorations.values() .next().value.data()); | |
159 decorationManager.usageByLine(uiSourceCode).then(lineUsage => { | |
160 textEditor.operation(() => this._innerDecorate(textEditor, lineUsage)); | |
161 }); | |
162 } | |
163 | |
164 /** | |
165 * @param {!TextEditor.CodeMirrorTextEditor} textEditor | |
166 * @param {!Array<boolean>} lineUsage | |
167 */ | |
168 _innerDecorate(textEditor, lineUsage) { | |
169 var gutterType = Coverage.CoverageView.LineDecorator._gutterType; | |
170 textEditor.uninstallGutter(gutterType); | |
171 textEditor.installGutter(gutterType, false); | |
172 for (var line = 0; line < lineUsage.length; ++line) { | |
173 var className = lineUsage[line] ? 'text-editor-coverage-used-marker' : 'te xt-editor-coverage-unused-marker'; | |
174 textEditor.setGutterDecoration(line, gutterType, createElementWithClass('d iv', className)); | |
175 } | |
176 } | |
177 }; | |
178 | |
179 Coverage.CoverageView.LineDecorator._gutterType = 'CodeMirror-gutter-coverage'; | |
OLD | NEW |