Skip to content

Commit

Permalink
sync 2.0.0-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
ykmnkmi committed Jul 6, 2023
1 parent 8ab5eac commit c037057
Show file tree
Hide file tree
Showing 7 changed files with 378 additions and 346 deletions.
12 changes: 8 additions & 4 deletions CHANGELOG.md
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.
66 changes: 66 additions & 0 deletions lib/src/extensions.dart
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();
}
}
206 changes: 206 additions & 0 deletions lib/src/functions.dart
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;
}
10 changes: 10 additions & 0 deletions lib/src/patterns.dart
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)))');
Loading

0 comments on commit c037057

Please sign in to comment.