replaceSourceIndent method
Returns the source with indentation changed from oldIndent
to
newIndent
, keeping indentation of lines relative to each other.
Indentation on the first line will only be updated if includeLeading
is
true
.
If ensureTrailingNewline
is true
, a newline will be added to
the end of the returned code if it does not already have one.
Usually includeLeading
and ensureTrailingNewline
are set together,
when indenting a set of statements to go inside a block (as opposed to
just wrapping a nested expression that might span multiple lines).
Implementation
String replaceSourceIndent(
String source,
String oldIndent,
String newIndent, {
bool includeLeading = false,
bool ensureTrailingNewline = false,
}) {
// Prepare token ranges.
var lineRanges = <SourceRange>[];
{
var tokens = TokenUtils.getTokens(source, _unit.featureSet);
for (var token in tokens) {
if (token.type == TokenType.STRING) {
lineRanges.add(range.token(token));
}
}
}
// Re-indent lines.
var sb = StringBuffer();
var eol = endOfLine;
var lines = source.split(eol);
var lineOffset = 0;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
// Exit early if this is the last line and it's already empty, to avoid
// inserting any whitespace or appending an additional newline if
// `ensureTrailingNewline`.
if (i == lines.length - 1 && isEmpty(line)) {
break;
}
// Don't replace whitespace on first line unless `includeLeading`.
var doReplaceWhitespace = i != 0 || includeLeading;
// Don't add eol to last line unless `ensureTrailingNewline`.
var doAppendEol = i != lines.length - 1 || ensureTrailingNewline;
// Check if "offset" is in one of the ranges.
var inString = false;
for (var lineRange in lineRanges) {
if (lineOffset > lineRange.offset && lineOffset < lineRange.end) {
inString = true;
break;
}
// We can skip the rest if this line ends before the end of this range
// because subsequent ranges are after it.
if (lineOffset < lineRange.end) {
break;
}
}
lineOffset += line.length + eol.length;
// Update line indent.
if (!inString && doReplaceWhitespace) {
line = '$newIndent${removeStart(line, oldIndent)}';
}
// Append line.
sb.write(line);
if (doAppendEol) {
sb.write(eol);
}
}
return sb.toString();
}