@@ -777,7 +777,7 @@ class MarkdownBuilder implements md.NodeVisitor {
777
777
}
778
778
779
779
/// Extracts all spans from an inline element and merges them into a single list
780
- Iterable <InlineSpan > _getInlineSpans (InlineSpan span) {
780
+ Iterable <InlineSpan > _getInlineSpansFromSpan (InlineSpan span) {
781
781
// If the span is not a TextSpan or it has no children, return the span
782
782
if (span is ! TextSpan || span.children == null ) {
783
783
return < InlineSpan > [span];
@@ -801,95 +801,69 @@ class MarkdownBuilder implements md.NodeVisitor {
801
801
return spans;
802
802
}
803
803
804
- /// Merges adjacent [TextSpan] children
804
+ // Accesses the TextSpan property correctly depending on the widget type.
805
+ // Returns null if not a valid (text) widget.
806
+ InlineSpan ? _getInlineSpanFromText (Widget widget) => switch (widget) {
807
+ SelectableText () => widget.textSpan,
808
+ Text () => widget.textSpan,
809
+ RichText () => widget.text,
810
+ _ => null
811
+ };
812
+
813
+ /// Merges adjacent [TextSpan] children.
814
+ /// Also forces a specific [TextAlign] regardless of merging.
815
+ /// This is essential for table column alignment, since desired column alignment
816
+ /// is discovered after the text widgets have been created. This function is the
817
+ /// last chance to enforce the desired column alignment in the texts.
805
818
List <Widget > _mergeInlineChildren (
806
819
List <Widget > children,
807
820
TextAlign ? textAlign,
808
821
) {
809
- // List of merged text spans and widgets
810
- final List <Widget > mergedTexts = < Widget > [];
822
+ // List of text widgets (merged) and non-text widgets (non-merged)
823
+ final List <Widget > mergedWidgets = < Widget > [];
811
824
825
+ bool lastIsText = false ;
812
826
for (final Widget child in children) {
813
- // If the list is empty, add the current widget to the list
814
- if (mergedTexts.isEmpty) {
815
- mergedTexts.add (child);
827
+ final InlineSpan ? currentSpan = _getInlineSpanFromText (child);
828
+ final bool currentIsText = currentSpan != null ;
829
+
830
+ if (! currentIsText) {
831
+ // There is no merging to do, so just add and continue
832
+ mergedWidgets.add (child);
833
+ lastIsText = false ;
816
834
continue ;
817
835
}
818
836
819
- // Remove last widget from the list to merge it with the current widget
820
- final Widget last = mergedTexts.removeLast ();
821
-
822
837
// Extracted spans from the last and the current widget
823
838
List <InlineSpan > spans = < InlineSpan > [];
824
839
825
- // Extract the text spans from the last widget
826
- if (last is SelectableText ) {
827
- final TextSpan span = last.textSpan! ;
828
- spans.addAll (_getInlineSpans (span));
829
- } else if (last is Text ) {
830
- final InlineSpan span = last.textSpan! ;
831
- spans.addAll (_getInlineSpans (span));
832
- } else if (last is RichText ) {
833
- final InlineSpan span = last.text;
834
- spans.addAll (_getInlineSpans (span));
835
- } else {
836
- // If the last widget is not a text widget,
837
- // add both the last and the current widget to the list
838
- mergedTexts.addAll (< Widget > [last, child]);
839
- continue ;
840
+ if (lastIsText) {
841
+ // Removes last widget from the list for merging and extracts its spans
842
+ spans.addAll (_getInlineSpansFromSpan (
843
+ _getInlineSpanFromText (mergedWidgets.removeLast ())! ));
840
844
}
841
845
842
- // Extract the text spans from the current widget
843
- if (child is Text ) {
844
- final InlineSpan span = child.textSpan! ;
845
- spans.addAll (_getInlineSpans (span));
846
- } else if (child is SelectableText ) {
847
- final TextSpan span = child.textSpan! ;
848
- spans.addAll (_getInlineSpans (span));
849
- } else if (child is RichText ) {
850
- final InlineSpan span = child.text;
851
- spans.addAll (_getInlineSpans (span));
852
- } else {
853
- // If the current widget is not a text widget,
854
- // add both the last and the current widget to the list
855
- mergedTexts.addAll (< Widget > [last, child]);
856
- continue ;
857
- }
846
+ spans.addAll (_getInlineSpansFromSpan (currentSpan));
847
+ spans = _mergeSimilarTextSpans (spans);
858
848
859
- if (spans.isNotEmpty) {
860
- // Merge similar text spans
861
- spans = _mergeSimilarTextSpans (spans);
849
+ final Widget mergedWidget;
862
850
863
- // Create a new text widget with the merged text spans
864
- InlineSpan child;
865
- if (spans.length == 1 ) {
866
- child = spans.first;
867
- } else {
868
- child = TextSpan (children: spans);
869
- }
870
-
871
- // Add the new text widget to the list
872
- if (selectable) {
873
- mergedTexts.add (SelectableText .rich (
874
- TextSpan (children: spans),
875
- textScaler: styleSheet.textScaler,
876
- textAlign: textAlign ?? TextAlign .start,
877
- onTap: onTapText,
878
- ));
879
- } else {
880
- mergedTexts.add (Text .rich (
881
- child,
882
- textScaler: styleSheet.textScaler,
883
- textAlign: textAlign ?? TextAlign .start,
884
- ));
885
- }
851
+ if (spans.isEmpty) {
852
+ // no spans found, just insert the current widget
853
+ mergedWidget = child;
886
854
} else {
887
- // If no text spans were found, add the current widget to the list
888
- mergedTexts.add (child);
855
+ final InlineSpan first = spans.first;
856
+ final TextSpan textSpan = (spans.length == 1 && first is TextSpan )
857
+ ? first
858
+ : TextSpan (children: spans);
859
+ mergedWidget = _buildRichText (textSpan, textAlign: textAlign);
889
860
}
861
+
862
+ mergedWidgets.add (mergedWidget);
863
+ lastIsText = true ;
890
864
}
891
865
892
- return mergedTexts ;
866
+ return mergedWidgets ;
893
867
}
894
868
895
869
TextAlign _textAlignForBlockTag (String ? blockTag) {
@@ -1003,12 +977,12 @@ class MarkdownBuilder implements md.NodeVisitor {
1003
977
return mergedSpans;
1004
978
}
1005
979
1006
- Widget _buildRichText (TextSpan ? text, {TextAlign ? textAlign, String ? key}) {
980
+ Widget _buildRichText (TextSpan text, {TextAlign ? textAlign, String ? key}) {
1007
981
//Adding a unique key prevents the problem of using the same link handler for text spans with the same text
1008
982
final Key k = key == null ? UniqueKey () : Key (key);
1009
983
if (selectable) {
1010
984
return SelectableText .rich (
1011
- text! ,
985
+ text,
1012
986
textScaler: styleSheet.textScaler,
1013
987
textAlign: textAlign ?? TextAlign .start,
1014
988
onSelectionChanged: onSelectionChanged != null
@@ -1020,7 +994,7 @@ class MarkdownBuilder implements md.NodeVisitor {
1020
994
);
1021
995
} else {
1022
996
return Text .rich (
1023
- text! ,
997
+ text,
1024
998
textScaler: styleSheet.textScaler,
1025
999
textAlign: textAlign ?? TextAlign .start,
1026
1000
key: k,
0 commit comments