autoCloseOpenUI function
Autocloser: make partial (mid-stream) text syntactically valid by appending the minimal closing quote and brackets. Brackets inside strings do not count, a trailing comma is dropped, and a trailing backslash inside an unfinished string is dropped before closing it.
Implementation
String autoCloseOpenUI(String text) {
var s = text.trimRight();
while (s.endsWith(',')) {
s = s.substring(0, s.length - 1).trimRight();
}
final stack = <String>[];
String? quote;
var escaped = false;
for (var i = 0; i < s.length; i++) {
final c = s[i];
if (quote != null) {
if (escaped) {
escaped = false;
} else if (c == '\\') {
escaped = true;
} else if (c == quote) {
quote = null;
}
continue;
}
if (c == '"' || c == "'") {
quote = c;
} else if (c == '(' || c == '[' || c == '{') {
stack.add(c);
} else if (c == ')' || c == ']' || c == '}') {
const pairs = {'(': ')', '[': ']', '{': '}'};
if (stack.isNotEmpty && pairs[stack.last] == c) stack.removeLast();
}
}
final buf = StringBuffer(s);
if (quote != null) {
if (buf.toString().endsWith('\\')) {
// Drop the dangling escape before closing the string.
final t = buf.toString();
buf.clear();
buf.write(t.substring(0, t.length - 1));
}
buf.write(quote);
}
const closers = {'(': ')', '[': ']', '{': '}'};
for (var i = stack.length - 1; i >= 0; i--) {
buf.write(closers[stack[i]]);
}
return buf.toString();
}