| 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 import 'dart:math' as Math; | 11 import 'dart:math' as Math; |
| 12 | 12 |
| 13 import 'package:compiler/src/io/source_file.dart'; | 13 import 'package:compiler/src/io/source_file.dart'; |
| 14 import 'package:compiler/src/io/source_information.dart'; | 14 import 'package:compiler/src/io/source_information.dart'; |
| 15 import 'package:compiler/src/js/js.dart' as js; | 15 import 'package:compiler/src/js/js.dart' as js; |
| 16 | 16 |
| 17 import 'colors.dart'; | 17 import 'colors.dart'; |
| 18 import 'sourcemap_helper.dart'; | 18 import 'sourcemap_helper.dart'; |
| 19 import 'sourcemap_html_templates.dart'; | 19 import 'sourcemap_html_templates.dart'; |
| 20 import 'html_parts.dart'; |
| 21 |
| 22 /// Truncate [input] to [length], adding '...' if truncated. |
| 23 String truncate(String input, int length) { |
| 24 if (input.length > length) { |
| 25 return '${input.substring(0, length - 3)}...'; |
| 26 } |
| 27 return input; |
| 28 } |
| 20 | 29 |
| 21 /// Returns the [index]th color for visualization. | 30 /// Returns the [index]th color for visualization. |
| 22 HSV toColor(int index) { | 31 HSV toColor(int index) { |
| 23 int hueCount = 24; | 32 int hueCount = 24; |
| 24 double h = 360.0 * (index % hueCount) / hueCount; | 33 double h = 360.0 * (index % hueCount) / hueCount; |
| 25 double v = 1.0; | 34 double v = 1.0; |
| 26 double s = 0.5; | 35 double s = 0.5; |
| 27 return new HSV(h, s, v); | 36 return new HSV(h, s, v); |
| 28 } | 37 } |
| 29 | 38 |
| 30 /// Return the CSS color value for the [index]th color. | 39 /// Return the CSS color value for the [index]th color. |
| 31 String toColorCss(int index) { | 40 String toColorCss(int index) { |
| 32 return toColor(index).toCss; | 41 return toColor(index).toCss; |
| 33 } | 42 } |
| 34 | 43 |
| 35 /// Return the CSS color value for the [index]th span. | 44 /// Return the CSS color value for the [index]th span. |
| 36 String toPattern(int index) { | 45 String toPattern(int index) { |
| 37 /// Use gradient on spans to visually identify consecutive spans mapped to the | 46 /// Use gradient on spans to visually identify consecutive spans mapped to the |
| 38 /// same source location. | 47 /// same source location. |
| 39 HSV startColor = toColor(index); | 48 HSV startColor = toColor(index); |
| 40 HSV endColor = new HSV(startColor.h, startColor.s + 0.4, startColor.v - 0.2); | 49 HSV endColor = new HSV(startColor.h, startColor.s + 0.4, startColor.v - 0.2); |
| 41 return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})'; | 50 return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})'; |
| 42 } | 51 } |
| 43 | 52 |
| 44 /// Return the html for the [index] line number. If [width] is provided, shorter | 53 /// Return the html for the [index] line number. If [width] is provided, shorter |
| 45 /// line numbers will be prefixed with spaces to match the width. | 54 /// line numbers will be prefixed with spaces to match the width. |
| 46 String lineNumber(int index, [int width]) { | 55 String lineNumber(int index, {int width, bool useNbsp: false}) { |
| 47 String text = '${index + 1}'; | 56 String text = '${index + 1}'; |
| 57 String padding = useNbsp ? ' ' : ' '; |
| 48 if (width != null && text.length < width) { | 58 if (width != null && text.length < width) { |
| 49 text = (' ' * (width - text.length)) + text; | 59 text = (padding * (width - text.length)) + text; |
| 50 } | 60 } |
| 51 return '<span class="lineNumber">$text </span>'; | 61 return '<span class="lineNumber">$text$padding</span>'; |
| 52 } | 62 } |
| 53 | 63 |
| 54 /// Return the html escaped [text]. | 64 /// Return the html escaped [text]. |
| 55 String escape(String text) { | 65 String escape(String text) { |
| 56 return const HtmlEscape().convert(text); | 66 return const HtmlEscape().convert(text); |
| 57 } | 67 } |
| 58 | 68 |
| 59 /// Information needed to generate HTML for a single [SourceMapInfo]. | 69 /// Information needed to generate HTML for a single [SourceMapInfo]. |
| 60 class SourceMapHtmlInfo { | 70 class SourceMapHtmlInfo { |
| 61 final SourceMapInfo sourceMapInfo; | 71 final SourceMapInfo sourceMapInfo; |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 StringBuffer htmlBuffer = new StringBuffer(); | 280 StringBuffer htmlBuffer = new StringBuffer(); |
| 271 List<CodeLine> lines = convertAnnotatedCodeToCodeLines( | 281 List<CodeLine> lines = convertAnnotatedCodeToCodeLines( |
| 272 code, annotations, | 282 code, annotations, |
| 273 colorScheme: colorScheme, | 283 colorScheme: colorScheme, |
| 274 elementScheme: elementScheme, | 284 elementScheme: elementScheme, |
| 275 windowSize: windowSize); | 285 windowSize: windowSize); |
| 276 int lineNoWidth; | 286 int lineNoWidth; |
| 277 if (lines.isNotEmpty) { | 287 if (lines.isNotEmpty) { |
| 278 lineNoWidth = '${lines.last.lineNo + 1}'.length; | 288 lineNoWidth = '${lines.last.lineNo + 1}'.length; |
| 279 } | 289 } |
| 290 HtmlPrintContext context = new HtmlPrintContext(lineNoWidth: lineNoWidth); |
| 280 for (CodeLine line in lines) { | 291 for (CodeLine line in lines) { |
| 281 line.printHtmlOn(htmlBuffer, lineNoWidth); | 292 line.printHtmlOn(htmlBuffer, context); |
| 282 } | 293 } |
| 283 return htmlBuffer.toString(); | 294 return htmlBuffer.toString(); |
| 284 } | 295 } |
| 285 | 296 |
| 286 List<CodeLine> convertAnnotatedCodeToCodeLines( | 297 List<CodeLine> convertAnnotatedCodeToCodeLines( |
| 287 String code, | 298 String code, |
| 288 Iterable<Annotation> annotations, | 299 Iterable<Annotation> annotations, |
| 289 {CssColorScheme colorScheme: const SingleColorScheme(), | 300 {CssColorScheme colorScheme: const SingleColorScheme(), |
| 290 ElementScheme elementScheme: const ElementScheme(), | 301 ElementScheme elementScheme: const ElementScheme(), |
| 291 int windowSize}) { | 302 int windowSize}) { |
| 292 | 303 |
| 293 List<CodeLine> lines = <CodeLine>[]; | 304 List<CodeLine> lines = <CodeLine>[]; |
| 294 CodeLine currentLine; | 305 CodeLine currentLine; |
| 295 int offset = 0; | 306 int offset = 0; |
| 296 int lineIndex = 0; | 307 int lineIndex = 0; |
| 297 int firstLine; | 308 int firstLine; |
| 298 int lastLine; | 309 int lastLine; |
| 299 bool pendingSourceLocationsEnd = false; | 310 bool pendingSourceLocationsEnd = false; |
| 300 | 311 |
| 301 void write(String code, String html) { | 312 void write(String code, HtmlPart html) { |
| 302 if (currentLine != null) { | 313 if (currentLine != null) { |
| 303 currentLine.codeBuffer.write(code); | 314 currentLine.codeBuffer.write(code); |
| 304 currentLine.htmlParts.add(html); | 315 currentLine.htmlParts.add(html); |
| 305 } | 316 } |
| 306 } | 317 } |
| 307 | 318 |
| 308 void startLine() { | 319 void startLine(int currentOffset) { |
| 309 lines.add(currentLine = new CodeLine(lines.length)); | 320 lines.add(currentLine = new CodeLine(lines.length, currentOffset)); |
| 310 } | 321 } |
| 311 | 322 |
| 312 void endCurrentLocation() { | 323 void endCurrentLocation() { |
| 313 if (pendingSourceLocationsEnd) { | 324 if (pendingSourceLocationsEnd) { |
| 314 write('', '</a>'); | 325 write('', const ConstHtmlPart('</a>')); |
| 315 } | 326 } |
| 316 pendingSourceLocationsEnd = false; | 327 pendingSourceLocationsEnd = false; |
| 317 } | 328 } |
| 318 | 329 |
| 319 void addSubstring(int until, {bool isFirst: false, bool isLast: false}) { | 330 void addSubstring(int until, {bool isFirst: false, bool isLast: false}) { |
| 320 if (until <= offset) return; | 331 if (until <= offset) return; |
| 321 if (offset >= code.length) return; | 332 if (offset >= code.length) return; |
| 322 | 333 |
| 323 String substring = code.substring(offset, until); | 334 String substring = code.substring(offset, until); |
| 324 offset = until; | |
| 325 bool first = true; | 335 bool first = true; |
| 326 | 336 |
| 327 if (isLast) { | 337 if (isLast) { |
| 328 lastLine = lineIndex; | 338 lastLine = lineIndex; |
| 329 } | 339 } |
| 340 int localOffset = 0; |
| 330 if (isFirst) { | 341 if (isFirst) { |
| 331 startLine(); | 342 startLine(offset + localOffset); |
| 332 } | 343 } |
| 333 for (String line in substring.split('\n')) { | 344 for (String line in substring.split('\n')) { |
| 334 if (!first) { | 345 if (!first) { |
| 335 endCurrentLocation(); | 346 endCurrentLocation(); |
| 336 write('', '\n'); | 347 write('', const NewLine()); |
| 337 lineIndex++; | 348 lineIndex++; |
| 338 startLine(); | 349 startLine(offset + localOffset); |
| 339 } | 350 } |
| 340 if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) { | 351 if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) { |
| 341 if (line.isNotEmpty) { | 352 if (line.isNotEmpty) { |
| 342 String before = line.substring(0, 1); | 353 String before = line.substring(0, 1); |
| 343 write(before, escape(before)); | 354 write(before, new HtmlText(before)); |
| 344 endCurrentLocation(); | 355 endCurrentLocation(); |
| 345 String after = line.substring(1); | 356 String after = line.substring(1); |
| 346 write(after, escape(after)); | 357 write(after, new HtmlText(after)); |
| 347 } | 358 } |
| 348 } else { | 359 } else { |
| 349 write(line, escape(line)); | 360 write(line, new HtmlText(line)); |
| 350 } | 361 } |
| 351 first = false; | 362 first = false; |
| 363 localOffset += line.length + 1; |
| 352 } | 364 } |
| 353 if (isFirst) { | 365 if (isFirst) { |
| 354 firstLine = lineIndex; | 366 firstLine = lineIndex; |
| 355 } | 367 } |
| 368 offset = until; |
| 356 } | 369 } |
| 357 | 370 |
| 358 void insertAnnotations(List<Annotation> annotations) { | 371 void insertAnnotations(List<Annotation> annotations) { |
| 359 endCurrentLocation(); | 372 endCurrentLocation(); |
| 360 | 373 |
| 361 String color; | 374 String color; |
| 362 var id; | 375 var id; |
| 363 String title; | 376 String title; |
| 364 if (annotations.length == 1) { | 377 if (annotations.length == 1) { |
| 365 Annotation annotation = annotations.single; | 378 Annotation annotation = annotations.single; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 377 color = colorScheme.multiLocationToCssColor(ids); | 390 color = colorScheme.multiLocationToCssColor(ids); |
| 378 title = annotations.map((l) => l.title).join(','); | 391 title = annotations.map((l) => l.title).join(','); |
| 379 } | 392 } |
| 380 if (id != null) { | 393 if (id != null) { |
| 381 Set ids = annotations.map((l) => l.id).toSet(); | 394 Set ids = annotations.map((l) => l.id).toSet(); |
| 382 String name = elementScheme.getName(id, ids); | 395 String name = elementScheme.getName(id, ids); |
| 383 String href = elementScheme.getHref(id, ids); | 396 String href = elementScheme.getHref(id, ids); |
| 384 String onclick = elementScheme.onClick(id, ids); | 397 String onclick = elementScheme.onClick(id, ids); |
| 385 String onmouseover = elementScheme.onMouseOver(id, ids); | 398 String onmouseover = elementScheme.onMouseOver(id, ids); |
| 386 String onmouseout = elementScheme.onMouseOut(id, ids); | 399 String onmouseout = elementScheme.onMouseOut(id, ids); |
| 387 write('', '<a'); | 400 write('', new AnchorHtmlPart( |
| 388 if (href != null) { | 401 color: color, |
| 389 write('', ' href="${href}"'); | 402 name: name, |
| 390 } | 403 href: href, |
| 391 if (name != null) { | 404 title: title, |
| 392 write('', ' name="${name}"'); | 405 onclick: onclick, |
| 393 } | 406 onmouseover: onmouseover, |
| 394 if (title != null) { | 407 onmouseout: onmouseout)); |
| 395 write('', ' title="${escape(title)}"'); | |
| 396 } | |
| 397 write('', ' style="${color}"'); | |
| 398 if (onclick != null) { | |
| 399 write('', ' onclick="${onclick}"'); | |
| 400 } | |
| 401 if (onmouseover != null) { | |
| 402 write('', ' onmouseover="${onmouseover}"'); | |
| 403 } | |
| 404 if (onmouseout != null) { | |
| 405 write('', ' onmouseout="${onmouseout}"'); | |
| 406 } | |
| 407 write('', '>'); | |
| 408 pendingSourceLocationsEnd = true; | 408 pendingSourceLocationsEnd = true; |
| 409 } | 409 } |
| 410 currentLine.annotations.addAll(annotations); |
| 410 if (annotations.last == null) { | 411 if (annotations.last == null) { |
| 411 endCurrentLocation(); | 412 endCurrentLocation(); |
| 412 } | 413 } |
| 413 } | 414 } |
| 414 | 415 |
| 415 Map<int, List<Annotation>> annotationMap = <int, List<Annotation>>{}; | 416 Map<int, List<Annotation>> annotationMap = <int, List<Annotation>>{}; |
| 416 for (Annotation annotation in annotations) { | 417 for (Annotation annotation in annotations) { |
| 417 annotationMap.putIfAbsent(annotation.codeOffset, () => <Annotation>[]) | 418 annotationMap.putIfAbsent(annotation.codeOffset, () => <Annotation>[]) |
| 418 .add(annotation); | 419 .add(annotation); |
| 419 } | 420 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 431 | 432 |
| 432 int start = 0; | 433 int start = 0; |
| 433 int end = lines.length - 1; | 434 int end = lines.length - 1; |
| 434 if (windowSize != null) { | 435 if (windowSize != null) { |
| 435 start = Math.max(firstLine - windowSize, start); | 436 start = Math.max(firstLine - windowSize, start); |
| 436 end = Math.min(lastLine + windowSize, end); | 437 end = Math.min(lastLine + windowSize, end); |
| 437 } | 438 } |
| 438 return lines.sublist(start, end); | 439 return lines.sublist(start, end); |
| 439 } | 440 } |
| 440 | 441 |
| 441 class CodeLine { | |
| 442 final int lineNo; | |
| 443 final StringBuffer codeBuffer = new StringBuffer(); | |
| 444 final List<String> htmlParts = <String>[]; | |
| 445 String _code; | |
| 446 | |
| 447 CodeLine(this.lineNo); | |
| 448 | |
| 449 String get code { | |
| 450 if (_code == null) { | |
| 451 _code = codeBuffer.toString(); | |
| 452 } | |
| 453 return _code; | |
| 454 } | |
| 455 | |
| 456 void printHtmlOn(StringBuffer htmlBuffer, [int lineNoWidth]) { | |
| 457 htmlBuffer.write(lineNumber(lineNo, lineNoWidth)); | |
| 458 for (String part in htmlParts) { | |
| 459 htmlBuffer.write(part); | |
| 460 } | |
| 461 } | |
| 462 } | |
| 463 | |
| 464 | |
| 465 /// Computes the HTML representation for a collection of JavaScript code blocks. | 442 /// Computes the HTML representation for a collection of JavaScript code blocks. |
| 466 String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) { | 443 String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) { |
| 467 | 444 |
| 468 StringBuffer jsCodeBuffer = new StringBuffer(); | 445 StringBuffer jsCodeBuffer = new StringBuffer(); |
| 469 for (SourceMapHtmlInfo info in infoList) { | 446 for (SourceMapHtmlInfo info in infoList) { |
| 470 String name = info.sourceMapInfo.name; | 447 String name = info.sourceMapInfo.name; |
| 471 String html = info.codeProcessor.convertToHtml(info.sourceMapInfo.code); | 448 String html = info.codeProcessor.convertToHtml(info.sourceMapInfo.code); |
| 472 String onclick = 'show(\'$name\');'; | 449 String onclick = 'show(\'$name\');'; |
| 473 jsCodeBuffer.write( | 450 jsCodeBuffer.write( |
| 474 '<h3 onclick="$onclick">JS code for: ${escape(name)}</h3>\n'); | 451 '<h3 onclick="$onclick">JS code for: ${escape(name)}</h3>\n'); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 501 | 478 |
| 502 /// Computes the HTML information for the [info]. | 479 /// Computes the HTML information for the [info]. |
| 503 SourceMapHtmlInfo createHtmlInfo(SourceLocationCollection collection, | 480 SourceMapHtmlInfo createHtmlInfo(SourceLocationCollection collection, |
| 504 SourceMapInfo info) { | 481 SourceMapInfo info) { |
| 505 js.Node node = info.node; | 482 js.Node node = info.node; |
| 506 String code = info.code; | 483 String code = info.code; |
| 507 String name = info.name; | 484 String name = info.name; |
| 508 SourceLocationCollection subcollection = | 485 SourceLocationCollection subcollection = |
| 509 new SourceLocationCollection(collection); | 486 new SourceLocationCollection(collection); |
| 510 CodeProcessor codeProcessor = new CodeProcessor(name, subcollection); | 487 CodeProcessor codeProcessor = new CodeProcessor(name, subcollection); |
| 511 //print('${info.element}:${info.nodeMap.nodes.length}'); | |
| 512 for (js.Node node in info.nodeMap.nodes) { | 488 for (js.Node node in info.nodeMap.nodes) { |
| 513 info.nodeMap[node].forEach( | 489 info.nodeMap[node].forEach( |
| 514 (int targetOffset, List<SourceLocation> sourceLocations) { | 490 (int targetOffset, List<SourceLocation> sourceLocations) { |
| 515 for (SourceLocation sourceLocation in sourceLocations) { | 491 for (SourceLocation sourceLocation in sourceLocations) { |
| 516 codeProcessor.addSourceLocation(targetOffset, sourceLocation); | 492 codeProcessor.addSourceLocation(targetOffset, sourceLocation); |
| 517 } | 493 } |
| 518 }); | 494 }); |
| 519 } | 495 } |
| 520 return new SourceMapHtmlInfo(info, codeProcessor, subcollection); | 496 return new SourceMapHtmlInfo(info, codeProcessor, subcollection); |
| 521 } | 497 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 Map<Uri, Map<int, List<SourceLocation>>> sourceLocationMap = {}; | 542 Map<Uri, Map<int, List<SourceLocation>>> sourceLocationMap = {}; |
| 567 collection.sourceLocations.forEach((SourceLocation sourceLocation) { | 543 collection.sourceLocations.forEach((SourceLocation sourceLocation) { |
| 568 Map<int, List<SourceLocation>> uriMap = | 544 Map<int, List<SourceLocation>> uriMap = |
| 569 sourceLocationMap.putIfAbsent(sourceLocation.sourceUri, () => {}); | 545 sourceLocationMap.putIfAbsent(sourceLocation.sourceUri, () => {}); |
| 570 List<SourceLocation> lineList = | 546 List<SourceLocation> lineList = |
| 571 uriMap.putIfAbsent(sourceLocation.line, () => []); | 547 uriMap.putIfAbsent(sourceLocation.line, () => []); |
| 572 lineList.add(sourceLocation); | 548 lineList.add(sourceLocation); |
| 573 }); | 549 }); |
| 574 sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) { | 550 sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) { |
| 575 SourceFile sourceFile = sourceFileManager.getSourceFile(uri); | 551 SourceFile sourceFile = sourceFileManager.getSourceFile(uri); |
| 552 if (sourceFile == null) return; |
| 576 StringBuffer codeBuffer = new StringBuffer(); | 553 StringBuffer codeBuffer = new StringBuffer(); |
| 577 | 554 |
| 578 int firstLineIndex; | 555 int firstLineIndex; |
| 579 int lastLineIndex; | 556 int lastLineIndex; |
| 580 List<int> lineIndices = uriMap.keys.toList()..sort(); | 557 List<int> lineIndices = uriMap.keys.toList()..sort(); |
| 581 int lineNoWidth; | 558 int lineNoWidth; |
| 582 if (lineIndices.isNotEmpty) { | 559 if (lineIndices.isNotEmpty) { |
| 583 lineNoWidth = '${lineIndices.last + windowSize + 1}'.length; | 560 lineNoWidth = '${lineIndices.last + windowSize + 1}'.length; |
| 584 } | 561 } |
| 585 | 562 |
| 586 void flush() { | 563 void flush() { |
| 587 if (firstLineIndex != null && lastLineIndex != null) { | 564 if (firstLineIndex != null && lastLineIndex != null) { |
| 588 dartCodeBuffer.write( | 565 dartCodeBuffer.write( |
| 589 '<h4>${uri.pathSegments.last}, ' | 566 '<h4>${uri.pathSegments.last}, ' |
| 590 '${firstLineIndex - windowSize + 1}-' | 567 '${firstLineIndex - windowSize + 1}-' |
| 591 '${lastLineIndex + windowSize + 1}' | 568 '${lastLineIndex + windowSize + 1}' |
| 592 '</h4>\n'); | 569 '</h4>\n'); |
| 593 dartCodeBuffer.write('<pre>\n'); | 570 dartCodeBuffer.write('<pre>\n'); |
| 594 for (int line = firstLineIndex - windowSize; | 571 for (int line = firstLineIndex - windowSize; |
| 595 line < firstLineIndex; | 572 line < firstLineIndex; |
| 596 line++) { | 573 line++) { |
| 597 if (line >= 0) { | 574 if (line >= 0) { |
| 598 dartCodeBuffer.write(lineNumber(line, lineNoWidth)); | 575 dartCodeBuffer.write(lineNumber(line, width: lineNoWidth)); |
| 599 dartCodeBuffer.write(sourceFile.getLineText(line)); | 576 dartCodeBuffer.write(sourceFile.getLineText(line)); |
| 600 } | 577 } |
| 601 } | 578 } |
| 602 dartCodeBuffer.write(codeBuffer); | 579 dartCodeBuffer.write(codeBuffer); |
| 603 for (int line = lastLineIndex + 1; | 580 for (int line = lastLineIndex + 1; |
| 604 line <= lastLineIndex + windowSize; | 581 line <= lastLineIndex + windowSize; |
| 605 line++) { | 582 line++) { |
| 606 if (line < sourceFile.lines) { | 583 if (line < sourceFile.lines) { |
| 607 dartCodeBuffer.write(lineNumber(line, lineNoWidth)); | 584 dartCodeBuffer.write(lineNumber(line, width: lineNoWidth)); |
| 608 dartCodeBuffer.write(sourceFile.getLineText(line)); | 585 dartCodeBuffer.write(sourceFile.getLineText(line)); |
| 609 } | 586 } |
| 610 } | 587 } |
| 611 dartCodeBuffer.write('</pre>\n'); | 588 dartCodeBuffer.write('</pre>\n'); |
| 612 firstLineIndex = null; | 589 firstLineIndex = null; |
| 613 lastLineIndex = null; | 590 lastLineIndex = null; |
| 614 } | 591 } |
| 615 codeBuffer.clear(); | 592 codeBuffer.clear(); |
| 616 } | 593 } |
| 617 | 594 |
| 618 lineIndices.forEach((int lineIndex) { | 595 lineIndices.forEach((int lineIndex) { |
| 619 List<SourceLocation> locations = uriMap[lineIndex]; | 596 List<SourceLocation> locations = uriMap[lineIndex]; |
| 620 if (lastLineIndex != null && | 597 if (lastLineIndex != null && |
| 621 lastLineIndex + windowSize * 4 < lineIndex) { | 598 lastLineIndex + windowSize * 4 < lineIndex) { |
| 622 flush(); | 599 flush(); |
| 623 } | 600 } |
| 624 if (firstLineIndex == null) { | 601 if (firstLineIndex == null) { |
| 625 firstLineIndex = lineIndex; | 602 firstLineIndex = lineIndex; |
| 626 } else { | 603 } else { |
| 627 for (int line = lastLineIndex + 1; line < lineIndex; line++) { | 604 for (int line = lastLineIndex + 1; line < lineIndex; line++) { |
| 628 codeBuffer.write(lineNumber(line, lineNoWidth)); | 605 codeBuffer.write(lineNumber(line, width: lineNoWidth)); |
| 629 codeBuffer.write(sourceFile.getLineText(line)); | 606 codeBuffer.write(sourceFile.getLineText(line)); |
| 630 } | 607 } |
| 631 } | 608 } |
| 632 String line = sourceFile.getLineText(lineIndex); | 609 String line = sourceFile.getLineText(lineIndex); |
| 633 locations.sort((a, b) => a.offset.compareTo(b.offset)); | 610 locations.sort((a, b) => a.offset.compareTo(b.offset)); |
| 634 for (int i = 0; i < locations.length; i++) { | 611 for (int i = 0; i < locations.length; i++) { |
| 635 SourceLocation sourceLocation = locations[i]; | 612 SourceLocation sourceLocation = locations[i]; |
| 636 int index = collection.getIndex(sourceLocation); | 613 int index = collection.getIndex(sourceLocation); |
| 637 int start = sourceLocation.column; | 614 int start = sourceLocation.column; |
| 638 int end = line.length; | 615 int end = line.length; |
| 639 if (i + 1 < locations.length) { | 616 if (i + 1 < locations.length) { |
| 640 end = locations[i + 1].column; | 617 end = locations[i + 1].column; |
| 641 } | 618 } |
| 642 if (i == 0) { | 619 if (i == 0) { |
| 643 codeBuffer.write(lineNumber(lineIndex, lineNoWidth)); | 620 codeBuffer.write(lineNumber(lineIndex, width: lineNoWidth)); |
| 644 codeBuffer.write(line.substring(0, start)); | 621 codeBuffer.write(line.substring(0, start)); |
| 645 } | 622 } |
| 646 codeBuffer.write( | 623 codeBuffer.write( |
| 647 '<a name="${index}" style="background:${toPattern(index)};" ' | 624 '<a name="${index}" style="background:${toPattern(index)};" ' |
| 648 'title="[${lineIndex + 1},${start + 1}]" ' | 625 'title="[${lineIndex + 1},${start + 1}]" ' |
| 649 'onmouseover="highlight(\'$index\');" ' | 626 'onmouseover="highlight(\'$index\');" ' |
| 650 'onmouseout="highlight();">'); | 627 'onmouseout="highlight();">'); |
| 651 codeBuffer.write(line.substring(start, end)); | 628 codeBuffer.write(line.substring(start, end)); |
| 652 codeBuffer.write('</a>'); | 629 codeBuffer.write('</a>'); |
| 653 } | 630 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 666 | 643 |
| 667 /// Computes a HTML visualization of the [codePoints]. | 644 /// Computes a HTML visualization of the [codePoints]. |
| 668 String computeJsTraceHtmlPart(List<CodePoint> codePoints, | 645 String computeJsTraceHtmlPart(List<CodePoint> codePoints, |
| 669 SourceLocationCollection collection) { | 646 SourceLocationCollection collection) { |
| 670 StringBuffer buffer = new StringBuffer(); | 647 StringBuffer buffer = new StringBuffer(); |
| 671 buffer.write('<table style="width:100%;">'); | 648 buffer.write('<table style="width:100%;">'); |
| 672 buffer.write( | 649 buffer.write( |
| 673 '<tr><th>Node kind</th><th>JS code @ offset</th>' | 650 '<tr><th>Node kind</th><th>JS code @ offset</th>' |
| 674 '<th>Dart code @ mapped location</th><th>file:position:name</th></tr>'); | 651 '<th>Dart code @ mapped location</th><th>file:position:name</th></tr>'); |
| 675 codePoints.forEach((CodePoint codePoint) { | 652 codePoints.forEach((CodePoint codePoint) { |
| 676 String jsCode = codePoint.jsCode; | 653 String jsCode = truncate(codePoint.jsCode, 50); |
| 677 if (codePoint.sourceLocation != null) { | 654 if (codePoint.sourceLocation != null) { |
| 678 int index = collection.getIndex(codePoint.sourceLocation); | 655 int index = collection.getIndex(codePoint.sourceLocation); |
| 679 if (index != null) { | 656 if (index != null) { |
| 680 String style = ''; | 657 String style = ''; |
| 681 if (!codePoint.isMissing) { | 658 if (!codePoint.isMissing) { |
| 682 style = 'style="background:${toColorCss(index)};" '; | 659 style = 'style="background:${toColorCss(index)};" '; |
| 683 } | 660 } |
| 684 buffer.write('<tr $style' | 661 buffer.write('<tr $style' |
| 685 'name="trace$index" ' | 662 'name="trace$index" ' |
| 686 'onmouseover="highlight([${index}]);"' | 663 'onmouseover="highlight([${index}]);"' |
| 687 'onmouseout="highlight([]);">'); | 664 'onmouseout="highlight([]);">'); |
| 688 } else { | 665 } else { |
| 689 buffer.write('<tr>'); | 666 buffer.write('<tr>'); |
| 690 print('${codePoint.sourceLocation} not found in '); | 667 print('${codePoint.sourceLocation} not found in '); |
| 691 collection.sourceLocationIndexMap.keys | 668 collection.sourceLocationIndexMap.keys |
| 692 .where((l) => l.sourceUri == codePoint.sourceLocation.sourceUri) | 669 .where((l) => l.sourceUri == codePoint.sourceLocation.sourceUri) |
| 693 .forEach((l) => print(' $l')); | 670 .forEach((l) => print(' $l')); |
| 694 } | 671 } |
| 695 } else { | 672 } else { |
| 696 buffer.write('<tr>'); | 673 buffer.write('<tr>'); |
| 697 } | 674 } |
| 698 buffer.write('<td>${codePoint.kind}</td>'); | 675 buffer.write('<td>${codePoint.kind}</td>'); |
| 699 buffer.write('<td class="code">${jsCode}</td>'); | 676 buffer.write('<td class="code">${jsCode}</td>'); |
| 700 if (codePoint.sourceLocation == null) { | 677 if (codePoint.sourceLocation == null) { |
| 701 //buffer.write('<td></td>'); | 678 //buffer.write('<td></td>'); |
| 702 } else { | 679 } else { |
| 703 buffer.write('<td class="code">${codePoint.dartCode}</td>'); | 680 String dartCode = truncate(codePoint.dartCode, 50); |
| 681 buffer.write('<td class="code">${dartCode}</td>'); |
| 704 buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>'); | 682 buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>'); |
| 705 } | 683 } |
| 706 buffer.write('</tr>'); | 684 buffer.write('</tr>'); |
| 707 }); | 685 }); |
| 708 buffer.write('</table>'); | 686 buffer.write('</table>'); |
| 709 | 687 |
| 710 return buffer.toString(); | 688 return buffer.toString(); |
| 711 } | 689 } |
| OLD | NEW |