Skip to content

Commit

Permalink
1.5.6
Browse files Browse the repository at this point in the history
  • Loading branch information
xErik committed May 19, 2023
1 parent 9868e7c commit 164c19b
Show file tree
Hide file tree
Showing 10 changed files with 369 additions and 173 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@
## 1.5.5

- Unit Tests.
- WrapResult: attribute `textStr` to getter.
- WrapResult: attribute `textStr` to getter.

## 1.5.6

- Unit Tests.
- Removed `TextTokens`.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ The `tex` patterns used in the algorithm can be at [tug.org](https://tug.org/tex

The package seems to work fine for western languages, other languages have to be evaluated.

A live Flutter demo: [https://xerik.github.io/hyphenatorx/](https://xerik.github.io/hyphenatorx/).
Test the live demo [https://xerik.github.io/hyphenatorx/](https://xerik.github.io/hyphenatorx/).

**Wrapping and Scaling Text**

The package [text_wrap_auto_size](https://pub.dev/packages/text_wrap_auto_size) uses
`hyphenatorx` for wrapping and auto scaling text - with and without hyphenation.

## Quickstart

Expand Down Expand Up @@ -184,9 +189,9 @@ final text = """A vast subdivision of culture,
composed of many creative endeavors and disciplines.""";
final hyphenator = Hyphenator(Language_en_us());
final TextTokens result = hyphenator.hyphenateTextToTokens(text);
final List<TextPartToken> tokens = hyphenator.hyphenateTextToTokens(text);
result.parts.forEach((part) {
tokens.forEach((part) {
if (part is NewlineToken) {
print(part.text); // = is always a single newline
} else if (part is TabsAndSpacesToken) {
Expand Down
56 changes: 41 additions & 15 deletions lib/hyphenatorx.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import 'dart:core';

import 'package:flutter/material.dart';
import 'package:hyphenatorx/src/calculationhelper.dart';
import 'package:hyphenatorx/src/extensions.dart';
import 'package:hyphenatorx/src/letterutil.dart';
import 'package:hyphenatorx/token/tokens.dart';

import 'languages/languageconfig.dart';
import 'src/calculationhelper.dart';
import 'src/letterutil.dart';
import 'src/pattern.dart';
import 'token/linewrapper.dart';
import 'token/linewrapperhyphen.dart';
import 'token/linewrappernohyphen.dart';
import 'token/tokens.dart';
import 'token/wrapresult.dart';

/// Wrapper class hyphenating text.
class Hyphenator {
late final CalculationHelper calc;
final RegExp _reBoundaries = RegExp(r'[\t\ ]+');
final RegExp _split = RegExp(r'\n|[\t ]+');
static final RegExp _reBoundaries = RegExp(r'[\t\ ]+');
static final RegExp _split = RegExp(r'\n|[\t ]+');

static Language getLanguageEnum(String lang) {
Language l;
Expand Down Expand Up @@ -115,7 +116,32 @@ class Hyphenator {
/// [WrapResult] holds a [Text] with the correctly hyphened [String].
WrapResult wrap(final Text text, final TextStyle style, final maxWidth) {
final tokens = hyphenateTextToTokens(text.data!);
final wrapper = LineWrapper(tokens, text, style, maxWidth, calc.hyphen);
final wrapper =
LineWrapperHyphen(tokens, text, style, maxWidth, calc.hyphen);
return wrapper.render();
}

/// Service method to wrap a text but perform no hyphenation.
static WrapResult wrapNoHyphen(
final Text text, final TextStyle style, final double maxWidth) {
final List<TextPartToken> tokens = [];

final List<String> parts =
text.data!.replaceAll(reR, '').splitWithDelim(_split);

for (final part in parts) {
if (part.isEmpty) {
// hu?!
} else if (part == '\n') {
tokens.add(NewlineToken());
} else if (part.trim().isEmpty) {
tokens.add(TabsAndSpacesToken(part));
} else {
tokens.add(WordToken([WordPartToken(part)]));
}
}
// print(tokens);
final wrapper = LineWrapperNoHyphen(tokens, text, style, maxWidth);
return wrapper.render();
}

Expand All @@ -137,31 +163,31 @@ class Hyphenator {
///
/// [[The], WS, [arts], WS, [are], WS, [a], NL, [vast], WS, [sub, di, vi, sion], WS]
///
TextTokens hyphenateTextToTokens(final String text) {
final List<TextPartToken> partsResult = [];
static final reR = RegExp(r'\r');
List<TextPartToken> hyphenateTextToTokens(final String text) {
final List<TextPartToken> tokens = [];

final String hyph = hyphenateText(text); // this is expensive

final List<String> parts =
hyph.replaceAll(r'\r', '').splitWithDelim(_split);
final List<String> parts = hyph.replaceAll(reR, '').splitWithDelim(_split);

for (final part in parts) {
if (part.isEmpty) {
// hu?!
} else if (part == '\n') {
partsResult.add(NewlineToken());
tokens.add(NewlineToken());
} else if (part.trim().isEmpty) {
partsResult.add(TabsAndSpacesToken(part));
tokens.add(TabsAndSpacesToken(part));
} else {
// Word
partsResult.add(WordToken(part
tokens.add(WordToken(part
.split(calc.symbol)
.map<WordPartToken>((e) => WordPartToken(e))
.toList(growable: false)));
}
}

return TextTokens(partsResult);
return tokens;
}

/// Hyphenates a text.
Expand Down
4 changes: 4 additions & 0 deletions lib/src/token/texthelper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class TextHelper {
locale: t.locale,
softWrap: t.softWrap,
overflow: t.overflow,
// Android has scaling larger than 1.0 set,
// thus the measurements appear to be not right
// if this is not 1.0 and consumd?
// textScaleFactor: 1.0,
textScaleFactor: t.textScaleFactor,
maxLines: t.maxLines,
semanticsLabel: t.semanticsLabel,
Expand Down
16 changes: 6 additions & 10 deletions lib/src/token/tokeniterator.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import 'dart:ui';

import 'package:hyphenatorx/token/tokens.dart';

class TokenIterator {
late final List<TextPartToken> _tokens;
int _index = 0;

TokenIterator(TextTokens tokens) {
_tokens = tokens.parts;
}
TokenIterator(List<TextPartToken> this._tokens);

bool isEmpty() => _tokens.isEmpty;
bool hasNext() => _index < _tokens.length - 1;
bool hasPrev() => _index > 0;
// bool hasPrev() => _index > 0;
TextPartToken current() => _tokens.elementAt(_index);
TextPartToken next() => _tokens.elementAt(++_index);
TextPartToken prev() => _tokens.elementAt(--_index);
TextPartToken peek() => hasNext()
? _tokens.elementAt(_index + 1)
: (TabsAndSpacesToken('')..sizeHyphen = const Size(0, 0));
// TextPartToken prev() => _tokens.elementAt(--_index);
// TextPartToken peek() => hasNext()
// ? _tokens.elementAt(_index + 1)
// : (TabsAndSpacesToken('')..sizeHyphen = const Size(0, 0));
}
20 changes: 8 additions & 12 deletions lib/token/linewrapper.dart → lib/token/linewrapperhyphen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:math';

import 'package:flutter/widgets.dart';
import 'package:hyphenatorx/src/token/texthelper.dart';

Expand All @@ -9,19 +7,19 @@ import 'wrapresult.dart';

/// Hyphenates tokens with respect to the attributes of
/// [Text], [TextStyle] and [maxWidth].
class LineWrapper {
class LineWrapperHyphen {
final String _hyphen;
late final double _maxWidth;
final List<List<TextPartToken>> _lines = [];
late final TextPainter _painter;
final TextStyle _style;
double maxSyllableWidth = 0;
// double maxSyllableWidth = 0;
late final TokenIterator _tokenIter;
final Text _text;

/// Constructor.
LineWrapper(TextTokens tokens, this._text, this._style, this._maxWidth,
this._hyphen) {
LineWrapperHyphen(List<TextPartToken> tokens, this._text, this._style,
this._maxWidth, this._hyphen) {
final Map<String, Size> tokensWidthCache = {};
_tokenIter = TokenIterator(tokens);

Expand All @@ -35,7 +33,7 @@ class LineWrapper {
textWidthBasis: _text.textWidthBasis ?? TextWidthBasis.parent,
);

for (final TextPartToken part in tokens.parts) {
for (final TextPartToken part in tokens) {
if (part is WordToken) {
for (final WordPartToken p in part.parts) {
_setWidths(p.text, tokensWidthCache, p);
Expand Down Expand Up @@ -73,18 +71,16 @@ class LineWrapper {
token.sizeHyphen = sizeHyphen;
token.sizeNoHyphen = sizeNoHyphen;
token.sizeCurrent = sizeNoHyphen;
maxSyllableWidth = max(maxSyllableWidth, sizeNoHyphen.width);
// maxSyllableWidth = max(maxSyllableWidth, sizeNoHyphen.width);
}

/// Returns the resulting String with hyphens and linebreaks.
///
/// Calls [lines] implicitly.
WrapResult render() {
if (_tokenIter.isEmpty()) {
return WrapResult(_text, _style, _maxWidth, Size(0, 0), _lines);
}

List<TextPartToken> line = [];
final List<TextPartToken> line = [];

while (true) {
var token = _tokenIter.current();
Expand All @@ -93,7 +89,7 @@ class LineWrapper {
// NEWLINE
// ------------------------------------------------------------
if (token is NewlineToken) {
_lines.add([NewlineToken()]);
_lines.add(_cloneLineAndAddNewline(line));
line.clear();
} else
// ------------------------------------------------------------
Expand Down
Loading

0 comments on commit 164c19b

Please sign in to comment.