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

Side by Side Diff: bin/inference/client.dart

Issue 1372333002: Add measurements and send-metrics to dart2js's info. (Closed) Base URL: git@github.com:dart-lang/dart2js_info.git@master
Patch Set: Created 5 years, 2 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 dart2js_info.bin.inference.client;
7
8 import 'dart:html' hide Entry;
9 import 'dart:convert';
10 import 'package:dart2js_info/info.dart';
11 import 'package:charcode/charcode.dart';
12
13 AllInfo data;
14 main() async {
15 data = AllInfo.parseFromJson(
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 RecursiveInfoVisitor {
74 List<String> _paths = [];
75
76 static List<String> run(AllInfo results) {
77 var visitor = new UrlRetriever();
78 results.accept(visitor);
79 return visitor._paths;
80 }
81
82 @override
83 visitLibrary(LibraryInfo info) {
84 _paths.add(info.uri.path);
85 super.visitLibrary(info);
86 }
87
88 @override
89 visitFunction(FunctionInfo info) {
90 var path = info.measurements?.uri?.path;
91 if (path != null) _paths.add(path);
92 }
93 }
94
95 /// Visitors that highlights every send in the text of a file using HTML
96 /// `<span>` tags.
97 class SendHighlighter extends RecursiveInfoVisitor {
98 final String path;
99 final StringEditBuffer code;
100
101 SendHighlighter(this.path, String contents)
102 : code = new StringEditBuffer(contents) {
103 code.insert(0, '<span class="line">');
104 for (int i = 0; i < contents.length; i++) {
105 if (contents.codeUnitAt(i) == $lt) {
106 code.replace(i, i + 1, '&lt;');
107 } else if (contents.codeUnitAt(i) == $gt) {
108 code.replace(i, i + 1, '&gt;');
109 } else if (contents.codeUnitAt(i) == $lf) {
110 code.insert(i + 1, '</span><span class="line">');
111 }
112 }
113 code.insert(contents.length, '</span>');
114 }
115
116 @override
117 visitFunction(FunctionInfo function) {
118 if (function.measurements?.uri?.path != path) return;
119 var entries = function.measurements.entries;
120 for (var metric in entries.keys) {
121 if (metric is GroupedMetric) continue;
122 var cssClassName = _classNameForMetric(metric);
123 for (var entry in entries[metric]) {
124 code.insert(entry.begin,
125 '<span class="send ${cssClassName} inactive">', -entry.end);
126 code.insert(entry.end, '</span>');
127 }
128 }
129 }
130 }
131
132 _classNameForMetric(Metric metric) => metric.name.replaceAll(' ', '-');
133
134 /// A buffer meant to apply edits on a string (rather than building a string
135 /// from scratch). Each change is described using the location information on
136 /// the original string. Internally this buffer keeps track of how a
137 /// modification in one portion can offset a modification further down the
138 /// string.
139 class StringEditBuffer {
Johnni Winther 2015/10/02 10:09:49 This should have its own package!
Siggi Cherem (dart-lang) 2015/10/02 17:16:17 :) - I moved it to it's own library for now and ad
140 final String original;
141 final _edits = <_StringEdit>[];
142
143 StringEditBuffer(this.original);
144
145 bool get hasEdits => _edits.length > 0;
146
147 /// Edit the original text, replacing text on the range [begin] and
148 /// exclusive [end] with the [replacement] string.
149 void replace(int begin, int end, String replacement, [int sortId]) {
150 _edits.add(new _StringEdit(begin, end, replacement, sortId));
151 }
152
153 /// Insert [string] at [offset].
154 /// Equivalent to `replace(offset, offset, string)`.
155 void insert(int offset, String string, [sortId]) =>
156 replace(offset, offset, string, sortId);
157
158 /// Remove text from the range [begin] to exclusive [end].
159 /// Equivalent to `replace(begin, end, '')`.
160 void remove(int begin, int end) => replace(begin, end, '');
161
162 /// Applies all pending [edit]s and returns a new string.
163 ///
164 /// This method is non-destructive: it does not discard existing edits or
165 /// change the [original] string. Further edits can be added and this method
166 /// can be called again.
167 ///
168 /// Throws [UnsupportedError] if the edits were overlapping. If no edits were
169 /// made, the original string will be returned.
170 String toString() {
171 var sb = new StringBuffer();
172 if (_edits.length == 0) return original;
173
174 // Sort edits by start location.
175 _edits.sort();
176
177 int consumed = 0;
178 for (var edit in _edits) {
179 if (consumed > edit.begin) {
180 sb = new StringBuffer();
181 sb.write('overlapping edits. Insert at offset ');
182 sb.write(edit.begin);
183 sb.write(' but have consumed ');
184 sb.write(consumed);
185 sb.write(' input characters. List of edits:');
186 for (var e in _edits) {
187 sb.write('\n ');
188 sb.write(e);
189 }
190 throw new UnsupportedError(sb.toString());
191 }
192
193 // Add characters from the original string between this edit and the last
194 // one, if any.
195 var betweenEdits = original.substring(consumed, edit.begin);
196 sb.write(betweenEdits);
197 sb.write(edit.string);
198 consumed = edit.end;
199 }
200
201 // Add any text from the end of the original string that was not replaced.
202 sb.write(original.substring(consumed));
203 return sb.toString();
204 }
205 }
206
207 /// A single edit in a [StringEditBuffer].
208 class _StringEdit implements Comparable<_StringEdit> {
209 // Offset where edit begins
210 final int begin;
211
212 // Offset where edit ends
213 final int end;
214
215 // Sort index as a tie-breaker for edits that have the same location.
216 final int sortId;
217
218 // String to insert
219 final String string;
220
221 _StringEdit(int begin, this.end, this.string, [int sortId])
222 : begin = begin, sortId = sortId == null ? begin : sortId;
223
224 int get length => end - begin;
225
226 String toString() => '(Edit @ $begin,$end: "$string")';
227
228 int compareTo(_StringEdit other) {
229 int diff = begin - other.begin;
230 if (diff != 0) return diff;
231 diff = end - other.end;
232 if (diff != 0) return diff;
233 // use edit order as a tie breaker
234 return sortId - other.sortId;
235 }
236 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | bin/inference/index.html » ('j') | lib/src/util.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698