paragraphs property
override
The paragraphs of the license, each as a LicenseParagraph consisting of a string and some formatting information. Paragraphs can include newline characters, but this is discouraged as it results in ugliness.
Implementation
@override
Iterable<LicenseParagraph> get paragraphs sync* {
int lineStart = 0;
int currentPosition = 0;
int lastLineIndent = 0;
int currentLineIndent = 0;
int currentParagraphIndentation;
_LicenseEntryWithLineBreaksParserState state = _LicenseEntryWithLineBreaksParserState.beforeParagraph;
final List<String> lines = <String>[];
void addLine() {
assert(lineStart < currentPosition);
lines.add(text.substring(lineStart, currentPosition));
}
LicenseParagraph getParagraph() {
assert(lines.isNotEmpty);
assert(currentParagraphIndentation != null);
final LicenseParagraph result = LicenseParagraph(lines.join(' '), currentParagraphIndentation);
assert(result.text.trimLeft() == result.text);
assert(result.text.isNotEmpty);
lines.clear();
return result;
}
while (currentPosition < text.length) {
switch (state) {
case _LicenseEntryWithLineBreaksParserState.beforeParagraph:
assert(lineStart == currentPosition);
switch (text[currentPosition]) {
case ' ':
lineStart = currentPosition + 1;
currentLineIndent += 1;
state = _LicenseEntryWithLineBreaksParserState.beforeParagraph;
break;
case '\t':
lineStart = currentPosition + 1;
currentLineIndent += 8;
state = _LicenseEntryWithLineBreaksParserState.beforeParagraph;
break;
case '\n':
case '\f':
if (lines.isNotEmpty) {
yield getParagraph();
}
lastLineIndent = 0;
currentLineIndent = 0;
currentParagraphIndentation = null;
lineStart = currentPosition + 1;
state = _LicenseEntryWithLineBreaksParserState.beforeParagraph;
break;
case '[':
// This is a bit of a hack for the LGPL 2.1, which does something like this:
//
// [this is a
// single paragraph]
//
// ...near the top.
currentLineIndent += 1;
continue startParagraph;
startParagraph:
default:
if (lines.isNotEmpty && currentLineIndent > lastLineIndent) {
yield getParagraph();
currentParagraphIndentation = null;
}
// The following is a wild heuristic for guessing the indentation level.
// It happens to work for common variants of the BSD and LGPL licenses.
if (currentParagraphIndentation == null) {
if (currentLineIndent > 10)
currentParagraphIndentation = LicenseParagraph.centeredIndent;
else
currentParagraphIndentation = currentLineIndent ~/ 3;
}
state = _LicenseEntryWithLineBreaksParserState.inParagraph;
}
break;
case _LicenseEntryWithLineBreaksParserState.inParagraph:
switch (text[currentPosition]) {
case '\n':
addLine();
lastLineIndent = currentLineIndent;
currentLineIndent = 0;
lineStart = currentPosition + 1;
state = _LicenseEntryWithLineBreaksParserState.beforeParagraph;
break;
case '\f':
addLine();
yield getParagraph();
lastLineIndent = 0;
currentLineIndent = 0;
currentParagraphIndentation = null;
lineStart = currentPosition + 1;
state = _LicenseEntryWithLineBreaksParserState.beforeParagraph;
break;
default:
state = _LicenseEntryWithLineBreaksParserState.inParagraph;
}
break;
}
currentPosition += 1;
}
switch (state) {
case _LicenseEntryWithLineBreaksParserState.beforeParagraph:
if (lines.isNotEmpty) {
yield getParagraph();
}
break;
case _LicenseEntryWithLineBreaksParserState.inParagraph:
addLine();
yield getParagraph();
break;
}
}