kashida 0.0.3
kashida: ^0.0.3 copied to clipboard
Finding kashida (tatweel) insertion points and priorities, driven by a small pattern language.
kashida #
A Dart port of raqim-kashida: find kashida (tatweel, U+0640) insertion points and priorities in Arabic and Syriac text, driven by a small pattern language.
Given a string and a compiled pattern set, the package finds connections that may take a kashida and a priority from 0–9 (higher is better). Detection is based on text analysis and kashida rules. It does not take fonts or shaping into account by itself.
There are three separate steps:
- Find points —
findKashidaPoints - Insert a fixed number of tatweels at every point —
insertKashida(not justification) - Wrap to a width and fill by priority —
layoutParagraph,layoutParagraphStyled, or theKashidaTextwidget
KashidaPoint.index is a grapheme index. Do not pass it to
substring; use point.endOffsetIn(text) or insertKashidaAt.
For background, see Khaled Hosny’s introduction to raqim-kashida and the interactive demo.
Demo #
The example’s Justify tab: pick a face and a pattern set, then fill a pixel width. Last line of each paragraph stays short.
[Justifying a paragraph with kashida]
Features #
- Compile pattern text, including
useof a built-in set - Built-in sets:
arabic-naskh,arabic-nastaliq,arabic-simple,syriac - Optional stripping of bare tatweels (mark-seated tatweels are kept)
- Insert tatweel into a string (
insertKashida) without choosing a font - Wrap and fill lines given a width and a
measurecallback - Grapheme-cluster indices, joining analysis, and rasm folding matching the original library
- A Flutter example with three tabs (justify, find & insert, custom rules); Arabic and Syriac faces are bundled so they work on macOS and web
Getting started #
Add the package to your pubspec.yaml:
dependencies:
kashida: ^0.0.3
Then:
import 'package:kashida/kashida.dart';
Usage #
import 'package:kashida/kashida.dart';
void main() {
final set = requiredBuiltinPatternSet('arabic-simple');
final found = findKashidaPoints('بيت', set);
for (final point in found.points) {
print('${point.priority} @ grapheme ${point.index}');
}
// Same count at every allowed join — not a justified line.
print(insertKashida('بيت', set));
}
findKashidaPointsIn (also named findKashidaPointsPatterns) skips stripping.
To justify to a pixel width in Flutter:
final set = requiredBuiltinPatternSet('arabic-naskh');
// Widget: leftover space goes between words.
KashidaText(
paragraph,
patternSet: set,
width: 320,
style: const TextStyle(fontSize: 22),
);
// Or measure yourself:
final lines = layoutParagraphStyled(
paragraph,
set,
const TextStyle(fontSize: 22),
width: 320,
);
A measure callback is the font hook if you are not using Flutter painting:
layoutParagraph(
paragraph,
set,
width: 320,
measure: (line) => /* width of line in the same units as 320 */,
);
Custom rules can extend or override a built-in set:
final set = compilePatternText('''
use arabic-naskh
* 2 @Heh .
''');
The pattern language is the same as upstream. See the
raqim-kashida README
for the grammar, length guards, priorities, and ! suppression.
Built-in pattern sets #
| Name | Intended for |
|---|---|
arabic-naskh |
Classical naskh and naskh-like faces |
arabic-nastaliq |
Nastaliq (naskh rules plus nastaliq tailoring) |
arabic-simple |
Simple / kufic-style faces (Microsoft-style newspaper rules) |
syriac |
Syriac, following the LibreOffice / expert guidelines |
requiredBuiltinPatternSet(name) is the usual lookup (throws if unknown).
builtinPatternSet(name) returns null instead, for probing names.
Example app #
example/ is a three-tab playground for the public API:
- Justify —
KashidaText/layoutParagraphStyledfills a pixel width - Find & insert —
findKashidaPoints,insertKashida,layoutParagraph - Rules —
compilePatternText, built-in lookup,CompileError
Arabic and Syriac faces are bundled in example/fonts/ (OFL) so they load on
macOS as well as web, with no runtime Google Fonts download. Switching to the
Syriac pattern or Noto Sans Syriac loads a Syriac sample.
cd example
flutter run
Acknowledgements #
This package is a Dart/Flutter port of raqim-kashida by Khaled Hosny and Alif Type.
Thank you to Khaled and everyone behind raqim-kashida for the research, the pattern language, the built-in rule sets, and the tests this port follows. Any mistakes in the Dart implementation are ours.
Additional information #
Issues and contributions are welcome on the package repository. Please include a small Arabic or Syriac sample and the pattern set name when reporting justification or matching bugs.
Insertion is U+0640. Filling a pixel width needs a font-aware measure
or KashidaText. Leftover space thinner than one tatweel is returned as
unusedWidth and spread between words by the widget.