injectGlanceModifier function
Helper to parse a typical Compose call (e.g. Column { or Text(...))
and inject a modifier string (e.g. fillMaxSize()).
A size the chain already there carries along an axis modifier sizes is
dropped, so the widget injecting its size wins over the one that asked for
it further in. weightAxis is the axis a defaultWeight() in modifier
sizes, which the call does not say on its own.
Implementation
String injectGlanceModifier(
String code,
String modifier, {
GlanceSizeAxis? weightAxis,
}) {
// We want to find the first Compose element like `Column(`, `Column {`, `Text(`.
// If it already has arguments `Column(abc) {`, we inject `modifier = modifier, abc` or similar.
final trimmed = code.trimLeft();
final indentMatch = RegExp(r'^(\s*)').firstMatch(code);
final indent = indentMatch?.group(1) ?? '';
if (trimmed.startsWith('if (')) {
final injected = _injectIntoIfBranches(code, modifier, weightAxis);
if (injected != null) return injected;
}
if (trimmed.startsWith('when (')) {
final injected = _injectIntoWhenBranches(code, modifier, weightAxis);
if (injected != null) return injected;
}
final compMatch = RegExp(r'^[A-Z][a-zA-Z0-9_]*').firstMatch(trimmed);
if (compMatch != null) {
final compName = compMatch.group(0);
final argRange = _argumentRange(trimmed, compMatch.end);
final declared =
argRange == null ? null : trimmed.substring(argRange.$1, argRange.$2);
final callEnd = argRange == null ? compMatch.end : argRange.$2 + 1;
final chainRange = declared == null ? null : _modifierChainRange(declared);
final chain = chainRange == null
? null
: declared!.substring(chainRange.$1, chainRange.$2);
// One axis of a chain already filling both says nothing more.
if (GlanceSizeAxis.values.any((axis) => axis.fill == modifier) &&
chain != null &&
_fillsBothAxes(chain)) {
return code;
}
final args = chainRange == null
? declared ?? ''
: declared!.replaceRange(
chainRange.$1,
chainRange.$2,
_withoutSupersededSizes(chain!, modifier, weightAxis),
);
final hasBrace = trimmed.substring(callEnd).trimLeft().startsWith('{');
String newArgs = '';
if (args.isEmpty) {
newArgs = 'modifier = GlanceModifier.$modifier';
} else if (chainRange != null) {
final head = args.substring(0, chainRange.$1);
final tail = args.substring(chainRange.$1 + _modifierToken.length);
newArgs = '$head$_modifierToken.$modifier$tail';
} else {
// Arguments spread over lines stay on theirs.
final separator = args.startsWith('\n') ? ',' : ', ';
newArgs = 'modifier = GlanceModifier.$modifier$separator$args';
}
final rest = trimmed.substring(
callEnd + (hasBrace ? trimmed.substring(callEnd).indexOf('{') + 1 : 0),
);
if (hasBrace) {
return '$indent$compName($newArgs) {$rest';
} else {
return '$indent$compName($newArgs)$rest';
}
}
// Fallback: if we can't find a direct Compose element (e.g. it's an if-statement), wrap it in a Box
final lines = code.split('\n');
final indentedLines =
lines.map((l) => l.trimRight().isEmpty ? '' : ' $l').join('\n');
return '${indent}Box(modifier = GlanceModifier.$modifier) {\n$indentedLines\n$indent}';
}