Chromium Code Reviews| 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 |