reorder static method
Returns (logical order indexes, embedding level per original index).
Implementation
static (List<int>, List<int>) reorder(List<String> visual, {required bool baseRtl}) {
final int count = visual.length;
final List<int> classes = visual.map(_classOf).toList();
final List<int> levels = List<int>.filled(count, baseRtl ? 1 : 0);
final int base = baseRtl ? 1 : 0;
int strongNear(int index, int step) {
for (int i = index + step; i >= 0 && i < count; i += step) {
final int kind = classes[i];
if (kind == _left || kind == _right) return kind;
}
return baseRtl ? _right : _left;
}
// Numbers take the direction of neighbouring Latin text (bidi rule W7,
// approximated on visual neighbours), otherwise they behave like RTL.
final List<int> resolved = List<int>.from(classes);
for (int i = 0; i < count; i++) {
if (classes[i] != _number) continue;
resolved[i] = strongNear(i, -1) == _left || strongNear(i, 1) == _left ? _left : _right;
}
for (int i = 0; i < count; i++) {
switch (classes[i]) {
case _right:
levels[i] = 1;
break;
case _left:
levels[i] = baseRtl ? 2 : 0;
break;
case _number:
levels[i] = resolved[i] == _left ? (baseRtl ? 2 : 0) : 2;
break;
default:
break;
}
}
for (int i = 0; i < count; i++) {
final int kind = classes[i];
if (kind != _neutral && kind != _mark) continue;
int left = i - 1;
while (left >= 0 && (classes[left] == _neutral || classes[left] == _mark)) {
left--;
}
int right = i + 1;
while (right < count && (classes[right] == _neutral || classes[right] == _mark)) {
right++;
}
final int leftDir = left < 0 ? (baseRtl ? _right : _left) : resolved[left];
final int rightDir = right >= count ? (baseRtl ? _right : _left) : resolved[right];
if (kind == _mark && left >= 0) {
levels[i] = levels[left];
} else if (leftDir == rightDir) {
levels[i] = leftDir == _right ? 1 : (baseRtl ? 2 : 0);
} else {
levels[i] = base;
}
if (levels[i] < base) levels[i] = base;
}
// Digits touching each other across separators ("1.5", "۱۴۰۳/۰۱") stay one number.
for (int i = 1; i < count - 1; i++) {
if (classes[i] == _neutral && classes[i - 1] == _number && classes[i + 1] == _number && visual[i].trim().length == 1 && ".,/:-٫٬".contains(visual[i].trim())) {
levels[i] = levels[i - 1];
}
}
final List<int> order = List<int>.generate(count, (int i) => i);
int maxLevel = 0;
for (final int level in levels) {
if (level > maxLevel) maxLevel = level;
}
for (int k = 1; k <= maxLevel; k++) {
int i = 0;
while (i < count) {
if (levels[order[i]] < k) {
i++;
continue;
}
int j = i;
while (j + 1 < count && levels[order[j + 1]] >= k) {
j++;
}
int a = i;
int b = j;
while (a < b) {
final int swap = order[a];
order[a] = order[b];
order[b] = swap;
a++;
b--;
}
i = j + 1;
}
}
return (order, levels);
}