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

Side by Side Diff: pkg/compiler/tool/stats/client.dart

Issue 1220043005: dart2js send stats, includes: (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 5 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// Client component to display [GlobalResult]s as a web app.
6 library compiler.tool.stats.client;
7
8 import 'dart:html' hide Entry;
9 import 'dart:convert';
10 import 'package:compiler/src/stats/stats.dart';
11 import 'package:charcode/charcode.dart';
12
13 GlobalResult data;
14 main() async {
15 data = GlobalResult.fromJson(
16 JSON.decode(await HttpRequest.getString('/data')));
17
18 routeByHash();
19 window.onHashChange.listen((_) => routeByHash());
20 }
21
22 /// Does basic routing for the client UI.
23 routeByHash() {
24 var hash = window.location.hash;
25 if (hash.isEmpty || hash == '#' || hash == '#!') {
26 handleHomePage();
27 } else if (hash.startsWith('#!')) {
28 handleFileView(hash.substring(2));
29 }
30 }
31
32 /// Renders the home screen: a list of files with results.
33 handleHomePage() {
34 var files = UrlRetriever.run(data);
35 var html = new StringBuffer()..write('<ul>');
36 for (var file in files) {
37 html.write('<li> <a href="#!$file">$file</a></li>');
38 }
39 html.write('</ul>');
40 document.body.setInnerHtml('$html', treeSanitizer: NodeTreeSanitizer.trusted);
41 }
42
43 /// Renders the results of a single file: the code with highlighting for each
44 /// send.
45 handleFileView(String path) async {
46 var contents = await HttpRequest.getString('file/$path');
47 var visitor = new SendHighlighter(path, contents);
48 data.accept(visitor);
49 var code = '${visitor.code}';
50 document.body.setInnerHtml('''
51 <div class="grid">
52 <div class="main code">$code</div>
53 <div id="selections" class="right code"></div>
54 </div>
55 ''',
56 treeSanitizer: NodeTreeSanitizer.trusted);
57
58 var div = document.querySelector('#selections');
59 visitAllMetrics((metric, _) {
60 if (metric is GroupedMetric || metric.name == 'reachable functions') return;
61 var cssClassName = _classNameForMetric(metric);
62 var node = new Element.html('<div>'
63 '<span class="send $cssClassName inactive">${metric.name}</span>'
64 '</div>');
65 node.children[0].onClick.listen((_) {
66 document.querySelectorAll('.$cssClassName').classes.toggle('inactive');
67 });
68 div.append(node);
69 });
70 }
71
72 /// Extracts urls for all files mentioned in the results.
73 class UrlRetriever extends RecursiveResultVisitor {
74 List<String> _paths = [];
75
76 static List<String> run(GlobalResult results) {
77 var visitor = new UrlRetriever();
78 results.accept(visitor);
79 return visitor._paths;
80 }
81
82 @override
83 visitCompilationUnit(CompilationUnitResult unit) {
84 _paths.add(unit.uri.path);
85 }
86
87 @override
88 visitFunction(FunctionResult function) {}
89 }
90
91 /// Visitors that highlights every send in the text of a file using HTML
92 /// `<span>` tags.
93 class SendHighlighter extends RecursiveResultVisitor {
94 final String path;
95 final StringEditBuffer code;
96
97 SendHighlighter(this.path, String contents)
98 : code = new StringEditBuffer(contents) {
99 code.insert(0, '<span class="line">');
100 for (int i = 0; i < contents.length; i++) {
101 if (contents.codeUnitAt(i) == $lt) {
102 code.replace(i, i + 1, '&lt;');
103 } else if (contents.codeUnitAt(i) == $gt) {
104 code.replace(i, i + 1, '&gt;');
105 } else if (contents.codeUnitAt(i) == $lf) {
106 code.insert(i + 1, '</span><span class="line">');
107 }
108 }
109 code.insert(contents.length, '</span>');
110 }
111
112 @override
113 visitCompilationUnit(CompilationUnitResult unit) {
114 // TODO(sigmund): change results to store a map from Uri to file results.
115 if (path != unit.uri.path) return;
116 super.visitCompilationUnit(unit);
117 }
118
119 @override
120 visitFunction(FunctionResult function) {
121 var entries = function.measurements.entries;
122 for (var metric in entries.keys) {
123 if (metric is GroupedMetric) continue;
124 var cssClassName = _classNameForMetric(metric);
125 for (var entry in entries[metric]) {
126 code.insert(entry.begin,
127 '<span class="send ${cssClassName} inactive">', -entry.end);
128 code.insert(entry.end, '</span>');
129 }
130 }
131 }
132 }
133
134 _classNameForMetric(Metric metric) => metric.name.replaceAll(' ', '-');
135
136 /// A buffer meant to apply edits on a string (rather than building a string
137 /// from scratch). Each change is described using the location information on
138 /// the original string. Internally this buffer keeps track of how a
139 /// modification in one portion can offset a modification further down the
140 /// string.
141 class StringEditBuffer {
142 final String original;
143 final _edits = <_StringEdit>[];
144
145 StringEditBuffer(this.original);
146
147 bool get hasEdits => _edits.length > 0;
148
149 /// Edit the original text, replacing text on the range [begin] and
150 /// exclusive [end] with the [replacement] string.
151 void replace(int begin, int end, String replacement, [int sortId]) {
152 _edits.add(new _StringEdit(begin, end, replacement, sortId));
153 }
154
155 /// Insert [string] at [offset].
156 /// Equivalent to `replace(offset, offset, string)`.
157 void insert(int offset, String string, [sortId]) =>
158 replace(offset, offset, string, sortId);
159
160 /// Remove text from the range [begin] to exclusive [end].
161 /// Equivalent to `replace(begin, end, '')`.
162 void remove(int begin, int end) => replace(begin, end, '');
163
164 /// Applies all pending [edit]s and returns a new string.
165 ///
166 /// This method is non-destructive: it does not discard existing edits or
167 /// change the [original] string. Further edits can be added and this method
168 /// can be called again.
169 ///
170 /// Throws [UnsupportedError] if the edits were overlapping. If no edits were
171 /// made, the original string will be returned.
172 String toString() {
173 var sb = new StringBuffer();
174 if (_edits.length == 0) return original;
175
176 // Sort edits by start location.
177 _edits.sort();
178
179 int consumed = 0;
180 for (var edit in _edits) {
181 if (consumed > edit.begin) {
182 sb = new StringBuffer();
183 sb.write('overlapping edits. Insert at offset ');
184 sb.write(edit.begin);
185 sb.write(' but have consumed ');
186 sb.write(consumed);
187 sb.write(' input characters. List of edits:');
188 for (var e in _edits) {
189 sb.write('\n ');
190 sb.write(e);
191 }
192 throw new UnsupportedError(sb.toString());
193 }
194
195 // Add characters from the original string between this edit and the last
196 // one, if any.
197 var betweenEdits = original.substring(consumed, edit.begin);
198 sb.write(betweenEdits);
199 sb.write(edit.string);
200 consumed = edit.end;
201 }
202
203 // Add any text from the end of the original string that was not replaced.
204 sb.write(original.substring(consumed));
205 return sb.toString();
206 }
207 }
208
209 /// A single edit in a [StringEditBuffer].
210 class _StringEdit implements Comparable<_StringEdit> {
211 // Offset where edit begins
212 final int begin;
213
214 // Offset where edit ends
215 final int end;
216
217 // Sort index as a tie-breaker for edits that have the same location.
218 final int sortId;
219
220 // String to insert
221 final String string;
222
223 _StringEdit(int begin, this.end, this.string, [int sortId])
224 : begin = begin, sortId = sortId == null ? begin : sortId;
225
226 int get length => end - begin;
227
228 String toString() => '(Edit @ $begin,$end: "$string")';
229
230 int compareTo(_StringEdit other) {
231 int diff = begin - other.begin;
232 if (diff != 0) return diff;
233 diff = end - other.end;
234 if (diff != 0) return diff;
235 // use edit order as a tie breaker
236 return sortId - other.sortId;
237 }
238 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698