normaliseClickText function
Android's normaliseForMatch (NFD → strip combining marks → ASCII
lowercase → every non-[a-z0-9] run to one space → trim), which the
click names are defined against.
Deliberately NOT the tree's text_normalizer.dart: that one is pinned to
the backend planner's match transform (it keeps punctuation and spells
%), and must never change for naming.
Dart has no Unicode normaliser, so the NFD step is a fold table for the Latin-1 Supplement and Latin Extended-A letters that decompose to an ASCII base (é → e, ş → s). Letters with no ASCII decomposition (ß, æ, ø, ł) and every non-Latin script collapse to a space — exactly as they do on Android.
Implementation
String normaliseClickText(String input) {
final out = StringBuffer();
var pendingSpace = false;
for (final rune in input.runes) {
// Combining diacritical marks — what NFD leaves after the base letter.
if (rune >= 0x0300 && rune <= 0x036F) continue;
var c = rune;
if (c >= 0xC0 && c <= 0x17F) {
final folded = _kLatinFold[c - 0xC0];
c = folded == 0x20 ? -1 : folded;
}
if (c >= 0x41 && c <= 0x5A) c += 0x20;
final alnum = (c >= 0x61 && c <= 0x7A) || (c >= 0x30 && c <= 0x39);
if (!alnum) {
pendingSpace = out.isNotEmpty;
continue;
}
if (pendingSpace) {
out.writeCharCode(0x20);
pendingSpace = false;
}
out.writeCharCode(c);
}
return out.toString();
}