| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Helper for creating HTML visualization of the source map information | 5 /// Helper for creating HTML visualization of the source map information |
| 6 /// generated by a [SourceMapProcessor]. | 6 /// generated by a [SourceMapProcessor]. |
| 7 | 7 |
| 8 library sourcemap.html.helper; | 8 library sourcemap.html.helper; |
| 9 | 9 |
| 10 import 'dart:convert'; | 10 import 'dart:convert'; |
| 11 | 11 |
| 12 import 'package:compiler/src/io/source_file.dart'; | 12 import 'package:compiler/src/io/source_file.dart'; |
| 13 import 'package:compiler/src/io/source_information.dart'; | 13 import 'package:compiler/src/io/source_information.dart'; |
| 14 import 'package:compiler/src/js/js.dart' as js; | 14 import 'package:compiler/src/js/js.dart' as js; |
| 15 | 15 |
| 16 import 'colors.dart'; | 16 import 'colors.dart'; |
| 17 import 'sourcemap_helper.dart'; | 17 import 'sourcemap_helper.dart'; |
| 18 import 'sourcemap_html_templates.dart'; | 18 import 'sourcemap_html_templates.dart'; |
| 19 | 19 |
| 20 /// Returns the [index]th color for visualization. | 20 /// Returns the [index]th color for visualization. |
| 21 String toColor(int index) { | 21 HSV toColor(int index) { |
| 22 int hueCount = 24; | 22 int hueCount = 24; |
| 23 double h = 360.0 * (index % hueCount) / hueCount; | 23 double h = 360.0 * (index % hueCount) / hueCount; |
| 24 double v = 1.0; | 24 double v = 1.0; |
| 25 double s = 0.5; | 25 double s = 0.5; |
| 26 HSV hsv = new HSV(h, s, v); | 26 return new HSV(h, s, v); |
| 27 RGB rgb = HSV.toRGB(hsv); | 27 } |
| 28 return rgb.toHex; | 28 |
| 29 /// Return the CSS color value for the [index]th color. |
| 30 String toColorCss(int index) { |
| 31 return toColor(index).toCss; |
| 32 } |
| 33 |
| 34 /// Return the CSS color value for the [index]th span. |
| 35 String toPattern(int index) { |
| 36 /// Use gradient on spans to visually identify consecutive spans mapped to the |
| 37 /// same source location. |
| 38 HSV startColor = toColor(index); |
| 39 HSV endColor = new HSV(startColor.h, startColor.s + 0.4, startColor.v - 0.2); |
| 40 return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})'; |
| 29 } | 41 } |
| 30 | 42 |
| 31 /// Return the html for the [index] line number. | 43 /// Return the html for the [index] line number. |
| 32 String lineNumber(int index) { | 44 String lineNumber(int index) { |
| 33 return '<span class="lineNumber">${index + 1} </span>'; | 45 return '<span class="lineNumber">${index + 1} </span>'; |
| 34 } | 46 } |
| 35 | 47 |
| 36 /// Return the html escaped [text]. | 48 /// Return the html escaped [text]. |
| 37 String escape(String text) { | 49 String escape(String text) { |
| 38 return const HtmlEscape().convert(text); | 50 return const HtmlEscape().convert(text); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 void insertSourceLocations(List<SourceLocation> lastSourceLocations) { | 136 void insertSourceLocations(List<SourceLocation> lastSourceLocations) { |
| 125 endCurrentLocation(); | 137 endCurrentLocation(); |
| 126 | 138 |
| 127 String color; | 139 String color; |
| 128 int index; | 140 int index; |
| 129 String title; | 141 String title; |
| 130 if (lastSourceLocations.length == 1) { | 142 if (lastSourceLocations.length == 1) { |
| 131 SourceLocation sourceLocation = lastSourceLocations.single; | 143 SourceLocation sourceLocation = lastSourceLocations.single; |
| 132 if (sourceLocation != null) { | 144 if (sourceLocation != null) { |
| 133 index = collection.getIndex(sourceLocation); | 145 index = collection.getIndex(sourceLocation); |
| 134 color = "background:#${toColor(index)};"; | 146 color = "background:${toPattern(index)};"; |
| 135 title = sourceLocation.shortText; | 147 title = sourceLocation.shortText; |
| 136 currentLocation = sourceLocation; | 148 currentLocation = sourceLocation; |
| 137 } | 149 } |
| 138 } else { | 150 } else { |
| 139 | 151 |
| 140 index = collection.getIndex(lastSourceLocations.first); | 152 index = collection.getIndex(lastSourceLocations.first); |
| 141 StringBuffer sb = new StringBuffer(); | 153 StringBuffer sb = new StringBuffer(); |
| 142 double delta = 100.0 / (lastSourceLocations.length); | 154 double delta = 100.0 / (lastSourceLocations.length); |
| 143 double position = 0.0; | 155 double position = 0.0; |
| 144 | 156 |
| 145 void addColor(String color) { | 157 void addColor(String color) { |
| 146 sb.write(', ${color} ${position.toInt()}%'); | 158 sb.write(', ${color} ${position.toInt()}%'); |
| 147 position += delta; | 159 position += delta; |
| 148 sb.write(', ${color} ${position.toInt()}%'); | 160 sb.write(', ${color} ${position.toInt()}%'); |
| 149 } | 161 } |
| 150 | 162 |
| 151 for (SourceLocation sourceLocation in lastSourceLocations) { | 163 for (SourceLocation sourceLocation in lastSourceLocations) { |
| 152 if (sourceLocation == null) continue; | 164 if (sourceLocation == null) continue; |
| 153 int colorIndex = collection.getIndex(sourceLocation); | 165 int colorIndex = collection.getIndex(sourceLocation); |
| 154 addColor('#${toColor(colorIndex)}'); | 166 addColor('${toColorCss(colorIndex)}'); |
| 155 currentLocation = sourceLocation; | 167 currentLocation = sourceLocation; |
| 156 } | 168 } |
| 157 color = 'background: linear-gradient(to right${sb}); ' | 169 color = 'background: linear-gradient(to right${sb}); ' |
| 158 'background-size: 10px 10px;'; | 170 'background-size: 10px 10px;'; |
| 159 title = lastSourceLocations.map((l) => l.shortText).join(','); | 171 title = lastSourceLocations.map((l) => l.shortText).join(','); |
| 160 } | 172 } |
| 161 if (index != null) { | 173 if (index != null) { |
| 162 Set<int> indices = | 174 Set<int> indices = |
| 163 lastSourceLocations.map((l) => collection.getIndex(l)).toSet(); | 175 lastSourceLocations.map((l) => collection.getIndex(l)).toSet(); |
| 164 String onmouseover = indices.map((i) => '\'$i\'').join(','); | 176 String onmouseover = indices.map((i) => '\'$i\'').join(','); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 int start = sourceLocation.column; | 368 int start = sourceLocation.column; |
| 357 int end = line.length; | 369 int end = line.length; |
| 358 if (i + 1 < locations.length) { | 370 if (i + 1 < locations.length) { |
| 359 end = locations[i + 1].column; | 371 end = locations[i + 1].column; |
| 360 } | 372 } |
| 361 if (i == 0) { | 373 if (i == 0) { |
| 362 codeBuffer.write(lineNumber(lineIndex)); | 374 codeBuffer.write(lineNumber(lineIndex)); |
| 363 codeBuffer.write(line.substring(0, start)); | 375 codeBuffer.write(line.substring(0, start)); |
| 364 } | 376 } |
| 365 codeBuffer.write( | 377 codeBuffer.write( |
| 366 '<a name="${index}" style="background:#${toColor(index)};" ' | 378 '<a name="${index}" style="background:${toPattern(index)};" ' |
| 367 'title="[${lineIndex + 1},${start + 1}]" ' | 379 'title="[${lineIndex + 1},${start + 1}]" ' |
| 368 'onmouseover="highlight(\'$index\');" ' | 380 'onmouseover="highlight(\'$index\');" ' |
| 369 'onmouseout="highlight();">'); | 381 'onmouseout="highlight();">'); |
| 370 codeBuffer.write(line.substring(start, end)); | 382 codeBuffer.write(line.substring(start, end)); |
| 371 codeBuffer.write('</a>'); | 383 codeBuffer.write('</a>'); |
| 372 } | 384 } |
| 373 lastLineIndex = lineIndex; | 385 lastLineIndex = lineIndex; |
| 374 }); | 386 }); |
| 375 | 387 |
| 376 flush(); | 388 flush(); |
| 377 }); | 389 }); |
| 378 String display = showAsBlock ? 'block' : 'none'; | 390 String display = showAsBlock ? 'block' : 'none'; |
| 379 return ''' | 391 return ''' |
| 380 <div name="$name" class="dart-buffer" style="display:$display;"> | 392 <div name="$name" class="dart-buffer" style="display:$display;"> |
| 381 <h3>Dart code for: ${escape(name)}</h3> | 393 <h3>Dart code for: ${escape(name)}</h3> |
| 382 ${dartCodeBuffer} | 394 ${dartCodeBuffer} |
| 383 </div>'''; | 395 </div>'''; |
| 384 } | 396 } |
| 385 | 397 |
| 386 /// Computes a HTML visualization of the [codePoints]. | 398 /// Computes a HTML visualization of the [codePoints]. |
| 387 String computeJsTraceHtmlPart(List<CodePoint> codePoints, | 399 String computeJsTraceHtmlPart(List<CodePoint> codePoints, |
| 388 SourceLocationCollection collection) { | 400 SourceLocationCollection collection) { |
| 389 StringBuffer buffer = new StringBuffer(); | 401 StringBuffer buffer = new StringBuffer(); |
| 390 buffer.write('<table style="width:100%;">'); | 402 buffer.write('<table style="width:100%;">'); |
| 391 buffer.write( | 403 buffer.write( |
| 392 '<tr><th>Node kind</th><th>JS code @ offset</th>' | 404 '<tr><th>Node kind</th><th>JS code @ offset</th>' |
| 393 '<th>Dart code @ mapped location</th><th>file:position:name</th></tr>'); | 405 '<th>Dart code @ mapped location</th><th>file:position:name</th></tr>'); |
| 394 codePoints.forEach((CodePoint codePoint) { | 406 codePoints.forEach((CodePoint codePoint) { |
| 395 String jsCode = codePoint.jsCode; | 407 String jsCode = codePoint.jsCode; |
| 396 if (jsCode.length > 40) { | |
| 397 jsCode = jsCode.substring(0, 40); | |
| 398 } | |
| 399 if (codePoint.sourceLocation != null) { | 408 if (codePoint.sourceLocation != null) { |
| 400 int index = collection.getIndex(codePoint.sourceLocation); | 409 int index = collection.getIndex(codePoint.sourceLocation); |
| 401 if (index != null) { | 410 if (index != null) { |
| 402 | 411 String style = ''; |
| 403 buffer.write('<tr style="background:#${toColor(index)};" ' | 412 if (!codePoint.isMissing) { |
| 413 style = 'style="background:${toColorCss(index)};" '; |
| 414 } |
| 415 buffer.write('<tr $style' |
| 404 'name="trace$index" ' | 416 'name="trace$index" ' |
| 405 'onmouseover="highlight([${index}]);"' | 417 'onmouseover="highlight([${index}]);"' |
| 406 'onmouseout="highlight([]);">'); | 418 'onmouseout="highlight([]);">'); |
| 407 } else { | 419 } else { |
| 408 buffer.write('<tr>'); | 420 buffer.write('<tr>'); |
| 409 print('${codePoint.sourceLocation} not found in '); | 421 print('${codePoint.sourceLocation} not found in '); |
| 410 collection.sourceLocationIndexMap.keys | 422 collection.sourceLocationIndexMap.keys |
| 411 .where((l) => l.sourceUri == codePoint.sourceLocation.sourceUri) | 423 .where((l) => l.sourceUri == codePoint.sourceLocation.sourceUri) |
| 412 .forEach((l) => print(' $l')); | 424 .forEach((l) => print(' $l')); |
| 413 } | 425 } |
| 414 } else { | 426 } else { |
| 415 buffer.write('<tr>'); | 427 buffer.write('<tr>'); |
| 416 } | 428 } |
| 417 buffer.write('<td>${codePoint.kind}</td>'); | 429 buffer.write('<td>${codePoint.kind}</td>'); |
| 418 buffer.write('<td class="code">${jsCode}</td>'); | 430 buffer.write('<td class="code">${jsCode}</td>'); |
| 419 if (codePoint.sourceLocation == null) { | 431 if (codePoint.sourceLocation == null) { |
| 420 //buffer.write('<td></td>'); | 432 //buffer.write('<td></td>'); |
| 421 } else { | 433 } else { |
| 422 buffer.write('<td class="code">${codePoint.dartCode}</td>'); | 434 buffer.write('<td class="code">${codePoint.dartCode}</td>'); |
| 423 buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>'); | 435 buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>'); |
| 424 } | 436 } |
| 425 buffer.write('</tr>'); | 437 buffer.write('</tr>'); |
| 426 }); | 438 }); |
| 427 buffer.write('</table>'); | 439 buffer.write('</table>'); |
| 428 | 440 |
| 429 return buffer.toString(); | 441 return buffer.toString(); |
| 430 } | 442 } |
| OLD | NEW |