Skip to content

wieslawsoltes/PretextSharp

Repository files navigation

Pretext

CI NuGet NuGet Downloads Docs Targets SkiaSharp 3.119.1 License: MIT

Universal text preparation and line layout for any SkiaSharp-based UI, with grapheme-aware wrapping, locale-aware segmentation, bidi support, and streaming line walking.

The core Pretext package targets netstandard2.0, net461, net6.0, net8.0, and net10.0. The Pretext.Uno companion package and sample app remain net10.0-desktop.

PretextSharp is a .NET/C# port of the original pretext project by Cheng Lou.

Documentation site: wieslawsoltes.github.io/PretextSharp

Key documentation:

NuGet Packages

Package Name NuGet Downloads Description
Pretext NuGet NuGet Downloads Universal text preparation and line layout engine for any SkiaSharp-based UI.
Pretext.Uno NuGet NuGet Downloads Uno-specific controls and obstacle-aware layout helpers built on top of Pretext.

Features

  • Prepare text once and reuse the result across repeated layout passes with Prepare and PrepareWithSegments.
  • Compute fast aggregate metrics with Layout, or materialize full line data with LayoutWithLines.
  • Stream line geometry incrementally with LayoutNextLine, LayoutNextLineRange, and WalkLineRanges for custom layout engines.
  • Re-materialize text lazily with MaterializeLineRange after cheap geometry-only probing.
  • Measure widest-line geometry without allocating text via MeasureLineStats and MeasureNaturalWidth.
  • Handle ordinary spaces, preserved spaces, tabs, hard breaks, non-breaking spaces, zero-width breaks, and soft hyphens.
  • Support WordBreakMode.KeepAll for CJK-focused no-space wrapping behavior.
  • Build rich inline flows with PrepareRichInline, WalkRichInlineLineRanges, and MaterializeRichInlineLineRange.
  • Support multilingual text with locale-aware segmentation on desktop targets and bidi-aware segment levels.
  • Depend only on SkiaSharp in the core library so the package can be used outside Uno as well.
  • Ship with a published Pretext.Uno companion library for reusable Uno host controls and obstacle-aware flow helpers.
  • Ship with deterministic parity tests and a Uno sample app that demonstrates bubbles, masonry, editorial, justification, rich-inline, and virtualized markdown chat layouts.

Core API

API Purpose
Prepare Prepare text for repeated layout when you only need aggregate metrics.
PrepareWithSegments Prepare text and expose segments, widths, break metadata, and segment levels.
Layout Return line count and total height for a given width and line height.
LayoutWithLines Return materialized line text and line widths.
LayoutNextLine Stream the next line from a given cursor for custom layout flows.
LayoutNextLineRange Stream geometry-only line ranges without materializing text.
MaterializeLineRange Turn a LayoutLineRange back into a materialized LayoutLine.
WalkLineRanges Iterate line geometry without allocating full line text.
MeasureLineStats Return line count plus widest line width for a prepared block.
MeasureNaturalWidth Return the widest unwrapped line width for prepared text.
PrepareRichInline Prepare multi-item inline flow with collapsed boundary whitespace and atomic items.
WalkRichInlineLineRanges Stream rich-inline line ranges without materializing fragment text.
MaterializeRichInlineLineRange Materialize one streamed rich-inline line when you actually need fragment text.
MeasureRichInlineStats Measure rich-inline line count and max line width.
ProfilePrepare Measure preparation cost for profiling and diagnostics.
SetLocale Override locale-sensitive segmentation behavior when needed.
ClearCache Reset cached font state and prepared segment text caches.

API Selection

Need Start with
Line count and total height only Prepare + Layout
Actual line text and widths PrepareWithSegments + LayoutWithLines
One line at a time in a custom loop PrepareWithSegments + LayoutNextLine
Geometry only, fewer allocations PrepareWithSegments + WalkLineRanges
Rich inline fragments with atomic chips or badges PrepareRichInline + WalkRichInlineLineRanges
Preparation cost diagnostics ProfilePrepare

Quick Start

Install from NuGet:

dotnet add package Pretext

Supported target frameworks for the core package:

  • netstandard2.0
  • net461
  • net6.0
  • net8.0
  • net10.0

Then prepare and lay out text:

using Pretext;

const string text = "Hello soft\u00ADwrapped world";
const string font = "16px Inter";
const double lineHeight = 20;

var prepared = PretextLayout.PrepareWithSegments(text, font);
var metrics = PretextLayout.Layout(prepared, maxWidth: 160, lineHeight);
var lines = PretextLayout.LayoutWithLines(prepared, maxWidth: 160, lineHeight);

