| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Internal debugging utilities. | 5 /// Internal debugging utilities. |
| 6 library dart_style.src.debug; | 6 library dart_style.src.debug; |
| 7 | 7 |
| 8 import 'dart:math' as math; | 8 import 'dart:math' as math; |
| 9 | 9 |
| 10 import 'chunk.dart'; | 10 import 'chunk.dart'; |
| 11 import 'line_splitting/rule_set.dart'; | 11 import 'line_splitting/rule_set.dart'; |
| 12 import 'rule/rule.dart'; | |
| 13 | 12 |
| 14 /// Set this to `true` to turn on diagnostic output while building chunks. | 13 /// Set this to `true` to turn on diagnostic output while building chunks. |
| 15 bool traceChunkBuilder = false; | 14 bool traceChunkBuilder = false; |
| 16 | 15 |
| 17 /// Set this to `true` to turn on diagnostic output while writing lines. | 16 /// Set this to `true` to turn on diagnostic output while writing lines. |
| 18 bool traceLineWriter = false; | 17 bool traceLineWriter = false; |
| 19 | 18 |
| 20 /// Set this to `true` to turn on diagnostic output while line splitting. | 19 /// Set this to `true` to turn on diagnostic output while line splitting. |
| 21 bool traceSplitter = false; | 20 bool traceSplitter = false; |
| 22 | 21 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 | 60 |
| 62 /// Wraps [message] in green ANSI escape codes if enabled. | 61 /// Wraps [message] in green ANSI escape codes if enabled. |
| 63 String green(message) => "$_green$message$_none"; | 62 String green(message) => "$_green$message$_none"; |
| 64 | 63 |
| 65 /// Wraps [message] in bold ANSI escape codes if enabled. | 64 /// Wraps [message] in bold ANSI escape codes if enabled. |
| 66 String bold(message) => "$_bold$message$_none"; | 65 String bold(message) => "$_bold$message$_none"; |
| 67 | 66 |
| 68 /// Prints [chunks] to stdout, one chunk per line, with detailed information | 67 /// Prints [chunks] to stdout, one chunk per line, with detailed information |
| 69 /// about each chunk. | 68 /// about each chunk. |
| 70 void dumpChunks(int start, List<Chunk> chunks) { | 69 void dumpChunks(int start, List<Chunk> chunks) { |
| 71 if (chunks.isEmpty) return; | 70 if (chunks.skip(start).isEmpty) return; |
| 72 | 71 |
| 73 // Show the spans as vertical bands over their range. | 72 // Show the spans as vertical bands over their range (unless there are too |
| 73 // many). |
| 74 var spans = new Set(); | 74 var spans = new Set(); |
| 75 addSpans(chunks) { | 75 addSpans(chunks) { |
| 76 for (var chunk in chunks) { | 76 for (var chunk in chunks) { |
| 77 spans.addAll(chunk.spans); | 77 spans.addAll(chunk.spans); |
| 78 | 78 |
| 79 addSpans(chunk.blockChunks); | 79 if (chunk.isBlock) addSpans(chunk.block.chunks); |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 | 82 |
| 83 addSpans(chunks); | 83 addSpans(chunks); |
| 84 | 84 |
| 85 spans = spans.toList(); | 85 spans = spans.toList(); |
| 86 | 86 |
| 87 var rules = chunks | 87 var rules = |
| 88 .map((chunk) => chunk.rule) | 88 chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet(); |
| 89 .where((rule) => rule != null && rule is! HardSplitRule) | |
| 90 .toSet(); | |
| 91 | 89 |
| 92 var rows = []; | 90 var rows = []; |
| 93 | 91 |
| 94 addChunk(chunk, prefix, index) { | 92 addChunk(List<Chunk> chunks, String prefix, int index) { |
| 95 var row = []; | 93 var row = []; |
| 96 row.add("$prefix$index:"); | 94 row.add("$prefix$index:"); |
| 97 | 95 |
| 96 var chunk = chunks[index]; |
| 98 if (chunk.text.length > 70) { | 97 if (chunk.text.length > 70) { |
| 99 row.add(chunk.text.substring(0, 70)); | 98 row.add(chunk.text.substring(0, 70)); |
| 100 } else { | 99 } else { |
| 101 row.add(chunk.text); | 100 row.add(chunk.text); |
| 102 } | 101 } |
| 103 | 102 |
| 104 var spanBars = ""; | 103 if (spans.length <= 20) { |
| 105 for (var span in spans) { | 104 var spanBars = ""; |
| 106 spanBars += chunk.spans.contains(span) ? "|" : " "; | 105 for (var span in spans) { |
| 106 if (chunk.spans.contains(span)) { |
| 107 if (index == 0 || !chunks[index - 1].spans.contains(span)) { |
| 108 spanBars += "╖"; |
| 109 } else { |
| 110 spanBars += "║"; |
| 111 } |
| 112 } else { |
| 113 if (index > 0 && chunks[index - 1].spans.contains(span)) { |
| 114 spanBars += "╜"; |
| 115 } else { |
| 116 spanBars += " "; |
| 117 } |
| 118 } |
| 119 } |
| 120 row.add(spanBars); |
| 107 } | 121 } |
| 108 row.add(spanBars); | |
| 109 | 122 |
| 110 writeIf(predicate, String callback()) { | 123 writeIf(predicate, String callback()) { |
| 111 if (predicate) { | 124 if (predicate) { |
| 112 row.add(callback()); | 125 row.add(callback()); |
| 113 } else { | 126 } else { |
| 114 row.add(""); | 127 row.add(""); |
| 115 } | 128 } |
| 116 } | 129 } |
| 117 | 130 |
| 118 if (chunk.rule != null) { | 131 if (chunk.rule == null) { |
| 119 row.add(chunk.isHardSplit ? "" : chunk.rule.toString()); | 132 row.add(""); |
| 133 row.add("(no rule)"); |
| 134 row.add(""); |
| 135 } else { |
| 136 writeIf(chunk.rule.cost != 0, () => "\$${chunk.rule.cost}"); |
| 120 | 137 |
| 121 var outerRules = chunk.rule.outerRules.toSet().intersection(rules); | 138 var ruleString = chunk.rule.toString(); |
| 122 writeIf(outerRules.isNotEmpty, () => "-> ${outerRules.join(" ")}"); | 139 if (chunk.rule.isHardened) ruleString += "!"; |
| 123 } else { | 140 row.add(ruleString); |
| 124 row.add("(no rule)"); | |
| 125 | 141 |
| 126 // Outer rules. | 142 var constrainedRules = |
| 127 row.add(""); | 143 chunk.rule.constrainedRules.toSet().intersection(rules); |
| 144 writeIf(constrainedRules.isNotEmpty, |
| 145 () => "-> ${constrainedRules.join(" ")}"); |
| 128 } | 146 } |
| 129 | 147 |
| 130 writeIf(chunk.indent != null && chunk.indent != 0, | 148 writeIf(chunk.indent != null && chunk.indent != 0, |
| 131 () => "indent ${chunk.indent}"); | 149 () => "indent ${chunk.indent}"); |
| 132 | 150 |
| 133 writeIf(chunk.nesting != null && chunk.nesting != 0, | 151 writeIf(chunk.nesting != null && chunk.nesting != 0, |
| 134 () => "nest ${chunk.nesting}"); | 152 () => "nest ${chunk.nesting}"); |
| 135 | 153 |
| 136 writeIf(chunk.flushLeft != null && chunk.flushLeft, () => "flush"); | 154 writeIf(chunk.flushLeft != null && chunk.flushLeft, () => "flush"); |
| 137 | 155 |
| 156 writeIf(chunk.canDivide, () => "divide"); |
| 157 |
| 138 rows.add(row); | 158 rows.add(row); |
| 139 | 159 |
| 140 for (var j = 0; j < chunk.blockChunks.length; j++) { | 160 if (chunk.isBlock) { |
| 141 addChunk(chunk.blockChunks[j], "$prefix$index.", j); | 161 for (var j = 0; j < chunk.block.chunks.length; j++) { |
| 162 addChunk(chunk.block.chunks, "$prefix$index.", j); |
| 163 } |
| 142 } | 164 } |
| 143 } | 165 } |
| 144 | 166 |
| 145 var i = start; | 167 for (var i = start; i < chunks.length; i++) { |
| 146 for (var chunk in chunks) { | 168 addChunk(chunks, "", i); |
| 147 addChunk(chunk, "", i); | |
| 148 i++; | |
| 149 } | 169 } |
| 150 | 170 |
| 151 var rowWidths = new List.filled(rows.first.length, 0); | 171 var rowWidths = new List.filled(rows.first.length, 0); |
| 152 for (var row in rows) { | 172 for (var row in rows) { |
| 153 for (var i = 0; i < row.length; i++) { | 173 for (var i = 0; i < row.length; i++) { |
| 154 rowWidths[i] = math.max(rowWidths[i], row[i].length); | 174 rowWidths[i] = math.max(rowWidths[i], row[i].length); |
| 155 } | 175 } |
| 156 } | 176 } |
| 157 | 177 |
| 158 var buffer = new StringBuffer(); | 178 var buffer = new StringBuffer(); |
| 159 for (var row in rows) { | 179 for (var row in rows) { |
| 160 for (var i = 0; i < row.length; i++) { | 180 for (var i = 0; i < row.length; i++) { |
| 161 var cell = row[i].padRight(rowWidths[i]); | 181 var cell = row[i].padRight(rowWidths[i]); |
| 162 | 182 |
| 163 if (i != 1) cell = gray(cell); | 183 if (i != 1) cell = gray(cell); |
| 164 | 184 |
| 165 buffer.write(cell); | 185 buffer.write(cell); |
| 166 buffer.write(" "); | 186 buffer.write(" "); |
| 167 } | 187 } |
| 168 | 188 |
| 169 buffer.writeln(); | 189 buffer.writeln(); |
| 170 } | 190 } |
| 171 | 191 |
| 172 print(buffer.toString()); | 192 print(buffer.toString()); |
| 173 } | 193 } |
| 174 | 194 |
| 195 /// Shows all of the constraints between the rules used by [chunks]. |
| 196 void dumpConstraints(List<Chunk> chunks) { |
| 197 var rules = |
| 198 chunks.map((chunk) => chunk.rule).where((rule) => rule != null).toSet(); |
| 199 |
| 200 for (var rule in rules) { |
| 201 var constrainedValues = []; |
| 202 for (var value = 0; value < rule.numValues; value++) { |
| 203 var constraints = []; |
| 204 for (var other in rules) { |
| 205 if (rule == other) continue; |
| 206 |
| 207 var constraint = rule.constrain(value, other); |
| 208 if (constraint != null) { |
| 209 constraints.add("$other->$constraint"); |
| 210 } |
| 211 } |
| 212 |
| 213 if (constraints.isNotEmpty) { |
| 214 constrainedValues.add("$value:(${constraints.join(' ')})"); |
| 215 } |
| 216 } |
| 217 |
| 218 log("$rule ${constrainedValues.join(' ')}"); |
| 219 } |
| 220 } |
| 221 |
| 175 /// Convert the line to a [String] representation. | 222 /// Convert the line to a [String] representation. |
| 176 /// | 223 /// |
| 177 /// It will determine how best to split it into multiple lines of output and | 224 /// It will determine how best to split it into multiple lines of output and |
| 178 /// return a single string that may contain one or more newline characters. | 225 /// return a single string that may contain one or more newline characters. |
| 179 void dumpLines(List<Chunk> chunks, int firstLineIndent, SplitSet splits) { | 226 void dumpLines(List<Chunk> chunks, int firstLineIndent, SplitSet splits) { |
| 180 var buffer = new StringBuffer(); | 227 var buffer = new StringBuffer(); |
| 181 | 228 |
| 182 writeIndent(indent) => buffer.write(gray("| " * (indent ~/ 2))); | 229 writeIndent(indent) => buffer.write(gray("| " * (indent ~/ 2))); |
| 183 | 230 |
| 184 writeChunksUnsplit(List<Chunk> chunks) { | 231 writeChunksUnsplit(List<Chunk> chunks) { |
| 185 for (var chunk in chunks) { | 232 for (var chunk in chunks) { |
| 186 buffer.write(chunk.text); | 233 buffer.write(chunk.text); |
| 187 if (chunk.spaceWhenUnsplit) buffer.write(" "); | 234 if (chunk.spaceWhenUnsplit) buffer.write(" "); |
| 188 | 235 |
| 189 // Recurse into the block. | 236 // Recurse into the block. |
| 190 writeChunksUnsplit(chunk.blockChunks); | 237 if (chunk.isBlock) writeChunksUnsplit(chunk.block.chunks); |
| 191 } | 238 } |
| 192 } | 239 } |
| 193 | 240 |
| 194 writeIndent(firstLineIndent); | 241 writeIndent(firstLineIndent); |
| 195 | 242 |
| 196 for (var i = 0; i < chunks.length - 1; i++) { | 243 for (var i = 0; i < chunks.length - 1; i++) { |
| 197 var chunk = chunks[i]; | 244 var chunk = chunks[i]; |
| 198 buffer.write(chunk.text); | 245 buffer.write(chunk.text); |
| 199 | 246 |
| 200 if (splits.shouldSplitAt(i)) { | 247 if (splits.shouldSplitAt(i)) { |
| 201 for (var j = 0; j < (chunk.isDouble ? 2 : 1); j++) { | 248 for (var j = 0; j < (chunk.isDouble ? 2 : 1); j++) { |
| 202 buffer.writeln(); | 249 buffer.writeln(); |
| 203 writeIndent(splits.getColumn(i)); | 250 writeIndent(splits.getColumn(i)); |
| 204 } | 251 } |
| 205 } else { | 252 } else { |
| 206 writeChunksUnsplit(chunk.blockChunks); | 253 if (chunk.isBlock) writeChunksUnsplit(chunk.block.chunks); |
| 207 | 254 |
| 208 if (chunk.spaceWhenUnsplit) buffer.write(" "); | 255 if (chunk.spaceWhenUnsplit) buffer.write(" "); |
| 209 } | 256 } |
| 210 } | 257 } |
| 211 | 258 |
| 212 buffer.write(chunks.last.text); | 259 buffer.write(chunks.last.text); |
| 213 log(buffer); | 260 log(buffer); |
| 214 } | 261 } |
| 215 | 262 |
| 216 String _color(String ansiEscape) => useAnsiColors ? ansiEscape : ""; | 263 String _color(String ansiEscape) => useAnsiColors ? ansiEscape : ""; |
| OLD | NEW |