Repository: flutter
Issue: [flutter_markdown] New lines (`\n`) do not behave as expected.
Labels: package,team-ecosystem,has reproducible steps,P2,p: flutter_markdown,triaged-ecosystem,found in release: 3.27,found in release: 3.28

### The problems
- `\n` by itself doesn't work inside the markdown widget unless there are 2 spaces before it like `  \n`.
- `\n\n\n` and `\n\n\n\n` (3, 4, or more) show the same as `\n\n`

### Steps to reproduce

~~~Dart
MarkdownBody(
  data: """
Testing123 test123\nTesting123 test123  \nTesting123 test123\n\nTesting123 test123  \n\nTesting123 test123\n\n\nTesting123  \n\n\nTesting123 test123
```
code snippet here
asdasdad
```
asdasd
# Hi
asdasd\n\n\n\ntest
""",
);
~~~

<details>
<summary>Note<strong> (click to expand)</strong></summary>

Sorry, in the example images below, the colours might be different to yours because I also set the `Markdown` widget's `style` parameter to:
```Dart
final style = MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
  p: Theme.of(context).textTheme.bodyMedium?.apply(
        color: Theme.of(context).colorScheme.primary,
      ),
);
```

Also, I haven't tested on mobile, this is Flutter web.
</details>

### Expected results

![image](https://github.com/user-attachments/assets/474fb50c-10a9-44e3-8baa-f1054efc98a2)


### Actual results

![image](https://github.com/user-attachments/assets/874bdf77-e716-4310-bca1-a78380b88f0e)


### My temporary fix

~~~Dart
MarkdownBody(
  data: """
Testing123 test123\nTesting123 test123  \nTesting123 test123\n\nTesting123 test123  \n\nTesting123 test123\n\n\nTesting123  \n\n\nTesting123 test123
```
code snippet here
asdasdad
```
asdasd
# Hi
asdasd\n\n\n\ntest
""",
);

String _fixMarkdownNewLines(String data) {
  final codeBlockPattern =
      RegExp(r'```.*?```', dotAll: true); // Matches code blocks
  final nonCodeBlocks = <String>[];
  final codeBlocks = <String>[];

  // Split data into segments of code blocks and non-code blocks
  final matches = codeBlockPattern.allMatches(data);
  int lastMatchEnd = 0;

  for (final match in matches) {
    // Add text before the code block as a non-code block
    if (match.start > lastMatchEnd) {
      nonCodeBlocks.add(data.substring(lastMatchEnd, match.start));
    }
    // Add the code block itself
    codeBlocks.add(data.substring(match.start, match.end));
    lastMatchEnd = match.end;
  }

  // Add any remaining non-code block text
  if (lastMatchEnd < data.length) {
    nonCodeBlocks.add(data.substring(lastMatchEnd));
  }

  // Process non-code blocks (using \u200B as a temporary hack to show new lines):
  final processedNonCodeBlocks = nonCodeBlocks.map((block) {
    return block
        .replaceAll(
            '\n\n\n\n', '\n\n\n\u200B\n') // First replace quadruple newlines
        .replaceAll('\n\n\n', '\n\n\u200B\n') // Then replace triple newlines
        .replaceAll('\n', '  \n'); // Then replace single newlines
  }).toList();

  // Combine processed non-code blocks and code blocks back together
  final buffer = StringBuffer();
  int codeIndex = 0, nonCodeIndex = 0;

  for (final _ in matches) {
    if (nonCodeIndex < processedNonCodeBlocks.length) {
      buffer.write(processedNonCodeBlocks[nonCodeIndex++]);
    }
    if (codeIndex < codeBlocks.length) {
      buffer.write(codeBlocks[codeIndex++]);
    }
  }

  // Add any remaining non-code block
  if (nonCodeIndex < processedNonCodeBlocks.length) {
    buffer.write(processedNonCodeBlocks[nonCodeIndex]);
  }

  return buffer.toString();
}
~~~