@@ -278,31 +278,64 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
278278 {
279279 return S_OK;
280280 }
281- // .. otherwise if we internally have a list of 2 and we're about to insert a single color
282- // it's probable that we're just walking left-to-right through the row and changing each
283- // cell one at a time.
284- // e.g.
285- // AAAAABBBBBBB
286- // AAAAAABBBBBB
287- // AAAAAAABBBBB
288- // Check for that circumstance by seeing if we're inserting a single run of the
289- // left side color right at the boundary and just adjust the counts in the existing
290- // two elements in our internal list.
291- else if (_list.size () == 2 && newAttrs.at (0 ).GetLength () == 1 )
281+ // .. otherwise if we internally have a list of 2 or more and we're about to insert a single color
282+ // it's possible that we just walk left-to-right through the row and find a quick exit.
283+ else if (iStart > 0 && iStart == iEnd)
292284 {
293- const auto left = _list.begin ();
294- if (iStart == left->GetLength () && NewAttr == left->GetAttributes ())
285+ // First we try to find the run where the insertion happens, using lowerBound and upperBound to track
286+ // where we are curretly at.
287+ size_t lowerBound = 0 ;
288+ size_t upperBound = 0 ;
289+ for (size_t i = 0 ; i < _list.size (); i++)
295290 {
296- const auto right = left + 1 ;
297- left->IncrementLength ();
298- right->DecrementLength ();
299-
300- // If we just reduced the right half to zero, just erase it out of the list.
301- if (right->GetLength () == 0 )
291+ upperBound += _list.at (i).GetLength ();
292+ if (iStart >= lowerBound && iStart < upperBound)
302293 {
303- _list.erase (right);
294+ const auto curr = std::next (_list.begin (), i);
295+
296+ // The run that we try to insert into has the same color as the new one.
297+ // e.g.
298+ // AAAAABBBBBBBCCC
299+ // ^
300+ // AAAAABBBBBBBCCC
301+ //
302+ // 'B' is the new color and '^' represents where iStart is. We don't have to
303+ // do anything.
304+ if (curr->GetAttributes () == NewAttr)
305+ {
306+ return S_OK;
307+ }
308+
309+ // If the insertion happens at current run's lower boundary...
310+ if (iStart == lowerBound)
311+ {
312+ const auto prev = std::prev (curr, 1 );
313+ // ... and the previous run has the same color as the new one, we can
314+ // just adjust the counts in the existing two elements in our internal list.
315+ // e.g.
316+ // AAAAABBBBBBBCCC
317+ // ^
318+ // AAAAAABBBBBBCCC
319+ //
320+ // Here 'A' is the new color.
321+ if (NewAttr == prev->GetAttributes ())
322+ {
323+ prev->IncrementLength ();
324+ curr->DecrementLength ();
325+
326+ // If we just reduced the right half to zero, just erase it out of the list.
327+ if (curr->GetLength () == 0 )
328+ {
329+ _list.erase (curr);
330+ }
331+
332+ return S_OK;
333+ }
334+ }
304335 }
305- return S_OK;
336+
337+ // Advance one run in the _list.
338+ lowerBound = upperBound;
306339 }
307340 }
308341 }
0 commit comments