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

Unified 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, 3 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
« no previous file with comments | « CHANGELOG.md ('k') | bin/inference/index.html » ('j') | lib/src/util.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: bin/inference/client.dart
diff --git a/bin/inference/client.dart b/bin/inference/client.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3851c3c1c78ac29c79237f451c04657c6d6aed1f
--- /dev/null
+++ b/bin/inference/client.dart
@@ -0,0 +1,236 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Client component to display [GlobalResult]s as a web app.
+library dart2js_info.bin.inference.client;
+
+import 'dart:html' hide Entry;
+import 'dart:convert';
+import 'package:dart2js_info/info.dart';
+import 'package:charcode/charcode.dart';
+
+AllInfo data;
+main() async {
+ data = AllInfo.parseFromJson(
+ JSON.decode(await HttpRequest.getString('/data')));
+
+ routeByHash();
+ window.onHashChange.listen((_) => routeByHash());
+}
+
+/// Does basic routing for the client UI.
+routeByHash() {
+ var hash = window.location.hash;
+ if (hash.isEmpty || hash == '#' || hash == '#!') {
+ handleHomePage();
+ } else if (hash.startsWith('#!')) {
+ handleFileView(hash.substring(2));
+ }
+}
+
+/// Renders the home screen: a list of files with results.
+handleHomePage() {
+ var files = UrlRetriever.run(data);
+ var html = new StringBuffer()..write('<ul>');
+ for (var file in files) {
+ html.write('<li> <a href="#!$file">$file</a></li>');
+ }
+ html.write('</ul>');
+ document.body.setInnerHtml('$html', treeSanitizer: NodeTreeSanitizer.trusted);
+}
+
+/// Renders the results of a single file: the code with highlighting for each
+/// send.
+handleFileView(String path) async {
+ var contents = await HttpRequest.getString('file/$path');
+ var visitor = new SendHighlighter(path, contents);
+ data.accept(visitor);
+ var code = '${visitor.code}';
+ document.body.setInnerHtml('''
+ <div class="grid">
+ <div class="main code">$code</div>
+ <div id="selections" class="right code"></div>
+ </div>
+ ''',
+ treeSanitizer: NodeTreeSanitizer.trusted);
+
+ var div = document.querySelector('#selections');
+ visitAllMetrics((metric, _) {
+ if (metric is GroupedMetric || metric.name == 'reachable functions') return;
+ var cssClassName = _classNameForMetric(metric);
+ var node = new Element.html('<div>'
+ '<span class="send $cssClassName inactive">${metric.name}</span>'
+ '</div>');
+ node.children[0].onClick.listen((_) {
+ document.querySelectorAll('.$cssClassName').classes.toggle('inactive');
+ });
+ div.append(node);
+ });
+}
+
+/// Extracts urls for all files mentioned in the results.
+class UrlRetriever extends RecursiveInfoVisitor {
+ List<String> _paths = [];
+
+ static List<String> run(AllInfo results) {
+ var visitor = new UrlRetriever();
+ results.accept(visitor);
+ return visitor._paths;
+ }
+
+ @override
+ visitLibrary(LibraryInfo info) {
+ _paths.add(info.uri.path);
+ super.visitLibrary(info);
+ }
+
+ @override
+ visitFunction(FunctionInfo info) {
+ var path = info.measurements?.uri?.path;
+ if (path != null) _paths.add(path);
+ }
+}
+
+/// Visitors that highlights every send in the text of a file using HTML
+/// `<span>` tags.
+class SendHighlighter extends RecursiveInfoVisitor {
+ final String path;
+ final StringEditBuffer code;
+
+ SendHighlighter(this.path, String contents)
+ : code = new StringEditBuffer(contents) {
+ code.insert(0, '<span class="line">');
+ for (int i = 0; i < contents.length; i++) {
+ if (contents.codeUnitAt(i) == $lt) {
+ code.replace(i, i + 1, '&lt;');
+ } else if (contents.codeUnitAt(i) == $gt) {
+ code.replace(i, i + 1, '&gt;');
+ } else if (contents.codeUnitAt(i) == $lf) {
+ code.insert(i + 1, '</span><span class="line">');
+ }
+ }
+ code.insert(contents.length, '</span>');
+ }
+
+ @override
+ visitFunction(FunctionInfo function) {
+ if (function.measurements?.uri?.path != path) return;
+ var entries = function.measurements.entries;
+ for (var metric in entries.keys) {
+ if (metric is GroupedMetric) continue;
+ var cssClassName = _classNameForMetric(metric);
+ for (var entry in entries[metric]) {
+ code.insert(entry.begin,
+ '<span class="send ${cssClassName} inactive">', -entry.end);
+ code.insert(entry.end, '</span>');
+ }
+ }
+ }
+}
+
+_classNameForMetric(Metric metric) => metric.name.replaceAll(' ', '-');
+
+/// A buffer meant to apply edits on a string (rather than building a string
+/// from scratch). Each change is described using the location information on
+/// the original string. Internally this buffer keeps track of how a
+/// modification in one portion can offset a modification further down the
+/// string.
+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
+ final String original;
+ final _edits = <_StringEdit>[];
+
+ StringEditBuffer(this.original);
+
+ bool get hasEdits => _edits.length > 0;
+
+ /// Edit the original text, replacing text on the range [begin] and
+ /// exclusive [end] with the [replacement] string.
+ void replace(int begin, int end, String replacement, [int sortId]) {
+ _edits.add(new _StringEdit(begin, end, replacement, sortId));
+ }
+
+ /// Insert [string] at [offset].
+ /// Equivalent to `replace(offset, offset, string)`.
+ void insert(int offset, String string, [sortId]) =>
+ replace(offset, offset, string, sortId);
+
+ /// Remove text from the range [begin] to exclusive [end].
+ /// Equivalent to `replace(begin, end, '')`.
+ void remove(int begin, int end) => replace(begin, end, '');
+
+ /// Applies all pending [edit]s and returns a new string.
+ ///
+ /// This method is non-destructive: it does not discard existing edits or
+ /// change the [original] string. Further edits can be added and this method
+ /// can be called again.
+ ///
+ /// Throws [UnsupportedError] if the edits were overlapping. If no edits were
+ /// made, the original string will be returned.
+ String toString() {
+ var sb = new StringBuffer();
+ if (_edits.length == 0) return original;
+
+ // Sort edits by start location.
+ _edits.sort();
+
+ int consumed = 0;
+ for (var edit in _edits) {
+ if (consumed > edit.begin) {
+ sb = new StringBuffer();
+ sb.write('overlapping edits. Insert at offset ');
+ sb.write(edit.begin);
+ sb.write(' but have consumed ');
+ sb.write(consumed);
+ sb.write(' input characters. List of edits:');
+ for (var e in _edits) {
+ sb.write('\n ');
+ sb.write(e);
+ }
+ throw new UnsupportedError(sb.toString());
+ }
+
+ // Add characters from the original string between this edit and the last
+ // one, if any.
+ var betweenEdits = original.substring(consumed, edit.begin);
+ sb.write(betweenEdits);
+ sb.write(edit.string);
+ consumed = edit.end;
+ }
+
+ // Add any text from the end of the original string that was not replaced.
+ sb.write(original.substring(consumed));
+ return sb.toString();
+ }
+}
+
+/// A single edit in a [StringEditBuffer].
+class _StringEdit implements Comparable<_StringEdit> {
+ // Offset where edit begins
+ final int begin;
+
+ // Offset where edit ends
+ final int end;
+
+ // Sort index as a tie-breaker for edits that have the same location.
+ final int sortId;
+
+ // String to insert
+ final String string;
+
+ _StringEdit(int begin, this.end, this.string, [int sortId])
+ : begin = begin, sortId = sortId == null ? begin : sortId;
+
+ int get length => end - begin;
+
+ String toString() => '(Edit @ $begin,$end: "$string")';
+
+ int compareTo(_StringEdit other) {
+ int diff = begin - other.begin;
+ if (diff != 0) return diff;
+ diff = end - other.end;
+ if (diff != 0) return diff;
+ // use edit order as a tie breaker
+ return sortId - other.sortId;
+ }
+}
« 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