Console.WriteLine(metrics.LineCount);
Console.WriteLine(metrics.Height);

foreach (var line in lines.Lines)
{
    Console.WriteLine($"{line.Text} ({line.Width})");
}

If the prepared text is empty after normalization, Layout returns new LayoutResult(0, 0). If a container in your UI must still reserve one visual row, clamp with Math.Max(1, metrics.LineCount) in the caller instead of expecting Pretext to synthesize a blank line.

The core package exposes the Pretext namespace and is not tied to Uno. Use it anywhere you use SkiaSharp.

The font argument is a CSS-like subset such as 16px Inter, italic 16px Georgia, or 700 18px "IBM Plex Sans". Line height is supplied separately to layout calls.

Use WhiteSpaceMode.PreWrap when your layout needs preserved spaces, tabs, or hard breaks:

var prepared = PretextLayout.PrepareWithSegments(
    "foo\tbar\nbaz",
    "16px Inter",
    new PrepareOptions(WhiteSpaceMode.PreWrap));

Use WordBreakMode.KeepAll when CJK-heavy text should avoid ordinary intra-run breaks:

var prepared = PretextLayout.PrepareWithSegments(
    "日本語foo-bar",
    "16px Inter",
    new PrepareOptions(WordBreak: WordBreakMode.KeepAll));

Use the rich-inline helper when paragraph text and atomic inline boxes must share one flow:

var flow = PretextLayout.PrepareRichInline(
[
    new RichInlineItem("Ship ", "16px Inter"),
    new RichInlineItem("@maya", "700 12px Inter", RichInlineBreakMode.Never, extraWidth: 18),
    new RichInlineItem("'s note wraps cleanly.", "16px Inter"),
]);

PretextLayout.WalkRichInlineLineRanges(flow, 180, line =>
{
    var materialized = PretextLayout.MaterializeRichInlineLineRange(flow, line);
    Console.WriteLine(string.Join("", materialized.Fragments.Select(f => f.Text)));
});

Uno Companion

Install the Uno companion package when you want the reusable Uno-specific helpers on top of the core engine:

dotnet add package Pretext.Uno

It brings the Pretext core package transitively and exposes:

  • Pretext.PretextLayout
  • Pretext.Uno.Controls.StretchScrollHost
  • Pretext.Uno.Controls.UiRenderScheduler
  • Pretext.Uno.Layout.PreparedTextMetrics
  • Pretext.Uno.Layout.ColumnFlowLayout
  • Pretext.Uno.Layout.ObstacleLayoutHelper

Sample App

The sample app lives in samples/PretextSamples and demonstrates the library in visually different layouts. It uses Uno Platform, exercises the core Pretext APIs together with the Pretext.Uno companion helpers, and keeps only sample-specific UI/theme code in the sample tree.

  • Overview
  • Accordion
  • Bubbles
  • Masonry
  • Rich Text
  • Markdown Chat
  • Dynamic Layout
  • Editorial Engine
  • Justification Comparison
  • Variable ASCII

Run it with:

dotnet run --project samples/PretextSamples/PretextSamples.csproj -f net10.0-desktop

Building

Prerequisites

  • .NET 10 SDK for building this repository
  • Uno.Sdk 6.5.x for the sample app only

Build, test, and pack

dotnet build PretextSamples.slnx
dotnet test tests/Pretext.Uno.Tests/Pretext.Uno.Tests.csproj
dotnet pack src/Pretext/Pretext.csproj -c Release
dotnet pack src/Pretext.Uno/Pretext.Uno.csproj -c Release

Docs and CI

The repository includes:

  • ci.yml for multi-platform build, test, docs validation, and preview package generation
  • docs.yml for GitHub Pages deployment
  • release.yml for tag-driven packing, optional NuGet publication, and GitHub release creation
  • a Lunet docs site in site/

The docs cover:

  • installation and namespace/package selection
  • font strings, measurement, and prepared-text lifecycle
  • whitespace and break behavior, locale-aware segmentation, and bidi
  • practical Uno and generic SkiaSharp integration patterns
  • full reference coverage for the public core API and Pretext.Uno helpers

Project Structure

src/
  Pretext/
  Pretext.Uno/
tests/
  Pretext.Uno.Tests/
samples/
  PretextSamples/
site/

Attribution

The core Pretext implementation in this repository is ported from the original pretext project by Cheng Lou. This repository adapts that work to .NET, SkiaSharp, packaging, tests, samples, and companion Uno helpers.

License

MIT. See LICENSE.

About

Universal text preparation and line layout for any SkiaSharp-based UI, with grapheme-aware wrapping, locale-aware segmentation, bidi support, and streaming line walking.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors