Skip to content

Instantly share code, notes, and snippets.

@matanlurey
Created May 15, 2022 01:30
Show Gist options
  • Save matanlurey/6e45a265f743513ac4d3688c2d87826e to your computer and use it in GitHub Desktop.
Save matanlurey/6e45a265f743513ac4d3688c2d87826e to your computer and use it in GitHub Desktop.
A fairly simple way to enhance "StringBuffer" to make recursive indentation easier.
extension IdentableStringSink on StringSink {
/// Provides a delegating implementation of [StringSink] on [invoke].
///
/// ```
/// String example(String name, int age) {
/// final sink = StringBuffer();
/// sink
/// ..writeln('Identification')
/// ..indent(2, (sink) {
/// sink
/// ..writeln('name: $name')
/// ..writeln('age: $age');
/// });
/// // Identification:
/// // name: $name
/// // age: $age
/// return sink.toString();
/// }
/// ```
///
/// **IMPORTANT**: Indentation is _recursive_ when it's invoked on itself:
///
/// ```
/// String double(String c) {
/// final sink = StringBuffer();
/// sink
/// ..writeln('a:')
/// ..indent(2, (sink) {
/// sink
/// ..writeln('b: )
/// ..writeIndented(2, 'c: $c');
/// });
/// // a:
/// // b:
/// // c: $c
/// return sink.toString();
/// }
/// ```
///
/// ... so, **do not** store the sink provided to [invoke].
void indent(int amount, void Function(/* @doNotStore */ StringSink) invoke) {
final self = this;
if (self is _PrefixedStringSink) {
final prefix = '${self._prefix}${' ' * amount}';
final delegate = _PrefixedStringSink(self._sink, prefix);
invoke(delegate);
} else {
invoke(_PrefixedStringSink(self, ' ' * amount));
}
}
/// A helper function for invoking [indent] with a single [immediate].
void writeIntended(int amount, String immediate) {
indent(2, (sink) => sink.write(immediate));
}
/// A helper function for invoking [indent] with a single [immediate].
void writelnIntended(int amount, String immediate) {
indent(2, (sink) => sink.writeln(immediate));
}
}
class _PrefixedStringSink implements StringSink {
final StringSink _sink;
final String _prefix;
_PrefixedStringSink(this._sink, this._prefix);
@override
void write(Object? object) {
_sink
..write(_prefix)
..write(object);
}
@override
void writeAll(Iterable<Object?> objects, [String separator = '']) {
_sink.writeAll(objects.map((e) => '$_prefix$e'), separator);
}
@override
void writeCharCode(int charCode) {
_sink
..write(_prefix)
..writeCharCode(charCode);
}
@override
void writeln([Object? object = '']) {
_sink
..write(_prefix)
..writeln(object);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment