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 |