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

Side by Side 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 unified diff | Download patch
OLDNEW
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 12
12 import 'package:compiler/src/io/source_file.dart'; 13 import 'package:compiler/src/io/source_file.dart';
13 import 'package:compiler/src/io/source_information.dart'; 14 import 'package:compiler/src/io/source_information.dart';
14 import 'package:compiler/src/js/js.dart' as js; 15 import 'package:compiler/src/js/js.dart' as js;
15 16
16 import 'colors.dart'; 17 import 'colors.dart';
17 import 'sourcemap_helper.dart'; 18 import 'sourcemap_helper.dart';
18 import 'sourcemap_html_templates.dart'; 19 import 'sourcemap_html_templates.dart';
19 20
20 /// Returns the [index]th color for visualization. 21 /// Returns the [index]th color for visualization.
(...skipping 12 matching lines...) Expand all
33 34
34 /// Return the CSS color value for the [index]th span. 35 /// Return the CSS color value for the [index]th span.
35 String toPattern(int index) { 36 String toPattern(int index) {
36 /// Use gradient on spans to visually identify consecutive spans mapped to the 37 /// Use gradient on spans to visually identify consecutive spans mapped to the
37 /// same source location. 38 /// same source location.
38 HSV startColor = toColor(index); 39 HSV startColor = toColor(index);
39 HSV endColor = new HSV(startColor.h, startColor.s + 0.4, startColor.v - 0.2); 40 HSV endColor = new HSV(startColor.h, startColor.s + 0.4, startColor.v - 0.2);
40 return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})'; 41 return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})';
41 } 42 }
42 43
43 /// Return the html for the [index] line number. 44 /// Return the html for the [index] line number. If [width] is provided, shorter
44 String lineNumber(int index) { 45 /// line numbers will be prefixed with spaces to match the width.
45 return '<span class="lineNumber">${index + 1} </span>'; 46 String lineNumber(int index, [int width]) {
47 String text = '${index + 1}';
48 if (width != null && text.length < width) {
49 text = (' ' * (width - text.length)) + text;
50 }
51 return '<span class="lineNumber">$text </span>';
46 } 52 }
47 53
48 /// Return the html escaped [text]. 54 /// Return the html escaped [text].
49 String escape(String text) { 55 String escape(String text) {
50 return const HtmlEscape().convert(text); 56 return const HtmlEscape().convert(text);
51 } 57 }
52 58
53 /// Information needed to generate HTML for a single [SourceMapInfo]. 59 /// Information needed to generate HTML for a single [SourceMapInfo].
54 class SourceMapHtmlInfo { 60 class SourceMapHtmlInfo {
55 final SourceMapInfo sourceMapInfo; 61 final SourceMapInfo sourceMapInfo;
56 final CodeProcessor codeProcessor; 62 final CodeProcessor codeProcessor;
57 final SourceLocationCollection sourceLocationCollection; 63 final SourceLocationCollection sourceLocationCollection;
58 64
59 SourceMapHtmlInfo(this.sourceMapInfo, 65 SourceMapHtmlInfo(this.sourceMapInfo,
60 this.codeProcessor, 66 this.codeProcessor,
61 this.sourceLocationCollection); 67 this.sourceLocationCollection);
68
69 String toString() {
70 return sourceMapInfo.toString();
71 }
62 } 72 }
63 73
64 /// A collection of source locations. 74 /// A collection of source locations.
65 /// 75 ///
66 /// Used to index source locations for visualization and linking. 76 /// Used to index source locations for visualization and linking.
67 class SourceLocationCollection { 77 class SourceLocationCollection {
68 List<SourceLocation> sourceLocations = []; 78 List<SourceLocation> sourceLocations = [];
69 Map<SourceLocation, int> sourceLocationIndexMap; 79 Map<SourceLocation, int> sourceLocationIndexMap;
70 80
71 SourceLocationCollection([SourceLocationCollection parent]) 81 SourceLocationCollection([SourceLocationCollection parent])
72 : sourceLocationIndexMap = 82 : sourceLocationIndexMap =
73 parent == null ? {} : parent.sourceLocationIndexMap; 83 parent == null ? {} : parent.sourceLocationIndexMap;
74 84
75 int registerSourceLocation(SourceLocation sourceLocation) { 85 int registerSourceLocation(SourceLocation sourceLocation) {
76 return sourceLocationIndexMap.putIfAbsent(sourceLocation, () { 86 return sourceLocationIndexMap.putIfAbsent(sourceLocation, () {
77 sourceLocations.add(sourceLocation); 87 sourceLocations.add(sourceLocation);
78 return sourceLocationIndexMap.length; 88 return sourceLocationIndexMap.length;
79 }); 89 });
80 } 90 }
81 91
82 int getIndex(SourceLocation sourceLocation) { 92 int getIndex(SourceLocation sourceLocation) {
83 return sourceLocationIndexMap[sourceLocation]; 93 return sourceLocationIndexMap[sourceLocation];
84 } 94 }
85 } 95 }
86 96
97 abstract class CssColorScheme {
98 String singleLocationToCssColor(var id);
99
100 String multiLocationToCssColor(List ids);
101
102 bool get showLocationAsSpan;
103 }
104
105 class CustomColorScheme implements CssColorScheme {
106 final bool showLocationAsSpan;
107 final Function single;
108 final Function multi;
109
110 CustomColorScheme(
111 {this.showLocationAsSpan: false,
112 String this.single(var id),
113 String this.multi(List ids)});
114
115 String singleLocationToCssColor(var id) => single != null ? single(id) : null;
116
117 String multiLocationToCssColor(List ids) => multi != null ? multi(ids) : null;
118 }
119
120 class PatternCssColorScheme implements CssColorScheme {
121 const PatternCssColorScheme();
122
123 bool get showLocationAsSpan => true;
124
125 String singleLocationToCssColor(int index) {
126 return "background:${toPattern(index)};";
127 }
128
129 String multiLocationToCssColor(List<int> indices) {
130
131 StringBuffer sb = new StringBuffer();
132 double delta = 100.0 / (indices.length);
133 double position = 0.0;
134
135 void addColor(String color) {
136 sb.write(', ${color} ${position.toInt()}%');
137 position += delta;
138 sb.write(', ${color} ${position.toInt()}%');
139 }
140
141 for (int index in indices) {
142 addColor('${toColorCss(index)}');
143 }
144 return 'background: linear-gradient(to right${sb}); '
145 'background-size: 10px 10px;';
146 }
147 }
148
149 class SingleColorScheme implements CssColorScheme {
150 const SingleColorScheme();
151
152 bool get showLocationAsSpan => false;
153
154 String singleLocationToCssColor(int index) {
155 return "background:${toColorCss(index)};";
156 }
157
158 String multiLocationToCssColor(List<int> indices) {
159 StringBuffer sb = new StringBuffer();
160 double delta = 100.0 / (indices.length);
161 double position = 0.0;
162
163 void addColor(String color) {
164 sb.write(', ${color} ${position.toInt()}%');
165 position += delta;
166 sb.write(', ${color} ${position.toInt()}%');
167 }
168
169 for (int index in indices) {
170 addColor('${toColorCss(index)}');
171 }
172 return 'background: linear-gradient(to bottom${sb}); '
173 'background-size: 10px 3px;';
174 }
175 }
176
87 /// Processor that computes the HTML representation of a block of JavaScript 177 /// Processor that computes the HTML representation of a block of JavaScript
88 /// code and collects the source locations mapped in the code. 178 /// code and collects the source locations mapped in the code.
89 class CodeProcessor { 179 class CodeProcessor {
90 int lineIndex = 0; 180 int lineIndex = 0;
91 final String onclick; 181 final String name;
92 int currentJsSourceOffset = 0; 182 int currentJsSourceOffset = 0;
93 final SourceLocationCollection collection; 183 final SourceLocationCollection collection;
94 final Map<int, List<SourceLocation>> codeLocations = {}; 184 final Map<int, List<SourceLocation>> codeLocations = {};
185 final CssColorScheme colorScheme;
95 186
96 CodeProcessor(this.onclick, this.collection); 187 CodeProcessor(this.name, this.collection,
188 {this.colorScheme: const PatternCssColorScheme()});
97 189
98 void addSourceLocation(int targetOffset, SourceLocation sourceLocation) { 190 void addSourceLocation(int targetOffset, SourceLocation sourceLocation) {
99 codeLocations.putIfAbsent(targetOffset, () => []).add(sourceLocation); 191 codeLocations.putIfAbsent(targetOffset, () => []).add(sourceLocation);
100 collection.registerSourceLocation(sourceLocation); 192 collection.registerSourceLocation(sourceLocation);
101 } 193 }
102 194
103 String convertToHtml(String text) { 195 String convertToHtml(String text) {
104 StringBuffer htmlBuffer = new StringBuffer(); 196 List<Annotation> annotations = <Annotation>[];
105 int offset = 0; 197 codeLocations.forEach((int codeOffset, List<SourceLocation> locations) {
106 int lineIndex = 0; 198 for (SourceLocation location in locations) {
107 bool pendingSourceLocationsEnd = false; 199 if (location != null) {
108 htmlBuffer.write(lineNumber(lineIndex)); 200 annotations.add(new Annotation(
109 SourceLocation currentLocation; 201 collection.getIndex(location),
110 202 codeOffset,
111 void endCurrentLocation() { 203 location.shortText));
112 if (currentLocation != null) { 204 }
113 htmlBuffer.write('</a>'); 205 }
114 } 206 });
115 currentLocation = null; 207 return convertAnnotatedCodeToHtml(
116 } 208 text, annotations, colorScheme: colorScheme,
117 209 elementScheme: new HighlightLinkScheme(name),
118 void addSubstring(int until) { 210 windowSize: 3);
119 if (until <= offset) return; 211 }
120 212 }
121 String substring = text.substring(offset, until); 213
122 offset = until; 214 class Annotation {
123 bool first = true; 215 final id;
124 for (String line in substring.split('\n')) { 216 final int codeOffset;
125 if (!first) { 217 final String title;
218
219 Annotation(this.id, this.codeOffset, this.title);
220 }
221
222 class ElementScheme {
223 const ElementScheme();
224
225 String getName(var id, Set ids) => null;
226 String getHref(var id, Set ids) => null;
227 String onClick(var id, Set ids) => null;
228 String onMouseOver(var id, Set ids) => null;
229 String onMouseOut(var id, Set ids) => null;
230 }
231
232 class HighlightLinkScheme implements ElementScheme {
233 final String name;
234
235 HighlightLinkScheme(this.name);
236
237 @override
238 String getName(int id, Set<int> indices) {
239 return 'js$id';
240 }
241
242 @override
243 String getHref(int id, Set<int> indices) {
244 return "#${id}";
245 }
246
247 @override
248 String onClick(int id, Set<int> indices) {
249 return "show(\'$name\');";
250 }
251
252 @override
253 String onMouseOut(int id, Set<int> indices) {
254 String onmouseover = indices.map((i) => '\'$i\'').join(',');
255 return "highlight([${onmouseover}]);";
256 }
257
258 @override
259 String onMouseOver(int id, Set<int> indices) {
260 return "highlight([]);";
261 }
262 }
263
264 String convertAnnotatedCodeToHtml(
265 String code,
266 Iterable<Annotation> annotations,
267 {CssColorScheme colorScheme: const SingleColorScheme(),
268 ElementScheme elementScheme: const ElementScheme(),
269 int windowSize}) {
270 StringBuffer htmlBuffer = new StringBuffer();
271 List<CodeLine> lines = convertAnnotatedCodeToCodeLines(
272 code, annotations,
273 colorScheme: colorScheme,
274 elementScheme: elementScheme,
275 windowSize: windowSize);
276 int lineNoWidth;
277 if (lines.isNotEmpty) {
278 lineNoWidth = '${lines.last.lineNo + 1}'.length;
279 }
280 for (CodeLine line in lines) {
281 line.printHtmlOn(htmlBuffer, lineNoWidth);
282 }
283 return htmlBuffer.toString();
284 }
285
286 List<CodeLine> convertAnnotatedCodeToCodeLines(
287 String code,
288 Iterable<Annotation> annotations,
289 {CssColorScheme colorScheme: const SingleColorScheme(),
290 ElementScheme elementScheme: const ElementScheme(),
291 int windowSize}) {
292
293 List<CodeLine> lines = <CodeLine>[];
294 CodeLine currentLine;
295 int offset = 0;
296 int lineIndex = 0;
297 int firstLine;
298 int lastLine;
299 bool pendingSourceLocationsEnd = false;
300
301 void write(String code, String html) {
302 if (currentLine != null) {
303 currentLine.codeBuffer.write(code);
304 currentLine.htmlParts.add(html);
305 }
306 }
307
308 void startLine() {
309 lines.add(currentLine = new CodeLine(lines.length));
310 }
311
312 void endCurrentLocation() {
313 if (pendingSourceLocationsEnd) {
314 write('', '</a>');
315 }
316 pendingSourceLocationsEnd = false;
317 }
318
319 void addSubstring(int until, {bool isFirst: false, bool isLast: false}) {
320 if (until <= offset) return;
321 if (offset >= code.length) return;
322
323 String substring = code.substring(offset, until);
324 offset = until;
325 bool first = true;
326
327 if (isLast) {
328 lastLine = lineIndex;
329 }
330 if (isFirst) {
331 startLine();
332 }
333 for (String line in substring.split('\n')) {
334 if (!first) {
335 endCurrentLocation();
336 write('', '\n');
337 lineIndex++;
338 startLine();
339 }
340 if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) {
341 if (line.isNotEmpty) {
342 String before = line.substring(0, 1);
343 write(before, escape(before));
126 endCurrentLocation(); 344 endCurrentLocation();
127 htmlBuffer.write('\n'); 345 String after = line.substring(1);
128 lineIndex++; 346 write(after, escape(after));
129 htmlBuffer.write(lineNumber(lineIndex));
130 }
131 htmlBuffer.write(escape(line));
132 first = false;
133 }
134 }
135
136 void insertSourceLocations(List<SourceLocation> lastSourceLocations) {
137 endCurrentLocation();
138
139 String color;
140 int index;
141 String title;
142 if (lastSourceLocations.length == 1) {
143 SourceLocation sourceLocation = lastSourceLocations.single;
144 if (sourceLocation != null) {
145 index = collection.getIndex(sourceLocation);
146 color = "background:${toPattern(index)};";
147 title = sourceLocation.shortText;
148 currentLocation = sourceLocation;
149 } 347 }
150 } else { 348 } else {
151 349 write(line, escape(line));
152 index = collection.getIndex(lastSourceLocations.first); 350 }
153 StringBuffer sb = new StringBuffer(); 351 first = false;
154 double delta = 100.0 / (lastSourceLocations.length); 352 }
155 double position = 0.0; 353 if (isFirst) {
156 354 firstLine = lineIndex;
157 void addColor(String color) { 355 }
158 sb.write(', ${color} ${position.toInt()}%'); 356 }
159 position += delta; 357
160 sb.write(', ${color} ${position.toInt()}%'); 358 void insertAnnotations(List<Annotation> annotations) {
161 }
162
163 for (SourceLocation sourceLocation in lastSourceLocations) {
164 if (sourceLocation == null) continue;
165 int colorIndex = collection.getIndex(sourceLocation);
166 addColor('${toColorCss(colorIndex)}');
167 currentLocation = sourceLocation;
168 }
169 color = 'background: linear-gradient(to right${sb}); '
170 'background-size: 10px 10px;';
171 title = lastSourceLocations.map((l) => l.shortText).join(',');
172 }
173 if (index != null) {
174 Set<int> indices =
175 lastSourceLocations.map((l) => collection.getIndex(l)).toSet();
176 String onmouseover = indices.map((i) => '\'$i\'').join(',');
177 htmlBuffer.write(
178 '<a name="js$index" href="#${index}" style="$color" title="$title" '
179 'onclick="${onclick}" onmouseover="highlight([${onmouseover}]);"'
180 'onmouseout="highlight([]);">');
181 pendingSourceLocationsEnd = true;
182 }
183 if (lastSourceLocations.last == null) {
184 endCurrentLocation();
185 }
186 }
187
188 for (int targetOffset in codeLocations.keys.toList()..sort()) {
189 List<SourceLocation> sourceLocations = codeLocations[targetOffset];
190 addSubstring(targetOffset);
191 insertSourceLocations(sourceLocations);
192 }
193
194 addSubstring(text.length);
195 endCurrentLocation(); 359 endCurrentLocation();
196 return htmlBuffer.toString(); 360
197 } 361 String color;
198 } 362 var id;
363 String title;
364 if (annotations.length == 1) {
365 Annotation annotation = annotations.single;
366 if (annotation != null) {
367 id = annotation.id;
368 color = colorScheme.singleLocationToCssColor(id);
369 title = annotation.title;
370 }
371 } else {
372 id = annotations.first.id;
373 List ids = [];
374 for (Annotation annotation in annotations) {
375 ids.add(annotation.id);
376 }
377 color = colorScheme.multiLocationToCssColor(ids);
378 title = annotations.map((l) => l.title).join(',');
379 }
380 if (id != null) {
381 Set ids = annotations.map((l) => l.id).toSet();
382 String name = elementScheme.getName(id, ids);
383 String href = elementScheme.getHref(id, ids);
384 String onclick = elementScheme.onClick(id, ids);
385 String onmouseover = elementScheme.onMouseOver(id, ids);
386 String onmouseout = elementScheme.onMouseOut(id, ids);
387 write('', '<a');
388 if (href != null) {
389 write('', ' href="${href}"');
390 }
391 if (name != null) {
392 write('', ' name="${name}"');
393 }
394 if (title != null) {
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;
409 }
410 if (annotations.last == null) {
411 endCurrentLocation();
412 }
413 }
414
415 Map<int, List<Annotation>> annotationMap = <int, List<Annotation>>{};
416 for (Annotation annotation in annotations) {
417 annotationMap.putIfAbsent(annotation.codeOffset, () => <Annotation>[])
418 .add(annotation);
419 }
420
421 bool first = true;
422 for (int codeOffset in annotationMap.keys.toList()..sort()) {
423 List<Annotation> annotationList = annotationMap[codeOffset];
424 addSubstring(codeOffset, isFirst: first);
425 insertAnnotations(annotationList);
426 first = false;
427 }
428
429 addSubstring(code.length, isFirst: first, isLast: true);
430 endCurrentLocation();
431
432 int start = 0;
433 int end = lines.length - 1;
434 if (windowSize != null) {
435 start = Math.max(firstLine - windowSize, start);
436 end = Math.min(lastLine + windowSize, end);
437 }
438 return lines.sublist(start, end);
439 }
440
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
199 464
200 /// Computes the HTML representation for a collection of JavaScript code blocks. 465 /// Computes the HTML representation for a collection of JavaScript code blocks.
201 String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) { 466 String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) {
202 467
203 StringBuffer jsCodeBuffer = new StringBuffer(); 468 StringBuffer jsCodeBuffer = new StringBuffer();
204 for (SourceMapHtmlInfo info in infoList) { 469 for (SourceMapHtmlInfo info in infoList) {
205 String name = info.sourceMapInfo.name; 470 String name = info.sourceMapInfo.name;
206 String html = info.codeProcessor.convertToHtml(info.sourceMapInfo.code); 471 String html = info.codeProcessor.convertToHtml(info.sourceMapInfo.code);
207 String onclick = 'show(\'$name\');'; 472 String onclick = 'show(\'$name\');';
208 jsCodeBuffer.write( 473 jsCodeBuffer.write(
(...skipping 24 matching lines...) Expand all
233 } 498 }
234 return jsTraceBuffer.toString(); 499 return jsTraceBuffer.toString();
235 } 500 }
236 501
237 /// Computes the HTML information for the [info]. 502 /// Computes the HTML information for the [info].
238 SourceMapHtmlInfo createHtmlInfo(SourceLocationCollection collection, 503 SourceMapHtmlInfo createHtmlInfo(SourceLocationCollection collection,
239 SourceMapInfo info) { 504 SourceMapInfo info) {
240 js.Node node = info.node; 505 js.Node node = info.node;
241 String code = info.code; 506 String code = info.code;
242 String name = info.name; 507 String name = info.name;
243 String onclick = 'show(\'$name\');';
244 SourceLocationCollection subcollection = 508 SourceLocationCollection subcollection =
245 new SourceLocationCollection(collection); 509 new SourceLocationCollection(collection);
246 CodeProcessor codeProcessor = new CodeProcessor(onclick, subcollection); 510 CodeProcessor codeProcessor = new CodeProcessor(name, subcollection);
511 //print('${info.element}:${info.nodeMap.nodes.length}');
247 for (js.Node node in info.nodeMap.nodes) { 512 for (js.Node node in info.nodeMap.nodes) {
248 info.nodeMap[node].forEach( 513 info.nodeMap[node].forEach(
249 (int targetOffset, List<SourceLocation> sourceLocations) { 514 (int targetOffset, List<SourceLocation> sourceLocations) {
250 for (SourceLocation sourceLocation in sourceLocations) { 515 for (SourceLocation sourceLocation in sourceLocations) {
251 codeProcessor.addSourceLocation(targetOffset, sourceLocation); 516 codeProcessor.addSourceLocation(targetOffset, sourceLocation);
252 } 517 }
253 }); 518 });
254 } 519 }
255 return new SourceMapHtmlInfo(info, codeProcessor, subcollection); 520 return new SourceMapHtmlInfo(info, codeProcessor, subcollection);
256 } 521 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 List<SourceLocation> lineList = 570 List<SourceLocation> lineList =
306 uriMap.putIfAbsent(sourceLocation.line, () => []); 571 uriMap.putIfAbsent(sourceLocation.line, () => []);
307 lineList.add(sourceLocation); 572 lineList.add(sourceLocation);
308 }); 573 });
309 sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) { 574 sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) {
310 SourceFile sourceFile = sourceFileManager.getSourceFile(uri); 575 SourceFile sourceFile = sourceFileManager.getSourceFile(uri);
311 StringBuffer codeBuffer = new StringBuffer(); 576 StringBuffer codeBuffer = new StringBuffer();
312 577
313 int firstLineIndex; 578 int firstLineIndex;
314 int lastLineIndex; 579 int lastLineIndex;
580 List<int> lineIndices = uriMap.keys.toList()..sort();
581 int lineNoWidth;
582 if (lineIndices.isNotEmpty) {
583 lineNoWidth = '${lineIndices.last + windowSize + 1}'.length;
584 }
315 585
316 void flush() { 586 void flush() {
317 if (firstLineIndex != null && lastLineIndex != null) { 587 if (firstLineIndex != null && lastLineIndex != null) {
318 dartCodeBuffer.write( 588 dartCodeBuffer.write(
319 '<h4>${uri.pathSegments.last}, ' 589 '<h4>${uri.pathSegments.last}, '
320 '${firstLineIndex - windowSize + 1}-' 590 '${firstLineIndex - windowSize + 1}-'
321 '${lastLineIndex + windowSize + 1}' 591 '${lastLineIndex + windowSize + 1}'
322 '</h4>\n'); 592 '</h4>\n');
323 dartCodeBuffer.write('<pre>\n'); 593 dartCodeBuffer.write('<pre>\n');
324 for (int line = firstLineIndex - windowSize; 594 for (int line = firstLineIndex - windowSize;
325 line < firstLineIndex; 595 line < firstLineIndex;
326 line++) { 596 line++) {
327 if (line >= 0) { 597 if (line >= 0) {
328 dartCodeBuffer.write(lineNumber(line)); 598 dartCodeBuffer.write(lineNumber(line, lineNoWidth));
329 dartCodeBuffer.write(sourceFile.getLineText(line)); 599 dartCodeBuffer.write(sourceFile.getLineText(line));
330 } 600 }
331 } 601 }
332 dartCodeBuffer.write(codeBuffer); 602 dartCodeBuffer.write(codeBuffer);
333 for (int line = lastLineIndex + 1; 603 for (int line = lastLineIndex + 1;
334 line <= lastLineIndex + windowSize; 604 line <= lastLineIndex + windowSize;
335 line++) { 605 line++) {
336 if (line < sourceFile.lines) { 606 if (line < sourceFile.lines) {
337 dartCodeBuffer.write(lineNumber(line)); 607 dartCodeBuffer.write(lineNumber(line, lineNoWidth));
338 dartCodeBuffer.write(sourceFile.getLineText(line)); 608 dartCodeBuffer.write(sourceFile.getLineText(line));
339 } 609 }
340 } 610 }
341 dartCodeBuffer.write('</pre>\n'); 611 dartCodeBuffer.write('</pre>\n');
342 firstLineIndex = null; 612 firstLineIndex = null;
343 lastLineIndex = null; 613 lastLineIndex = null;
344 } 614 }
345 codeBuffer.clear(); 615 codeBuffer.clear();
346 } 616 }
347 617
348 List<int> lineIndices = uriMap.keys.toList()..sort();
349 lineIndices.forEach((int lineIndex) { 618 lineIndices.forEach((int lineIndex) {
350 List<SourceLocation> locations = uriMap[lineIndex]; 619 List<SourceLocation> locations = uriMap[lineIndex];
351 if (lastLineIndex != null && 620 if (lastLineIndex != null &&
352 lastLineIndex + windowSize * 4 < lineIndex) { 621 lastLineIndex + windowSize * 4 < lineIndex) {
353 flush(); 622 flush();
354 } 623 }
355 if (firstLineIndex == null) { 624 if (firstLineIndex == null) {
356 firstLineIndex = lineIndex; 625 firstLineIndex = lineIndex;
357 } else { 626 } else {
358 for (int line = lastLineIndex + 1; line < lineIndex; line++) { 627 for (int line = lastLineIndex + 1; line < lineIndex; line++) {
359 codeBuffer.write(lineNumber(line)); 628 codeBuffer.write(lineNumber(line, lineNoWidth));
360 codeBuffer.write(sourceFile.getLineText(line)); 629 codeBuffer.write(sourceFile.getLineText(line));
361 } 630 }
362 } 631 }
363 String line = sourceFile.getLineText(lineIndex); 632 String line = sourceFile.getLineText(lineIndex);
364 locations.sort((a, b) => a.offset.compareTo(b.offset)); 633 locations.sort((a, b) => a.offset.compareTo(b.offset));
365 for (int i = 0; i < locations.length; i++) { 634 for (int i = 0; i < locations.length; i++) {
366 SourceLocation sourceLocation = locations[i]; 635 SourceLocation sourceLocation = locations[i];
367 int index = collection.getIndex(sourceLocation); 636 int index = collection.getIndex(sourceLocation);
368 int start = sourceLocation.column; 637 int start = sourceLocation.column;
369 int end = line.length; 638 int end = line.length;
370 if (i + 1 < locations.length) { 639 if (i + 1 < locations.length) {
371 end = locations[i + 1].column; 640 end = locations[i + 1].column;
372 } 641 }
373 if (i == 0) { 642 if (i == 0) {
374 codeBuffer.write(lineNumber(lineIndex)); 643 codeBuffer.write(lineNumber(lineIndex, lineNoWidth));
375 codeBuffer.write(line.substring(0, start)); 644 codeBuffer.write(line.substring(0, start));
376 } 645 }
377 codeBuffer.write( 646 codeBuffer.write(
378 '<a name="${index}" style="background:${toPattern(index)};" ' 647 '<a name="${index}" style="background:${toPattern(index)};" '
379 'title="[${lineIndex + 1},${start + 1}]" ' 648 'title="[${lineIndex + 1},${start + 1}]" '
380 'onmouseover="highlight(\'$index\');" ' 649 'onmouseover="highlight(\'$index\');" '
381 'onmouseout="highlight();">'); 650 'onmouseout="highlight();">');
382 codeBuffer.write(line.substring(start, end)); 651 codeBuffer.write(line.substring(start, end));
383 codeBuffer.write('</a>'); 652 codeBuffer.write('</a>');
384 } 653 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 } else { 702 } else {
434 buffer.write('<td class="code">${codePoint.dartCode}</td>'); 703 buffer.write('<td class="code">${codePoint.dartCode}</td>');
435 buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>'); 704 buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>');
436 } 705 }
437 buffer.write('</tr>'); 706 buffer.write('</tr>');
438 }); 707 });
439 buffer.write('</table>'); 708 buffer.write('</table>');
440 709
441 return buffer.toString(); 710 return buffer.toString();
442 } 711 }
OLDNEW
« 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