[flutter_markdown] Fix mergeInlineChildren when first span is not a TextSpan (#365)

diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md
index 521aee5..d32ccb1 100644
--- a/packages/flutter_markdown/CHANGELOG.md
+++ b/packages/flutter_markdown/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.4
+
+ * Fix merging of spans when first span is not a TextSpan
+
 ## 0.6.3
 
  * Fixed `onTap`, now the changed hyperlinks are reflected even with keeping the same link name unchanged.
diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart
index 1e0da20..7d8e91e 100644
--- a/packages/flutter_markdown/lib/src/builder.dart
+++ b/packages/flutter_markdown/lib/src/builder.dart
@@ -623,7 +623,11 @@
         final RichText previous = mergedTexts.removeLast() as RichText;
         final TextSpan previousTextSpan = previous.text as TextSpan;
         final List<TextSpan> children = previousTextSpan.children != null
-            ? List<TextSpan>.from(previousTextSpan.children!)
+            ? previousTextSpan.children!
+                .map((InlineSpan span) => span is! TextSpan
+                    ? TextSpan(children: <InlineSpan>[span])
+                    : span)
+                .toList()
             : <TextSpan>[previousTextSpan];
         children.add(child.text as TextSpan);
         final TextSpan? mergedSpan = _mergeSimilarTextSpans(children);
diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml
index 2d87412..96b7b08 100644
--- a/packages/flutter_markdown/pubspec.yaml
+++ b/packages/flutter_markdown/pubspec.yaml
@@ -4,7 +4,7 @@
   formatted with simple Markdown tags.
 repository: https://github.com/flutter/packages/tree/master/packages/flutter_markdown
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_markdown%22
-version: 0.6.3
+version: 0.6.4
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/flutter_markdown/test/custom_syntax_test.dart b/packages/flutter_markdown/test/custom_syntax_test.dart
index c7f5c5b..7fee7ce 100644
--- a/packages/flutter_markdown/test/custom_syntax_test.dart
+++ b/packages/flutter_markdown/test/custom_syntax_test.dart
@@ -7,6 +7,7 @@
 import 'package:flutter_markdown/flutter_markdown.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:markdown/markdown.dart' as md;
+
 import 'utils.dart';
 
 void main() => defineTests();
@@ -58,7 +59,59 @@
         expect(span.recognizer.runtimeType, equals(TapGestureRecognizer));
       },
     );
+
+    testWidgets(
+      'WidgetSpan in RichText is handled correctly',
+      (WidgetTester tester) async {
+        await tester.pumpWidget(
+          boilerplate(
+            Markdown(
+              data: 'container is a widget that allows to customize its child',
+              extensionSet: md.ExtensionSet.none,
+              inlineSyntaxes: <md.InlineSyntax>[ContainerSyntax()],
+              builders: <String, MarkdownElementBuilder>{
+                'container': ContainerBuilder(),
+              },
+            ),
+          ),
+        );
+
+        final RichText textWidget = tester.widget(find.byType(RichText));
+        final TextSpan span =
+            (textWidget.text as TextSpan).children![0] as TextSpan;
+        final WidgetSpan widgetSpan = span.children![0] as WidgetSpan;
+        expect(widgetSpan.child, isInstanceOf<Container>());
+      },
+    );
   });
+
+  testWidgets(
+    'TextSpan and WidgetSpan as children in RichText are handled correctly',
+    (WidgetTester tester) async {
+      await tester.pumpWidget(
+        boilerplate(
+          Markdown(
+            data: 'this test replaces a string with a container',
+            extensionSet: md.ExtensionSet.none,
+            inlineSyntaxes: <md.InlineSyntax>[ContainerSyntax()],
+            builders: <String, MarkdownElementBuilder>{
+              'container': ContainerBuilder2(),
+            },
+          ),
+        ),
+      );
+
+      final RichText textWidget = tester.widget(find.byType(RichText));
+      final TextSpan textSpan = textWidget.text as TextSpan;
+      final TextSpan start = textSpan.children![0] as TextSpan;
+      expect(start.text, 'this test replaces a string with a ');
+      final TextSpan end = textSpan.children![1] as TextSpan;
+      final TextSpan foo = end.children![0] as TextSpan;
+      expect(foo.text, 'foo');
+      final WidgetSpan widgetSpan = end.children![1] as WidgetSpan;
+      expect(widgetSpan.child, isInstanceOf<Container>());
+    },
+  );
 }
 
 class SubscriptSyntax extends md.InlineSyntax {
@@ -126,3 +179,48 @@
     );
   }
 }
+
+class ContainerSyntax extends md.InlineSyntax {
+  ContainerSyntax() : super(_pattern);
+
+  static const String _pattern = 'container';
+
+  @override
+  bool onMatch(md.InlineParser parser, Match match) {
+    parser.addNode(
+      md.Element.text('container', ''),
+    );
+    return true;
+  }
+}
+
+class ContainerBuilder extends MarkdownElementBuilder {
+  @override
+  Widget? visitElementAfter(md.Element element, _) {
+    return RichText(
+      text: TextSpan(
+        children: <InlineSpan>[
+          WidgetSpan(
+            child: Container(),
+          ),
+        ],
+      ),
+    );
+  }
+}
+
+class ContainerBuilder2 extends MarkdownElementBuilder {
+  @override
+  Widget? visitElementAfter(md.Element element, _) {
+    return RichText(
+      text: TextSpan(
+        children: <InlineSpan>[
+          const TextSpan(text: 'foo'),
+          WidgetSpan(
+            child: Container(),
+          ),
+        ],
+      ),
+    );
+  }
+}