Skip to content

Instantly share code, notes, and snippets.

@abulka
Last active July 16, 2020 13:09
Show Gist options
  • Save abulka/8c2a04a465e416f255e1c2637ae9c517 to your computer and use it in GitHub Desktop.
Save abulka/8c2a04a465e416f255e1c2637ae9c517 to your computer and use it in GitHub Desktop.
Dart dedent() function inspired by Python dedent
library dedent;
// Translation of Python textwrap.dedent algorithm
// https://github.com/python/cpython/blob/eb97b9211e7c99841d6cae8c63893b3525d5a401/Lib/textwrap.py
import 'package:quiver/iterables.dart';
String dedent(String text) {
/// Remove any common leading whitespace from every line in `text`.
/// This can be used to make triple-quoted strings line up with the left
/// edge of the display, while still presenting them in the source code
/// in indented form.
/// Note that tabs and spaces are both treated as whitespace, but they
/// are not equal: the lines " hello" and "\\thello" are
/// considered to have no common leading whitespace.
/// Entirely blank lines are normalized to a newline character.
var _whitespace_only_re = new RegExp(r"^[ \t]+$", multiLine: true);
var _leading_whitespace_re =
new RegExp(r"(^[ \t]*)(?:[^ \t\n])", multiLine: true);
// Look for the longest leading string of spaces and tabs common to
// all lines.
String margin;
text = text.replaceAll(_whitespace_only_re, '');
var indents = _leading_whitespace_re.allMatches(text);
indents.forEach((_indent) {
String indent = text.substring(_indent.start, _indent.end - 1);
if (margin == null)
margin = indent;
// Current line more deeply indented than previous winner:
// no change (previous winner is still on top).
else if (indent.startsWith(margin)) {
}
// Current line consistent with and no deeper than previous winner:
// it's the new winner.
else if (margin.startsWith(indent))
margin = indent;
// Find the largest common whitespace between current line and previous
// winner.
else {
var it = zip([margin.split(''), indent.split('')]).toList();
for (var i = 0; i < it.length; i++) {
if (it[0] != it[1]) {
var till = (i == 0) // compensate for lack of [:-1] Python syntax
? margin.length - 1
: i - 1;
margin = margin.substring(0, till);
break;
}
}
} // else
}); // forEach
// sanity check (testing/debugging only)
var debug = true;
if (debug && margin != '')
text.split("\n").forEach((line) {
assert(line == "" || line.startsWith(margin),
"line = $line, margin = $margin");
});
if (margin != "") {
var r = new RegExp(r"^" + margin,
multiLine: true); // python r"(?m)^" illegal in js regex so leave it out
text = text.replaceAll(r, '');
}
return text;
}
@abulka
Copy link
Author

abulka commented Jul 15, 2020

Here is a test for the nice version of dedent translated from Python.

  test('test dart dedent() implementation', () {
    var s = """
      1.x
      2.y
    """;
    // print('\n$s');
    // print('\n${dedent(s)}');
    var expected = """1.x\n2.y\n""";
    expect(dedent(s), equals(expected));

    s = """
      This is
      a test string
        with a slight indent here
      which goes back here.
    """;
    // print('\n$s');
    // print('\n${dedent(s)}');
    expected = """This is
a test string
  with a slight indent here
which goes back here.\n""";
    expect(dedent(s), equals(expected));

  });

@abulka
Copy link
Author

abulka commented Jul 16, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment