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 |