log static method

void log(
  1. String? title
)

The main log method to print styled debugging information.

Only runs in debug mode. Captures the file, method, and line number where Bugger.log() is called and formats it in a table.

Implementation

static void log(String? title) {
  // Return early if not in debug mode (to avoid logs in production)
  if (!kDebugMode) return;

  /// Get current stack trace (skip 1 frame to get caller)
  final trace = Trace.current(1);

  /// Find the frame that is not from the Bugger class itself
  final frame = trace.frames.firstWhere(
        (f) => !f.uri.toString().contains('bugger'),
    orElse: () => trace.frames.first,
  );

  /// Extracting debug info from the selected frame
  final filePath = frame.uri.toString();
  final fileName = frame.uri.pathSegments.isNotEmpty
      ? frame.uri.pathSegments.last
      : 'unknown';
  final line = frame.line ?? 0;
  final method = frame.member ?? 'unknown';

  /// Key-value pairs to show in the log table
  final rows = [
    ["πŸ“ Issue", title],
    ["πŸ“„ File", fileName],
    ["πŸ“Œ Line", "$line"],
    ["πŸ”§ Method", method],
    ["πŸ”— Location", "$filePath : At line - $line"],
    ["🌐 GitHub", "https://github.com/rahmanprofile/bugger.git"],
  ];

  /// Get the maximum width of the 'Field' column
  final fieldWidth = rows.fold(
    0,
        (w, r) => r[0]!.length > w ? r[0]!.length : w,
  );

  /// Utility to wrap long text into multiple lines based on max width
  List<String> wrapValue(String value) {
    if (value.length <= maxValueWidth) return [value];
    final lines = <String>[];
    int start = 0;
    while (start < value.length) {
      int end = (start + maxValueWidth < value.length)
          ? start + maxValueWidth
          : value.length;
      lines.add(value.substring(start, end));
      start = end;
    }
    return lines;
  }

  /// Wraps all rows and aligns extra lines with blank keys
  List<List<String>> wrapRows() {
    final wrapped = <List<String>>[];
    for (var row in rows) {
      final key = row[0];
      final lines = wrapValue(row[1]!);
      for (int i = 0; i < lines.length; i++) {
        if (i == 0) {
          wrapped.add([key!, lines[i]]);
        } else {
          wrapped.add(['', lines[i]]);
        }
      }
    }
    return wrapped;
  }

  /// Get wrapped rows with aligned keys and values
  final processedRows = wrapRows();

  /// Get the maximum width for the value column
  final valueWidth = processedRows.fold(
    0,
        (w, r) => r[1].length > w ? r[1].length : w,
  );

  /// Draw a single table row using padding and a separator
  String drawRow(List<String> cols, String sep) =>
      '$sep ${cols[0].padRight(fieldWidth)} $sep ${cols[1].padRight(valueWidth)} $sep';

  /// Building the top, header, divider, body, and bottom of the table
  final top = 'β•”${'═' * (fieldWidth + 2)}╦${'═' * (valueWidth + 2)}β•—';
  final header = drawRow(["Field", "Value - [Bugger Detection]"], 'β•‘');
  final divider = 'β• ${'═' * (fieldWidth + 2)}╬${'═' * (valueWidth + 2)}β•£';
  final data = processedRows.map((row) => drawRow(row, 'β•‘')).join('\n');
  final bottom = 'β•š${'═' * (fieldWidth + 2)}β•©${'═' * (valueWidth + 2)}╝';

  /// Combine everything with colors and print to debug console
  final table = '''
$borderColor$top
$borderColor$header
$borderColor$divider
$infoColor$data
$borderColor$bottom$reset
''';

  /// Print to debug console only (debugPrint avoids overflow)
  debugPrint(table);
}