kashida_core
Pure Dart library for kashida (tatweel, U+0640) in Arabic and Syriac
text: compile a small pattern language, find insertion points and priorities,
insert a fixed count, or wrap and fill a target width with a caller-supplied
measure callback.
No Flutter dependency. For TextPainter measuring and the KashidaText
widget, use kashida, which re-exports
this package.
Features
- Compile pattern text, including
useof a built-in set - Built-ins:
arabic-naskh,arabic-nastaliq,arabic-simple,syriac - Find points (
findKashidaPoints) with optional bare-tatweel stripping (mark-seated tatweels are kept) - Insert a fixed tatweel count at every allowed join (
insertKashida) layoutParagraph— greedy wrap and fill by priority givenwidthandmeasure- Optional
justifyLastLine— stretch the last line of each paragraph (off by default) - Grapheme-cluster indices, joining analysis, and rasm folding
Getting started
dependencies:
kashida_core: ^0.1.2
import 'package:kashida_core/kashida_core.dart';
Usage
Find points or insert a fixed count
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 — does not wrap or honor a width.
print(insertKashida('بيت', set));
KashidaPoint.index is a grapheme index. Do not pass it to substring;
use point.endOffsetIn(text) or insertKashidaAt.
findKashidaPointsIn (also named findKashidaPointsPatterns) skips
stripping bare tatweel.
Justify to a width
final lines = layoutParagraph(
paragraph,
set,
width: 320,
measure: (line) => /* width of line in the same units as 320 */,
// justified: true, // default
// justifyLastLine: false, // default — last line stays short
);
Each \n starts a new paragraph with its own last line. When
justified: false, no line stretches and justifyLastLine is ignored.
Custom rules
final set = compilePatternText('''
use arabic-naskh
* 2 @Heh .
''');
Pattern grammar details: raqim-kashida README.
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) throws if unknown;
builtinPatternSet(name) returns null instead.
Layout behavior
- Greedy wrap on whitespace; a word wider than the target overflows
- Leftover thinner than one tatweel →
KashidaLine.unusedWidth - Last line short unless
justifyLastLine: true
Design notes: doc/design.md.
Regenerating Unicode tables
Joining type/group tables are generated from Unicode 17.0.0 UCD files:
dart run tool/generate_joining_tables.dart
Downloads are cached under tool/ucd/ (gitignored). Generated
joining_tables.dart is committed; CI does not hit the network to regenerate.
Acknowledgements
Port of raqim-kashida by Khaled Hosny and Alif Type. Any mistakes in the Dart implementation are ours.
Additional information
Issues: github.com/byshy/kashida/issues. Include a small Arabic or Syriac sample and the pattern set name when reporting matching or layout bugs.
To publish a new version from this monorepo subdirectory:
./tool/publish.sh
(dart pub publish directly under kashida_core/ fails while the package
lives in a git subdirectory; the script publishes from a clean temporary tree.)
Libraries
- kashida_core
- Finding kashida (tatweel) insertion points and priorities, driven by a small pattern language.