-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
378 additions
and
346 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,25 @@ | ||
## 2.0.0-dev | ||
|
||
- Minimal SDK version: 3.0.0. | ||
- Refactoring. | ||
|
||
## 1.2.0 | ||
|
||
- Minimal SDK version: 2.18.0. | ||
- Refactoring. | ||
|
||
|
||
## 1.1.0 | ||
|
||
- `Pattern.split` no empty trailing strings. | ||
|
||
## 1.0.2 | ||
|
||
- internal changes. | ||
- Internal changes. | ||
|
||
## 1.0.1 | ||
|
||
- update meta & dart format. | ||
- Update meta. | ||
|
||
## 1.0.0 | ||
|
||
- initial release. | ||
- Initial release. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/// Extends [Pattern]. | ||
extension PatternUtils on Pattern { | ||
/// Split string by the occurrences of pattern. | ||
List<String> split(String text) { | ||
var result = <String>[]; | ||
var start = 0, end = 0; | ||
|
||
for (var match in allMatches(text)) { | ||
end = match.start; | ||
|
||
if (start < end) { | ||
result.add(text.substring(start, end)); | ||
} | ||
|
||
for (var i = 0, count = match.groupCount; i < count; i++) { | ||
result.add(match.group(i + 1)!); | ||
} | ||
|
||
start = match.end; | ||
} | ||
|
||
if (start < text.length) { | ||
result.add(text.substring(start)); | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
|
||
/// Extends [String]. | ||
extension StringUtils on String { | ||
/// Return a copy where all tab characters are expanded using spaces. | ||
String expandTabs([int tabSize = 8]) { | ||
var buffer = StringBuffer(); | ||
var units = runes.toList(); | ||
var length = units.length; | ||
|
||
for (var i = 0, line = 0; i < length; i += 1, line += 1) { | ||
var char = units[i]; | ||
|
||
if (char == 13 || char == 10) { | ||
line = -1; | ||
buffer.writeCharCode(char); | ||
} else if (char == 9) { | ||
var size = tabSize - (line % tabSize); | ||
buffer.write(' ' * size); | ||
line = -1; | ||
} else { | ||
buffer.writeCharCode(char); | ||
} | ||
} | ||
|
||
return buffer.toString(); | ||
} | ||
|
||
/// Replace each character in the string using the given translation table. | ||
String translate(Map<int, int> table) { | ||
var buffer = StringBuffer(); | ||
|
||
for (var rune in runes) { | ||
buffer.writeCharCode(table.containsKey(rune) ? table[rune]! : rune); | ||
} | ||
|
||
return buffer.toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
import 'package:textwrap/src/extensions.dart'; | ||
import 'package:textwrap/src/patterns.dart'; | ||
|
||
void fixEndings(List<String> chunks) { | ||
for (var i = 0; i < chunks.length - 1;) { | ||
var chunk = chunks[i]; | ||
var length = chunk.length; | ||
var input = length > 2 ? chunk.substring(length - 2) : chunk; | ||
|
||
if (chunks[i + 1] == ' ' && sentenceEndRe.hasMatch(input)) { | ||
chunks[i + 1] = ' '; | ||
i += 2; | ||
} else { | ||
i += 1; | ||
} | ||
} | ||
} | ||
|
||
void handleLongWord( | ||
List<String> reversedChunks, | ||
List<String> currentLine, | ||
int currentLength, | ||
int width, { | ||
bool breakLongWords = true, | ||
bool breakOnHyphens = true, | ||
}) { | ||
var spaceLeft = width < 1 ? 1 : width - currentLength; | ||
|
||
if (breakLongWords) { | ||
var chunk = reversedChunks.last; | ||
var end = spaceLeft; | ||
|
||
if (breakOnHyphens && chunk.length > spaceLeft) { | ||
var hyphen = chunk.lastIndexOf('-'); | ||
|
||
if (hyphen > 0 && chunk.substring(0, hyphen).contains('-')) { | ||
end = hyphen + 1; | ||
} | ||
} | ||
|
||
currentLine.add(chunk.substring(0, end)); | ||
reversedChunks[reversedChunks.length - 1] = chunk.substring(end); | ||
} else if (currentLine.isEmpty) { | ||
currentLine.add(reversedChunks.removeLast()); | ||
} | ||
} | ||
|
||
String mungeWhitespace( | ||
String text, { | ||
bool expandTabs = true, | ||
int tabSize = 8, | ||
bool replaceWhitespace = true, | ||
}) { | ||
if (expandTabs) { | ||
text = text.expandTabs(tabSize); | ||
} | ||
|
||
if (replaceWhitespace) { | ||
text = text.translate(const <int, int>{ | ||
9: 32, | ||
10: 32, | ||
11: 32, | ||
12: 32, | ||
13: 32, | ||
}); | ||
} | ||
|
||
return text; | ||
} | ||
|
||
List<String> split(String text, {bool breakOnHyphens = true}) { | ||
List<String> chunks; | ||
|
||
if (breakOnHyphens) { | ||
chunks = wordSeparatorRe.split(text); | ||
} else { | ||
chunks = wordSeparatorSimpleRe.split(text); | ||
} | ||
|
||
return chunks; | ||
} | ||
|
||
List<String> splitChunks( | ||
String text, { | ||
bool expandTabs = true, | ||
bool replaceWhitespace = true, | ||
bool breakOnHyphens = true, | ||
int tabSize = 8, | ||
}) { | ||
text = mungeWhitespace(text, | ||
expandTabs: expandTabs, | ||
replaceWhitespace: replaceWhitespace, | ||
tabSize: tabSize); | ||
return split(text, breakOnHyphens: breakOnHyphens); | ||
} | ||
|
||
List<String> wrapChunks( | ||
List<String> chunks, { | ||
int width = 70, | ||
String initialIndent = '', | ||
String subsequentIndent = '', | ||
bool breakLongWords = true, | ||
bool dropWhitespace = true, | ||
bool breakOnHyphens = true, | ||
int maxLines = -1, | ||
String placeholder = ' ...', | ||
}) { | ||
if (width < 0) { | ||
throw Exception('Invalid width $width (must be > 0).'); | ||
} | ||
|
||
var lines = <String>[]; | ||
|
||
if (maxLines != -1) { | ||
var indent = maxLines > 1 ? subsequentIndent : initialIndent; | ||
|
||
if (indent.length + placeholder.trimLeft().length > width) { | ||
throw StateError('Placeholder too large for max width.'); | ||
} | ||
} | ||
|
||
chunks = chunks.reversed.toList(); | ||
|
||
while (chunks.isNotEmpty) { | ||
var currentLine = <String>[]; | ||
var currentLength = 0; | ||
|
||
var indent = lines.isNotEmpty ? subsequentIndent : initialIndent; | ||
var contentWidth = width - indent.length; | ||
|
||
if (dropWhitespace && chunks.last.trim().isEmpty && lines.isNotEmpty) { | ||
chunks.removeLast(); | ||
} | ||
|
||
while (chunks.isNotEmpty) { | ||
var length = chunks.last.length; | ||
|
||
if (currentLength + length <= contentWidth) { | ||
currentLine.add(chunks.removeLast()); | ||
currentLength += length; | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
if (chunks.isNotEmpty && chunks.last.length > contentWidth) { | ||
handleLongWord(chunks, currentLine, currentLength, contentWidth, | ||
breakLongWords: breakLongWords, breakOnHyphens: breakOnHyphens); | ||
currentLength = 0; | ||
|
||
for (var line in currentLine) { | ||
currentLength += line.length; | ||
} | ||
} | ||
|
||
if (dropWhitespace && | ||
currentLine.isNotEmpty && | ||
currentLine.last.trim().isEmpty) { | ||
var last = currentLine.removeLast(); | ||
currentLength -= last.length; | ||
} | ||
|
||
if (currentLine.isNotEmpty) { | ||
if (maxLines == -1 || | ||
lines.length + 1 < maxLines || | ||
(chunks.isEmpty || | ||
dropWhitespace && | ||
chunks.length == 1 && | ||
chunks.first.trim().isEmpty) && | ||
currentLength <= width) { | ||
lines.add(indent + currentLine.join()); | ||
} else { | ||
var not = true; | ||
|
||
while (currentLine.isNotEmpty) { | ||
if (currentLine.last.trim().isNotEmpty && | ||
currentLength + placeholder.length <= contentWidth) { | ||
currentLine.add(placeholder); | ||
lines.add(indent + currentLine.join()); | ||
not = false; | ||
break; | ||
} | ||
|
||
var last = currentLine.removeLast(); | ||
currentLength -= last.length; | ||
} | ||
|
||
if (not) { | ||
if (lines.isNotEmpty) { | ||
var previousLine = lines.last.trimRight(); | ||
|
||
if (previousLine.length + placeholder.length <= contentWidth) { | ||
lines[lines.length - 1] = previousLine + placeholder; | ||
} | ||
|
||
lines.add(indent + placeholder.trimLeft()); | ||
} | ||
} | ||
|
||
break; | ||
} | ||
} | ||
} | ||
|
||
return lines; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
final RegExp spaceRe = RegExp('\\s+'); | ||
|
||
final RegExp sentenceEndRe = RegExp('\\w[\\.\\!\\?][\\"\']?\$'); | ||
|
||
final RegExp wordSeparatorSimpleRe = RegExp('([\t\n\v\r ])+'); | ||
|
||
final RegExp wordSeparatorRe = RegExp( | ||
'([\t\n\v\r ]+|(?<=[\\w!"\'&.,?])-{2,}(?=\\w)|[^\t\n\v\r ]+?' | ||
'(?:-(?:(?<=[^\\d\\W]{2}-)|(?<=[^\\d\\W]-[^\\d\\W]-))(?=[^\\d\\W]-?[^\\d\\W])|' | ||
'(?=[\t\n\v\r ]|\$)|(?<=[\\w!"\'&.,?])(?=-{2,}\\w)))'); |
Oops, something went wrong.