diff --git a/example/format.dart b/example/format.dart index caaa5d1d..94ed2237 100644 --- a/example/format.dart +++ b/example/format.dart @@ -15,6 +15,9 @@ void main(List args) { debug.useAnsiColors = true; debug.tracePieceBuilder = true; debug.traceSolver = true; + debug.traceSolverEnqueing = true; + debug.traceSolverDequeing = true; + debug.traceSolverShowCode = true; _formatStmt(''' 1 + 2; diff --git a/lib/src/back_end/code.dart b/lib/src/back_end/code.dart index addd1831..9f4e5af1 100644 --- a/lib/src/back_end/code.dart +++ b/lib/src/back_end/code.dart @@ -16,8 +16,9 @@ import '../source_code.dart'; /// as fast simply appending a single [GroupCode] to the parent solution's /// [GroupCode]. sealed class Code { - /// Traverse the [Code] tree and generate a string for debugging purposes. - String toDebugString() { + /// Traverse the [Code] tree and generate a string showing the [Code] tree's + /// structure for debugging purposes. + String toCodeTree() { var buffer = StringBuffer(); var prefix = ''; @@ -55,6 +56,14 @@ sealed class Code { return buffer.toString(); } + + /// Write the [Code] to a string of output code, ignoring selection and + /// format on/off markers. + String toDebugString() { + var builder = _DebugStringBuilder(); + builder.traverse(this); + return builder.finish(); + } } /// A [Code] object which can be written to and contain other child [Code] @@ -376,3 +385,43 @@ final class _StringBuilder { selectionLength: selectionLength); } } + +/// Traverses a [Code] tree and produces a string of output code, ignoring +/// selection and format on/off markers. +/// +/// This is a simpler version of [_StringBuilder] that doesn't require having +/// access to the original [SourceCode] and line ending. +final class _DebugStringBuilder { + final StringBuffer _buffer = StringBuffer(); + + /// How many spaces of indentation should be written before the next text. + int _indent = 0; + + void traverse(Code code) { + switch (code) { + case _NewlineCode(): + _buffer.writeln(); + if (code._blank) _buffer.writeln(); + _indent = code._indent; + + case _TextCode(): + // Write any pending indentation. + _buffer.write(' ' * _indent); + _indent = 0; + _buffer.write(code._text); + + case GroupCode(): + _indent = code._indent; + for (var i = 0; i < code._children.length; i++) { + traverse(code._children[i]); + } + + case _MarkerCode(): + case _EnableFormattingCode(): + // The debug output doesn't support disabled formatting or selections. + break; + } + } + + String finish() => _buffer.toString(); +} diff --git a/lib/src/back_end/solver.dart b/lib/src/back_end/solver.dart index ce2a344c..f5fd5236 100644 --- a/lib/src/back_end/solver.dart +++ b/lib/src/back_end/solver.dart @@ -90,6 +90,14 @@ final class Solver { _queue.add(solution); Profile.end('Solver enqueue'); + if (debug.traceSolverEnqueing) { + debug.log(debug.bold('Enqueue initial $solution')); + if (debug.traceSolverShowCode) { + debug.log(solution.code.toDebugString()); + debug.log(''); + } + } + // The lowest cost solution found so far that does overflow. var best = solution; @@ -101,10 +109,12 @@ final class Solver { attempts++; - if (debug.traceSolver) { + if (debug.traceSolverDequeing) { debug.log(debug.bold('Try #$attempts $solution')); - debug.log(solution.code.toDebugString()); - debug.log(''); + if (debug.traceSolverShowCode) { + debug.log(solution.code.toDebugString()); + debug.log(''); + } } if (solution.isValid) { @@ -127,6 +137,14 @@ final class Solver { pageWidth: _pageWidth, leadingIndent: _leadingIndent)) { Profile.count('Solver enqueue'); _queue.add(expanded); + + if (debug.traceSolverEnqueing) { + debug.log(debug.bold('Enqueue $expanded')); + if (debug.traceSolverShowCode) { + debug.log(expanded.code.toDebugString()); + debug.log(''); + } + } } } diff --git a/lib/src/debug.dart b/lib/src/debug.dart index 5d3999a8..f07289ec 100644 --- a/lib/src/debug.dart +++ b/lib/src/debug.dart @@ -26,6 +26,18 @@ bool tracePieceBuilder = false; /// Set this to `true` to turn on diagnostic output while solving pieces. bool traceSolver = false; +/// Set this to `true` to turn on diagnostic output when the solver enqueues a +/// potential solution. +bool traceSolverEnqueing = false; + +/// Set this to `true` to turn on diagnostic output when the solver dequeues a +/// potential solution. +bool traceSolverDequeing = false; + +/// Set this to `true` to show the formatted code for a given solution when the +/// solver it printing diagnostic output. +bool traceSolverShowCode = false; + bool useAnsiColors = false; const unicodeSection = '\u00a7';