OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, 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 library polymer.src.utils; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'package:path/path.dart' show Builder; |
| 9 export 'utils_observe.dart' show toCamelCase, toHyphenedName; |
| 10 |
| 11 /** |
| 12 * An instance of the pathos library builder. We could just use the default |
| 13 * builder in pathos, but we add this indirection to make it possible to run |
| 14 * unittest for windows paths. |
| 15 */ |
| 16 Builder path = new Builder(); |
| 17 |
| 18 /** Convert a OS specific path into a url. */ |
| 19 String pathToUrl(String relPath) => |
| 20 (path.separator == '/') ? relPath : path.split(relPath).join('/'); |
| 21 |
| 22 /** |
| 23 * Invokes [callback], logs how long it took to execute in ms, and returns |
| 24 * whatever [callback] returns. The log message will be printed if [printTime] |
| 25 * is true. |
| 26 */ |
| 27 time(String logMessage, callback(), |
| 28 {bool printTime: false, bool useColors: false}) { |
| 29 final watch = new Stopwatch(); |
| 30 watch.start(); |
| 31 var result = callback(); |
| 32 watch.stop(); |
| 33 final duration = watch.elapsedMilliseconds; |
| 34 if (printTime) { |
| 35 _printMessage(logMessage, duration, useColors); |
| 36 } |
| 37 return result; |
| 38 } |
| 39 |
| 40 /** |
| 41 * Invokes [callback], logs how long it takes from the moment [callback] is |
| 42 * executed until the future it returns is completed. Returns the future |
| 43 * returned by [callback]. The log message will be printed if [printTime] |
| 44 * is true. |
| 45 */ |
| 46 Future asyncTime(String logMessage, Future callback(), |
| 47 {bool printTime: false, bool useColors: false}) { |
| 48 final watch = new Stopwatch(); |
| 49 watch.start(); |
| 50 return callback()..then((_) { |
| 51 watch.stop(); |
| 52 final duration = watch.elapsedMilliseconds; |
| 53 if (printTime) { |
| 54 _printMessage(logMessage, duration, useColors); |
| 55 } |
| 56 }); |
| 57 } |
| 58 |
| 59 void _printMessage(String logMessage, int duration, bool useColors) { |
| 60 var buf = new StringBuffer(); |
| 61 buf.write(logMessage); |
| 62 for (int i = logMessage.length; i < 60; i++) buf.write(' '); |
| 63 buf.write(' -- '); |
| 64 if (useColors) { |
| 65 buf.write(GREEN_COLOR); |
| 66 } |
| 67 if (duration < 10) buf.write(' '); |
| 68 if (duration < 100) buf.write(' '); |
| 69 buf..write(duration)..write(' ms'); |
| 70 if (useColors) { |
| 71 buf.write(NO_COLOR); |
| 72 } |
| 73 print(buf.toString()); |
| 74 } |
| 75 |
| 76 // Color constants used for generating messages. |
| 77 final String GREEN_COLOR = '\u001b[32m'; |
| 78 final String RED_COLOR = '\u001b[31m'; |
| 79 final String MAGENTA_COLOR = '\u001b[35m'; |
| 80 final String NO_COLOR = '\u001b[0m'; |
| 81 |
| 82 /** A future that waits until all added [Future]s complete. */ |
| 83 // TODO(sigmund): this should be part of the futures/core libraries. |
| 84 class FutureGroup { |
| 85 static const _FINISHED = -1; |
| 86 |
| 87 int _pending = 0; |
| 88 Future _failedTask; |
| 89 final Completer<List> _completer = new Completer<List>(); |
| 90 final List results = []; |
| 91 |
| 92 /** Gets the task that failed, if any. */ |
| 93 Future get failedTask => _failedTask; |
| 94 |
| 95 /** |
| 96 * Wait for [task] to complete. |
| 97 * |
| 98 * If this group has already been marked as completed, you'll get a |
| 99 * [StateError]. |
| 100 * |
| 101 * If this group has a [failedTask], new tasks will be ignored, because the |
| 102 * error has already been signaled. |
| 103 */ |
| 104 void add(Future task) { |
| 105 if (_failedTask != null) return; |
| 106 if (_pending == _FINISHED) throw new StateError("Future already completed"); |
| 107 |
| 108 _pending++; |
| 109 var i = results.length; |
| 110 results.add(null); |
| 111 task.then((res) { |
| 112 results[i] = res; |
| 113 if (_failedTask != null) return; |
| 114 _pending--; |
| 115 if (_pending == 0) { |
| 116 _pending = _FINISHED; |
| 117 _completer.complete(results); |
| 118 } |
| 119 }, onError: (e) { |
| 120 if (_failedTask != null) return; |
| 121 _failedTask = task; |
| 122 _completer.completeError(e, getAttachedStackTrace(e)); |
| 123 }); |
| 124 } |
| 125 |
| 126 Future<List> get future => _completer.future; |
| 127 } |
| 128 |
| 129 |
| 130 /** |
| 131 * Escapes [text] for use in a Dart string. |
| 132 * [single] specifies single quote `'` vs double quote `"`. |
| 133 * [triple] indicates that a triple-quoted string, such as `'''` or `"""`. |
| 134 */ |
| 135 String escapeDartString(String text, {bool single: true, bool triple: false}) { |
| 136 // Note: don't allocate anything until we know we need it. |
| 137 StringBuffer result = null; |
| 138 |
| 139 for (int i = 0; i < text.length; i++) { |
| 140 int code = text.codeUnitAt(i); |
| 141 var replace = null; |
| 142 switch (code) { |
| 143 case 92/*'\\'*/: replace = r'\\'; break; |
| 144 case 36/*r'$'*/: replace = r'\$'; break; |
| 145 case 34/*'"'*/: if (!single) replace = r'\"'; break; |
| 146 case 39/*"'"*/: if (single) replace = r"\'"; break; |
| 147 case 10/*'\n'*/: if (!triple) replace = r'\n'; break; |
| 148 case 13/*'\r'*/: if (!triple) replace = r'\r'; break; |
| 149 |
| 150 // Note: we don't escape unicode characters, under the assumption that |
| 151 // writing the file in UTF-8 will take care of this. |
| 152 |
| 153 // TODO(jmesserly): do we want to replace any other non-printable |
| 154 // characters (such as \f) for readability? |
| 155 } |
| 156 |
| 157 if (replace != null && result == null) { |
| 158 result = new StringBuffer(text.substring(0, i)); |
| 159 } |
| 160 |
| 161 if (result != null) result.write(replace != null ? replace : text[i]); |
| 162 } |
| 163 |
| 164 return result == null ? text : result.toString(); |
| 165 } |
| 166 |
| 167 /** Iterates through an infinite sequence, starting from zero. */ |
| 168 class IntIterator implements Iterator<int> { |
| 169 int _next = -1; |
| 170 |
| 171 int get current => _next < 0 ? null : _next; |
| 172 |
| 173 bool moveNext() { |
| 174 _next++; |
| 175 return true; |
| 176 } |
| 177 } |
OLD | NEW |