@@ -51,8 +51,14 @@ class AttributedText {
5151 AttributedSpans ? spans,
5252 Map <int , Object >? placeholders,
5353 ]) : _text = text ?? "" ,
54- spans = spans ?? AttributedSpans (),
55- placeholders = placeholders ?? < int , Object > {} {
54+ spans = spans ?? AttributedSpans () {
55+ // Sort the placeholders map so that we can always assume the entries
56+ // iterate in the placeholder content order. This knowledge is relied upon
57+ // in multiple places in this class.
58+ this .placeholders = Map .fromEntries (
59+ placeholders? .entries.sorted ((a, b) => a.key - b.key) ?? [],
60+ );
61+
5662 assert (() {
5763 // ^ Run this in an assert with a callback so that the validation doesn't run in
5864 // production and cost processor cycles.
@@ -70,6 +76,7 @@ class AttributedText {
7076 final buffer = StringBuffer ();
7177 int start = 0 ;
7278 int insertedPlaceholders = 0 ;
79+
7380 for (final entry in this .placeholders.entries) {
7481 final textSegment = _text.substring (start - insertedPlaceholders, entry.key - insertedPlaceholders);
7582 buffer.write (textSegment);
@@ -160,8 +167,11 @@ class AttributedText {
160167 /// Placeholders that represent non-text content, e.g., inline images, that
161168 /// should appear in the rendered text.
162169 ///
170+ /// The entries in this map are in content-order, e.g., the entry for a placeholder
171+ /// at index 3 comes before an entry whose placeholder is at index 5.
172+ ///
163173 /// In terms of [length] , each placeholder is treated as a single character.
164- final Map <int , Object > placeholders;
174+ late final Map <int , Object > placeholders;
165175
166176 /// Returns the `length` of this [AttributedText] , which includes the length
167177 /// of the plain text `String` , and the number of [placeholders] .
0 commit comments