Coverage report for lib/src/debug.dart

Line coverage: 1 / 113 (0.9%)

All files > lib/src/debug.dart

1
// Copyright (c) 2014, 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
/// Internal debugging utilities.
6
library dart_style.src.debug;
7
8
import 'dart:math' as math;
9
10
import 'chunk.dart';
11
import 'line_splitting/rule_set.dart';
12
13
/// Set this to `true` to turn on diagnostic output while building chunks.
14
bool traceChunkBuilder = false;
15
16
/// Set this to `true` to turn on diagnostic output while writing lines.
17
bool traceLineWriter = false;
18
19
/// Set this to `true` to turn on diagnostic output while line splitting.
20
bool traceSplitter = false;
21
22
bool useAnsiColors = false;
23
24
const unicodeSection = "\u00a7";
25
const unicodeMidDot = "\u00b7";
26
27
/// The whitespace prefixing each line of output.
28
String _indent = "";
29
300
void indent() {
310
  _indent = "  $_indent";
32
}
33
340
void unindent() {
350
  _indent = _indent.substring(2);
36
}
37
38
/// Constants for ANSI color escape codes.
39
final _gray = _color("\u001b[1;30m");
40
final _green = _color("\u001b[32m");
41
final _none = _color("\u001b[0m");
42
final _bold = _color("\u001b[1m");
43
44
/// Prints [message] to stdout with each line correctly indented.
450
void log([message]) {
46
  if (message == null) {
470
    print("");
48
    return;
49
  }
50
510
  print(_indent + message.toString().replaceAll("\n", "\n$_indent"));
52
}
53
54
/// Wraps [message] in gray ANSI escape codes if enabled.
550
String gray(message) => "$_gray$message$_none";
56
57
/// Wraps [message] in green ANSI escape codes if enabled.
580
String green(message) => "$_green$message$_none";
59
60
/// Wraps [message] in bold ANSI escape codes if enabled.
610
String bold(message) => "$_bold$message$_none";
62
63
/// Prints [chunks] to stdout, one chunk per line, with detailed information
64
/// about each chunk.
650
void dumpChunks(int start, List<Chunk> chunks) {
660
  if (chunks.skip(start).isEmpty) return;
67
68
  // Show the spans as vertical bands over their range (unless there are too
69
  // many).
700
  var spanSet = new Set<Span>();
710
  addSpans(List<Chunk> chunks) {
720
    for (var chunk in chunks) {
730
      spanSet.addAll(chunk.spans);
74
750
      if (chunk.isBlock) addSpans(chunk.block.chunks);
76
    }
77
  }
78
790
  addSpans(chunks);
80
810
  var spans = spanSet.toList();
82
  var rules =
830
      chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet();
84
850
  var rows = <List<String>>[];
86
870
  addChunk(List<Chunk> chunks, String prefix, int index) {
880
    var row = <String>[];
890
    row.add("$prefix$index:");
90
910
    var chunk = chunks[index];
920
    if (chunk.text.length > 70) {
930
      row.add(chunk.text.substring(0, 70));
94
    } else {
950
      row.add(chunk.text);
96
    }
97
980
    if (spans.length <= 20) {
99
      var spanBars = "";
1000
      for (var span in spans) {
1010
        if (chunk.spans.contains(span)) {
1020
          if (index == 0 || !chunks[index - 1].spans.contains(span)) {
1030
            if (span.cost == 1) {
1040
              spanBars += "╖";
105
            } else {
1060
              spanBars += span.cost.toString();
107
            }
108
          } else {
1090
            spanBars += "║";
110
          }
111
        } else {
1120
          if (index > 0 && chunks[index - 1].spans.contains(span)) {
1130
            spanBars += "╜";
114
          } else {
1150
            spanBars += " ";
116
          }
117
        }
118
      }
1190
      row.add(spanBars);
120
    }
121
1220
    writeIf(predicate, String callback()) {
123
      if (predicate) {
1240
        row.add(callback());
125
      } else {
1260
        row.add("");
127
      }
128
    }
129
1300
    if (chunk.rule == null) {
1310
      row.add("");
1320
      row.add("(no rule)");
1330
      row.add("");
134
    } else {
1350
      writeIf(chunk.rule.cost != 0, () => "\$${chunk.rule.cost}");
136
1370
      var ruleString = chunk.rule.toString();
1380
      if (chunk.rule.isHardened) ruleString += "!";
1390
      row.add(ruleString);
140
141
      var constrainedRules =
1420
          chunk.rule.constrainedRules.toSet().intersection(rules);
1430
      writeIf(constrainedRules.isNotEmpty,
1440
          () => "-> ${constrainedRules.join(" ")}");
145
    }
146
1470
    writeIf(chunk.indent != null && chunk.indent != 0,
1480
        () => "indent ${chunk.indent}");
149
1500
    writeIf(chunk.nesting != null && chunk.nesting.indent != 0,
1510
        () => "nest ${chunk.nesting}");
152
1530
    writeIf(chunk.flushLeft != null && chunk.flushLeft, () => "flush");
154
1550
    writeIf(chunk.canDivide, () => "divide");
156
1570
    rows.add(row);
158
1590
    if (chunk.isBlock) {
1600
      for (var j = 0; j < chunk.block.chunks.length; j++) {
1610
        addChunk(chunk.block.chunks, "$prefix$index.", j);
162
      }
163
    }
164
  }
165
1660
  for (var i = start; i < chunks.length; i++) {
1670
    addChunk(chunks, "", i);
168
  }
169
1700
  var rowWidths = new List.filled(rows.first.length, 0);
1710
  for (var row in rows) {
1720
    for (var i = 0; i < row.length; i++) {
1735
      rowWidths[i] = math.max(rowWidths[i], row[i].length);
174
    }
175
  }
176
1770
  var buffer = new StringBuffer();
1780
  for (var row in rows) {
1790
    for (var i = 0; i < row.length; i++) {
1800
      var cell = row[i].padRight(rowWidths[i]);
181
1820
      if (i != 1) cell = gray(cell);
183
1840
      buffer.write(cell);
1850
      buffer.write("  ");
186
    }
187
1880
    buffer.writeln();
189
  }
190
1910
  print(buffer.toString());
192
}
193
194
/// Shows all of the constraints between the rules used by [chunks].
1950
void dumpConstraints(List<Chunk> chunks) {
196
  var rules =
1970
      chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet();
198
1990
  for (var rule in rules) {
2000
    var constrainedValues = [];
2010
    for (var value = 0; value < rule.numValues; value++) {
2020
      var constraints = [];
2030
      for (var other in rules) {
2040
        if (rule == other) continue;
205
2060
        var constraint = rule.constrain(value, other);
207
        if (constraint != null) {
2080
          constraints.add("$other->$constraint");
209
        }
210
      }
211
2120
      if (constraints.isNotEmpty) {
2130
        constrainedValues.add("$value:(${constraints.join(' ')})");
214
      }
215
    }
216
2170
    log("$rule ${constrainedValues.join(' ')}");
218
  }
219
}
220
221
/// Convert the line to a [String] representation.
222
///
223
/// It will determine how best to split it into multiple lines of output and
224
/// return a single string that may contain one or more newline characters.
2250
void dumpLines(List<Chunk> chunks, int firstLineIndent, SplitSet splits) {
2260
  var buffer = new StringBuffer();
227
2280
  writeIndent(indent) => buffer.write(gray("| " * (indent ~/ 2)));
229
2300
  writeChunksUnsplit(List<Chunk> chunks) {
2310
    for (var chunk in chunks) {
2320
      buffer.write(chunk.text);
2330
      if (chunk.spaceWhenUnsplit) buffer.write(" ");
234
235
      // Recurse into the block.
2360
      if (chunk.isBlock) writeChunksUnsplit(chunk.block.chunks);
237
    }
238
  }
239
2400
  writeIndent(firstLineIndent);
241
2420
  for (var i = 0; i < chunks.length - 1; i++) {
2430
    var chunk = chunks[i];
2440
    buffer.write(chunk.text);
245
2460
    if (splits.shouldSplitAt(i)) {
2470
      for (var j = 0; j < (chunk.isDouble ? 2 : 1); j++) {
2480
        buffer.writeln();
2490
        writeIndent(splits.getColumn(i));
250
      }
251
    } else {
2520
      if (chunk.isBlock) writeChunksUnsplit(chunk.block.chunks);
253
2540
      if (chunk.spaceWhenUnsplit) buffer.write(" ");
255
    }
256
  }
257
2580
  buffer.write(chunks.last.text);
2590
  log(buffer);
260
}
261
2620
String _color(String ansiEscape) => useAnsiColors ? ansiEscape : "";