| Index: pkg/stack_trace/lib/src/trace.dart
|
| diff --git a/pkg/stack_trace/lib/src/trace.dart b/pkg/stack_trace/lib/src/trace.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1ab7695b996d279b8115e243e89007ae68fa7c53
|
| --- /dev/null
|
| +++ b/pkg/stack_trace/lib/src/trace.dart
|
| @@ -0,0 +1,127 @@
|
| +// Copyright (c) 2013, 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.
|
| +
|
| +library trace;
|
| +
|
| +import 'dart:uri';
|
| +
|
| +import 'frame.dart';
|
| +
|
| +final _patchRegExp = new RegExp(r"-patch$");
|
| +
|
| +/// A stack trace, comprised of a list of stack frames.
|
| +class Trace implements StackTrace {
|
| + // TODO(nweiz): make this read-only once issue 8321 is fixed.
|
| + /// The stack frames that comprise this stack trace.
|
| + final List<Frame> frames;
|
| +
|
| + /// Returns a human-readable representation of [stackTrace]. If [terse] is
|
| + /// set, this folds together multiple stack frames from the Dart core
|
| + /// libraries, so that only the core library method directly called from user
|
| + /// code is visible (see [Trace.terse]).
|
| + static String format(StackTrace stackTrace, {bool terse: true}) {
|
| + var trace = new Trace.from(stackTrace);
|
| + if (terse) trace = trace.terse;
|
| + return trace.toString();
|
| + }
|
| +
|
| + /// Returns the current stack trace.
|
| + ///
|
| + /// By default, the first frame of this trace will be the line where
|
| + /// [Trace.current] is called. If [level] is passed, the trace will start that
|
| + /// many frames up instead.
|
| + factory Trace.current([int level=0]) {
|
| + if (level < 0) {
|
| + throw new ArgumentError("Argument [level] must be greater than or equal "
|
| + "to 0.");
|
| + }
|
| +
|
| + try {
|
| + throw '';
|
| + } catch (_, nativeTrace) {
|
| + var trace = new Trace.from(nativeTrace);
|
| + return new Trace(trace.frames.skip(level + 1));
|
| + }
|
| + }
|
| +
|
| + /// Returns a new stack trace containing the same data as [trace].
|
| + ///
|
| + /// If [trace] is a native [StackTrace], its data will be parsed out; if it's
|
| + /// a [Trace], it will be returned as-is.
|
| + factory Trace.from(StackTrace trace) {
|
| + if (trace is Trace) return trace;
|
| + return new Trace.parse(trace.fullStackTrace);
|
| + }
|
| +
|
| + /// Parses a string representation of a stack trace.
|
| + ///
|
| + /// [trace] should be formatted in the same way as native stack traces.
|
| + Trace.parse(String trace)
|
| + : this(trace.trim().split("\n").map((line) => new Frame.parse(line)));
|
| +
|
| + /// Returns a new [Trace] comprised of [frames].
|
| + Trace(Iterable<Frame> frames)
|
| + : frames = frames.toList();
|
| +
|
| + // TODO(nweiz): Keep track of which [Frame]s are part of the partial stack
|
| + // trace and only print them.
|
| + /// Returns a string representation of this stack trace.
|
| + ///
|
| + /// This is identical to [toString]. It will not be formatted in the manner of
|
| + /// native stack traces.
|
| + String get stackTrace => toString();
|
| +
|
| + /// Returns a string representation of this stack trace.
|
| + ///
|
| + /// This is identical to [toString]. It will not be formatted in the manner of
|
| + /// native stack traces.
|
| + String get fullStackTrace => toString();
|
| +
|
| + /// Returns a terser version of [this]. This is accomplished by folding
|
| + /// together multiple stack frames from the core library. If multiple such
|
| + /// frames appear in a row, only the last (the one directly called by user
|
| + /// code) is kept. Core library patches are also renamed to remove their
|
| + /// `-patch` suffix.
|
| + Trace get terse {
|
| + var newFrames = <Frame>[];
|
| + for (var frame in frames.reversed) {
|
| + if (!frame.isCore) {
|
| + newFrames.add(frame);
|
| + } else if (newFrames.isEmpty || !newFrames.last.isCore) {
|
| + var library = frame.library.replaceAll(_patchRegExp, '');
|
| + newFrames.add(new Frame(
|
| + Uri.parse(library), frame.line, frame.column, frame.member));
|
| + }
|
| + }
|
| +
|
| + return new Trace(newFrames.reversed);
|
| + }
|
| +
|
| + /// Returns a human-readable string representation of [this].
|
| + String toString() {
|
| + if (frames.length == '') return '';
|
| +
|
| + // Figure out the longest path so we know how much to pad.
|
| + var longest = frames.map((frame) => frame.location.length).max();
|
| +
|
| + // Print out the stack trace nicely formatted.
|
| + return frames.map((frame) {
|
| + return '${_padRight(frame.location, longest)} ${frame.member}\n';
|
| + }).join();
|
| + }
|
| +}
|
| +
|
| +/// Returns [string] with enough spaces added to the end to make it [length]
|
| +/// characters long.
|
| +String _padRight(String string, int length) {
|
| + if (string.length >= length) return string;
|
| +
|
| + var result = new StringBuffer();
|
| + result.write(string);
|
| + for (var i = 0; i < length - string.length; i++) {
|
| + result.write(' ');
|
| + }
|
| +
|
| + return result.toString();
|
| +}
|
|
|