Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Unified Diff: tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart

Issue 1617083002: Base JavaScript code position computation on JavaScript tracer. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
index 4227fee724ff4bf7c43a26b202ea79efe0d20070..52e871d7779b8b36daea279e1b41b96b87b2bb69 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -8,6 +8,7 @@
library sourcemap.html.helper;
import 'dart:convert';
+import 'dart:math' as Math;
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/io/source_information.dart';
@@ -40,9 +41,14 @@ String toPattern(int index) {
return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})';
}
-/// Return the html for the [index] line number.
-String lineNumber(int index) {
- return '<span class="lineNumber">${index + 1} </span>';
+/// Return the html for the [index] line number. If [width] is provided, shorter
+/// line numbers will be prefixed with spaces to match the width.
+String lineNumber(int index, [int width]) {
+ String text = '${index + 1}';
+ if (width != null && text.length < width) {
+ text = (' ' * (width - text.length)) + text;
+ }
+ return '<span class="lineNumber">$text </span>';
}
/// Return the html escaped [text].
@@ -59,6 +65,10 @@ class SourceMapHtmlInfo {
SourceMapHtmlInfo(this.sourceMapInfo,
this.codeProcessor,
this.sourceLocationCollection);
+
+ String toString() {
+ return sourceMapInfo.toString();
+ }
}
/// A collection of source locations.
@@ -84,16 +94,98 @@ class SourceLocationCollection {
}
}
+abstract class CssColorScheme {
+ String singleLocationToCssColor(var id);
+
+ String multiLocationToCssColor(List ids);
+
+ bool get showLocationAsSpan;
+}
+
+class CustomColorScheme implements CssColorScheme {
+ final bool showLocationAsSpan;
+ final Function single;
+ final Function multi;
+
+ CustomColorScheme(
+ {this.showLocationAsSpan: false,
+ String this.single(var id),
+ String this.multi(List ids)});
+
+ String singleLocationToCssColor(var id) => single != null ? single(id) : null;
+
+ String multiLocationToCssColor(List ids) => multi != null ? multi(ids) : null;
+}
+
+class PatternCssColorScheme implements CssColorScheme {
+ const PatternCssColorScheme();
+
+ bool get showLocationAsSpan => true;
+
+ String singleLocationToCssColor(int index) {
+ return "background:${toPattern(index)};";
+ }
+
+ String multiLocationToCssColor(List<int> indices) {
+
+ StringBuffer sb = new StringBuffer();
+ double delta = 100.0 / (indices.length);
+ double position = 0.0;
+
+ void addColor(String color) {
+ sb.write(', ${color} ${position.toInt()}%');
+ position += delta;
+ sb.write(', ${color} ${position.toInt()}%');
+ }
+
+ for (int index in indices) {
+ addColor('${toColorCss(index)}');
+ }
+ return 'background: linear-gradient(to right${sb}); '
+ 'background-size: 10px 10px;';
+ }
+}
+
+class SingleColorScheme implements CssColorScheme {
+ const SingleColorScheme();
+
+ bool get showLocationAsSpan => false;
+
+ String singleLocationToCssColor(int index) {
+ return "background:${toColorCss(index)};";
+ }
+
+ String multiLocationToCssColor(List<int> indices) {
+ StringBuffer sb = new StringBuffer();
+ double delta = 100.0 / (indices.length);
+ double position = 0.0;
+
+ void addColor(String color) {
+ sb.write(', ${color} ${position.toInt()}%');
+ position += delta;
+ sb.write(', ${color} ${position.toInt()}%');
+ }
+
+ for (int index in indices) {
+ addColor('${toColorCss(index)}');
+ }
+ return 'background: linear-gradient(to bottom${sb}); '
+ 'background-size: 10px 3px;';
+ }
+}
+
/// Processor that computes the HTML representation of a block of JavaScript
/// code and collects the source locations mapped in the code.
class CodeProcessor {
int lineIndex = 0;
- final String onclick;
+ final String name;
int currentJsSourceOffset = 0;
final SourceLocationCollection collection;
final Map<int, List<SourceLocation>> codeLocations = {};
+ final CssColorScheme colorScheme;
- CodeProcessor(this.onclick, this.collection);
+ CodeProcessor(this.name, this.collection,
+ {this.colorScheme: const PatternCssColorScheme()});
void addSourceLocation(int targetOffset, SourceLocation sourceLocation) {
codeLocations.putIfAbsent(targetOffset, () => []).add(sourceLocation);
@@ -101,102 +193,275 @@ class CodeProcessor {
}
String convertToHtml(String text) {
- StringBuffer htmlBuffer = new StringBuffer();
- int offset = 0;
- int lineIndex = 0;
- bool pendingSourceLocationsEnd = false;
- htmlBuffer.write(lineNumber(lineIndex));
- SourceLocation currentLocation;
-
- void endCurrentLocation() {
- if (currentLocation != null) {
- htmlBuffer.write('</a>');
+ List<Annotation> annotations = <Annotation>[];
+ codeLocations.forEach((int codeOffset, List<SourceLocation> locations) {
+ for (SourceLocation location in locations) {
+ if (location != null) {
+ annotations.add(new Annotation(
+ collection.getIndex(location),
+ codeOffset,
+ location.shortText));
+ }
}
- currentLocation = null;
+ });
+ return convertAnnotatedCodeToHtml(
+ text, annotations, colorScheme: colorScheme,
+ elementScheme: new HighlightLinkScheme(name),
+ windowSize: 3);
+ }
+}
+
+class Annotation {
+ final id;
+ final int codeOffset;
+ final String title;
+
+ Annotation(this.id, this.codeOffset, this.title);
+}
+
+class ElementScheme {
+ const ElementScheme();
+
+ String getName(var id, Set ids) => null;
+ String getHref(var id, Set ids) => null;
+ String onClick(var id, Set ids) => null;
+ String onMouseOver(var id, Set ids) => null;
+ String onMouseOut(var id, Set ids) => null;
+}
+
+class HighlightLinkScheme implements ElementScheme {
+ final String name;
+
+ HighlightLinkScheme(this.name);
+
+ @override
+ String getName(int id, Set<int> indices) {
+ return 'js$id';
+ }
+
+ @override
+ String getHref(int id, Set<int> indices) {
+ return "#${id}";
+ }
+
+ @override
+ String onClick(int id, Set<int> indices) {
+ return "show(\'$name\');";
+ }
+
+ @override
+ String onMouseOut(int id, Set<int> indices) {
+ String onmouseover = indices.map((i) => '\'$i\'').join(',');
+ return "highlight([${onmouseover}]);";
+ }
+
+ @override
+ String onMouseOver(int id, Set<int> indices) {
+ return "highlight([]);";
+ }
+}
+
+String convertAnnotatedCodeToHtml(
+ String code,
+ Iterable<Annotation> annotations,
+ {CssColorScheme colorScheme: const SingleColorScheme(),
+ ElementScheme elementScheme: const ElementScheme(),
+ int windowSize}) {
+ StringBuffer htmlBuffer = new StringBuffer();
+ List<CodeLine> lines = convertAnnotatedCodeToCodeLines(
+ code, annotations,
+ colorScheme: colorScheme,
+ elementScheme: elementScheme,
+ windowSize: windowSize);
+ int lineNoWidth;
+ if (lines.isNotEmpty) {
+ lineNoWidth = '${lines.last.lineNo + 1}'.length;
+ }
+ for (CodeLine line in lines) {
+ line.printHtmlOn(htmlBuffer, lineNoWidth);
+ }
+ return htmlBuffer.toString();
+}
+
+List<CodeLine> convertAnnotatedCodeToCodeLines(
+ String code,
+ Iterable<Annotation> annotations,
+ {CssColorScheme colorScheme: const SingleColorScheme(),
+ ElementScheme elementScheme: const ElementScheme(),
+ int windowSize}) {
+
+ List<CodeLine> lines = <CodeLine>[];
+ CodeLine currentLine;
+ int offset = 0;
+ int lineIndex = 0;
+ int firstLine;
+ int lastLine;
+ bool pendingSourceLocationsEnd = false;
+
+ void write(String code, String html) {
+ if (currentLine != null) {
+ currentLine.codeBuffer.write(code);
+ currentLine.htmlParts.add(html);
}
+ }
- void addSubstring(int until) {
- if (until <= offset) return;
+ void startLine() {
+ lines.add(currentLine = new CodeLine(lines.length));
+ }
- String substring = text.substring(offset, until);
- offset = until;
- bool first = true;
- for (String line in substring.split('\n')) {
- if (!first) {
- endCurrentLocation();
- htmlBuffer.write('\n');
- lineIndex++;
- htmlBuffer.write(lineNumber(lineIndex));
- }
- htmlBuffer.write(escape(line));
- first = false;
- }
+ void endCurrentLocation() {
+ if (pendingSourceLocationsEnd) {
+ write('', '</a>');
}
+ pendingSourceLocationsEnd = false;
+ }
- void insertSourceLocations(List<SourceLocation> lastSourceLocations) {
- endCurrentLocation();
+ void addSubstring(int until, {bool isFirst: false, bool isLast: false}) {
+ if (until <= offset) return;
+ if (offset >= code.length) return;
+
+ String substring = code.substring(offset, until);
+ offset = until;
+ bool first = true;
- String color;
- int index;
- String title;
- if (lastSourceLocations.length == 1) {
- SourceLocation sourceLocation = lastSourceLocations.single;
- if (sourceLocation != null) {
- index = collection.getIndex(sourceLocation);
- color = "background:${toPattern(index)};";
- title = sourceLocation.shortText;
- currentLocation = sourceLocation;
+ if (isLast) {
+ lastLine = lineIndex;
+ }
+ if (isFirst) {
+ startLine();
+ }
+ for (String line in substring.split('\n')) {
+ if (!first) {
+ endCurrentLocation();
+ write('', '\n');
+ lineIndex++;
+ startLine();
+ }
+ if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) {
+ if (line.isNotEmpty) {
+ String before = line.substring(0, 1);
+ write(before, escape(before));
+ endCurrentLocation();
+ String after = line.substring(1);
+ write(after, escape(after));
}
} else {
+ write(line, escape(line));
+ }
+ first = false;
+ }
+ if (isFirst) {
+ firstLine = lineIndex;
+ }
+ }
- index = collection.getIndex(lastSourceLocations.first);
- StringBuffer sb = new StringBuffer();
- double delta = 100.0 / (lastSourceLocations.length);
- double position = 0.0;
-
- void addColor(String color) {
- sb.write(', ${color} ${position.toInt()}%');
- position += delta;
- sb.write(', ${color} ${position.toInt()}%');
- }
+ void insertAnnotations(List<Annotation> annotations) {
+ endCurrentLocation();
- for (SourceLocation sourceLocation in lastSourceLocations) {
- if (sourceLocation == null) continue;
- int colorIndex = collection.getIndex(sourceLocation);
- addColor('${toColorCss(colorIndex)}');
- currentLocation = sourceLocation;
- }
- color = 'background: linear-gradient(to right${sb}); '
- 'background-size: 10px 10px;';
- title = lastSourceLocations.map((l) => l.shortText).join(',');
+ String color;
+ var id;
+ String title;
+ if (annotations.length == 1) {
+ Annotation annotation = annotations.single;
+ if (annotation != null) {
+ id = annotation.id;
+ color = colorScheme.singleLocationToCssColor(id);
+ title = annotation.title;
}
- if (index != null) {
- Set<int> indices =
- lastSourceLocations.map((l) => collection.getIndex(l)).toSet();
- String onmouseover = indices.map((i) => '\'$i\'').join(',');
- htmlBuffer.write(
- '<a name="js$index" href="#${index}" style="$color" title="$title" '
- 'onclick="${onclick}" onmouseover="highlight([${onmouseover}]);"'
- 'onmouseout="highlight([]);">');
- pendingSourceLocationsEnd = true;
+ } else {
+ id = annotations.first.id;
+ List ids = [];
+ for (Annotation annotation in annotations) {
+ ids.add(annotation.id);
}
- if (lastSourceLocations.last == null) {
- endCurrentLocation();
+ color = colorScheme.multiLocationToCssColor(ids);
+ title = annotations.map((l) => l.title).join(',');
+ }
+ if (id != null) {
+ Set ids = annotations.map((l) => l.id).toSet();
+ String name = elementScheme.getName(id, ids);
+ String href = elementScheme.getHref(id, ids);
+ String onclick = elementScheme.onClick(id, ids);
+ String onmouseover = elementScheme.onMouseOver(id, ids);
+ String onmouseout = elementScheme.onMouseOut(id, ids);
+ write('', '<a');
+ if (href != null) {
+ write('', ' href="${href}"');
+ }
+ if (name != null) {
+ write('', ' name="${name}"');
+ }
+ if (title != null) {
+ write('', ' title="${escape(title)}"');
+ }
+ write('', ' style="${color}"');
+ if (onclick != null) {
+ write('', ' onclick="${onclick}"');
+ }
+ if (onmouseover != null) {
+ write('', ' onmouseover="${onmouseover}"');
}
+ if (onmouseout != null) {
+ write('', ' onmouseout="${onmouseout}"');
+ }
+ write('', '>');
+ pendingSourceLocationsEnd = true;
+ }
+ if (annotations.last == null) {
+ endCurrentLocation();
}
+ }
+
+ Map<int, List<Annotation>> annotationMap = <int, List<Annotation>>{};
+ for (Annotation annotation in annotations) {
+ annotationMap.putIfAbsent(annotation.codeOffset, () => <Annotation>[])
+ .add(annotation);
+ }
+
+ bool first = true;
+ for (int codeOffset in annotationMap.keys.toList()..sort()) {
+ List<Annotation> annotationList = annotationMap[codeOffset];
+ addSubstring(codeOffset, isFirst: first);
+ insertAnnotations(annotationList);
+ first = false;
+ }
+
+ addSubstring(code.length, isFirst: first, isLast: true);
+ endCurrentLocation();
+
+ int start = 0;
+ int end = lines.length - 1;
+ if (windowSize != null) {
+ start = Math.max(firstLine - windowSize, start);
+ end = Math.min(lastLine + windowSize, end);
+ }
+ return lines.sublist(start, end);
+}
+
+class CodeLine {
+ final int lineNo;
+ final StringBuffer codeBuffer = new StringBuffer();
+ final List<String> htmlParts = <String>[];
+ String _code;
+
+ CodeLine(this.lineNo);
- for (int targetOffset in codeLocations.keys.toList()..sort()) {
- List<SourceLocation> sourceLocations = codeLocations[targetOffset];
- addSubstring(targetOffset);
- insertSourceLocations(sourceLocations);
+ String get code {
+ if (_code == null) {
+ _code = codeBuffer.toString();
}
+ return _code;
+ }
- addSubstring(text.length);
- endCurrentLocation();
- return htmlBuffer.toString();
+ void printHtmlOn(StringBuffer htmlBuffer, [int lineNoWidth]) {
+ htmlBuffer.write(lineNumber(lineNo, lineNoWidth));
+ for (String part in htmlParts) {
+ htmlBuffer.write(part);
+ }
}
}
+
/// Computes the HTML representation for a collection of JavaScript code blocks.
String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) {
@@ -240,10 +505,10 @@ SourceMapHtmlInfo createHtmlInfo(SourceLocationCollection collection,
js.Node node = info.node;
String code = info.code;
String name = info.name;
- String onclick = 'show(\'$name\');';
SourceLocationCollection subcollection =
new SourceLocationCollection(collection);
- CodeProcessor codeProcessor = new CodeProcessor(onclick, subcollection);
+ CodeProcessor codeProcessor = new CodeProcessor(name, subcollection);
+ //print('${info.element}:${info.nodeMap.nodes.length}');
for (js.Node node in info.nodeMap.nodes) {
info.nodeMap[node].forEach(
(int targetOffset, List<SourceLocation> sourceLocations) {
@@ -312,6 +577,11 @@ String computeDartHtmlPart(String name,
int firstLineIndex;
int lastLineIndex;
+ List<int> lineIndices = uriMap.keys.toList()..sort();
+ int lineNoWidth;
+ if (lineIndices.isNotEmpty) {
+ lineNoWidth = '${lineIndices.last + windowSize + 1}'.length;
+ }
void flush() {
if (firstLineIndex != null && lastLineIndex != null) {
@@ -325,7 +595,7 @@ String computeDartHtmlPart(String name,
line < firstLineIndex;
line++) {
if (line >= 0) {
- dartCodeBuffer.write(lineNumber(line));
+ dartCodeBuffer.write(lineNumber(line, lineNoWidth));
dartCodeBuffer.write(sourceFile.getLineText(line));
}
}
@@ -334,7 +604,7 @@ String computeDartHtmlPart(String name,
line <= lastLineIndex + windowSize;
line++) {
if (line < sourceFile.lines) {
- dartCodeBuffer.write(lineNumber(line));
+ dartCodeBuffer.write(lineNumber(line, lineNoWidth));
dartCodeBuffer.write(sourceFile.getLineText(line));
}
}
@@ -345,7 +615,6 @@ String computeDartHtmlPart(String name,
codeBuffer.clear();
}
- List<int> lineIndices = uriMap.keys.toList()..sort();
lineIndices.forEach((int lineIndex) {
List<SourceLocation> locations = uriMap[lineIndex];
if (lastLineIndex != null &&
@@ -356,7 +625,7 @@ String computeDartHtmlPart(String name,
firstLineIndex = lineIndex;
} else {
for (int line = lastLineIndex + 1; line < lineIndex; line++) {
- codeBuffer.write(lineNumber(line));
+ codeBuffer.write(lineNumber(line, lineNoWidth));
codeBuffer.write(sourceFile.getLineText(line));
}
}
@@ -371,7 +640,7 @@ String computeDartHtmlPart(String name,
end = locations[i + 1].column;
}
if (i == 0) {
- codeBuffer.write(lineNumber(lineIndex));
+ codeBuffer.write(lineNumber(lineIndex, lineNoWidth));
codeBuffer.write(line.substring(0, start));
}
codeBuffer.write(
« no previous file with comments | « tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart ('k') | tests/compiler/dart2js/sourcemaps/trace_graph.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698