Emacs-KP: Knuth–Plass line breaking for Emacs, usable standalone or as an Ebox wrap mode
  • Emacs Lisp 76.8%
  • C 12.5%
  • Python 9%
  • Shell 1%
  • Makefile 0.7%
Find a file
Kinneyzhang a1bf446278
Some checks failed
Repository structure / structure (push) Has been cancelled
chore(scripts): sync shared workspace tooling
Copy the shared tooling maintained in the workspace root, as of
5de8e6457c52 feat(release): carry packages other authors build with ETAF:

- scripts/package_archive.py

Validation: workspace.py seal-sync found each copy identical to the
committed root tooling and kept this commit only after
check-repository.py --staged passed on it.
2026-10-22 13:15:54 +08:00
.githooks chore(git): enforce logical commits and structured messages 2026-09-13 11:15:12 +08:00
.github/workflows chore(scripts): sync shared workspace tooling 2026-10-13 01:37:25 +08:00
benchmarks refactor(api)!: expose the root entry and enforce public contracts 2026-09-13 12:55:21 +08:00
dictionaries refactor: separate plugin tests from development scripts 2026-09-13 11:13:09 +08:00
docs docs(ekp): replace the package manual with the reference manual 2026-10-12 21:20:10 +08:00
examples refactor(api)!: expose the root entry and enforce public contracts 2026-09-13 12:55:21 +08:00
lisp chore(contact): use the current maintainer address 2026-10-21 20:04:07 +08:00
native test(api)!: retain only public contract acceptance 2026-09-13 13:28:25 +08:00
scripts chore(scripts): sync shared workspace tooling 2026-10-22 13:15:54 +08:00
tests feat(ekp): expose the layout plan readers 2026-10-12 22:46:52 +08:00
.editorconfig chore: establish consistent repository and acceptance policy 2026-09-13 11:10:48 +08:00
.gitignore chore: establish consistent repository and acceptance policy 2026-09-13 11:10:48 +08:00
CHANGELOG.md fix(layout): name the incremental append guard binding 2026-10-17 16:37:39 +08:00
COPYING Keep license and README files in package root 2026-09-13 10:02:03 +08:00
ekp.el chore(contact): use the current maintainer address 2026-10-21 20:04:07 +08:00
Makefile build(workspace): remove retired TP provider paths 2026-09-18 17:05:22 +08:00
README.md docs: describe package.el installation 2026-10-21 19:47:17 +08:00
README.zh-CN.md docs: describe package.el installation 2026-10-21 19:47:17 +08:00

Emacs-KP: Knuth-Plass Line Breaking for Emacs

Source layout: add the repository root to load-path and use (require 'ekp). The supported API and usage notes are in ekp.el; implementation modules live in lisp/.

中文文档 | Developer Guide

Emacs-kp implements the Knuth-Plass optimal line breaking algorithm with full support for CJK (Chinese, Japanese, Korean) and Latin mixed text typesetting, entirely inside Emacs.

Features

  • Optimal line breaking — the Knuth-Plass dynamic program finds the globally optimal set of breaks for a paragraph, not greedy first-fit.
  • CJK support — every CJK character is a breakable box; kinsoku rules keep punctuation attached (,。 never start a line, 「《 never end one); dedicated inter-CJK and CJK↔Latin spacing.
  • Hyphenation — Frank Liang's algorithm (the TeX algorithm) with 49 checksum-pinned Hunspell pattern dictionaries bundled.
  • Pixel-accurate justification — one semantic layout plan drives both renderers. The string API uses pixel spaces; buffer layout combines space-width with absolute-pixel min-width, so it works with variable-width fonts without inserting layout characters.
  • Clean editable buffers — buffer commands create no overlays and add no glue spaces, soft newlines, or discretionary hyphens to the character stream. buffer-string, char-after, search, syntax, save, and ordinary Elisp text consumers see the source characters.
  • Text properties preserved — faces, colors and other properties survive justification; inserted hyphens inherit the face of the word they break.
  • Robust on hard input — unprotected overlong tokens (URLs, long words at narrow widths) degrade to emergency breaks instead of losing text; every input produces output.
  • Optional C module — a dynamic module runs the DP in C with a thread pool that processes paragraphs in parallel (see benchmarks).

Requirements

  • Emacs 29.1+ (uses string-pixel-width and object-intervals)
  • Optional, for the C module: a C11 compiler and pthreads

Installation

With package.el, install the package from your archive of choice. The package keeps dictionaries/ and native/ next to lisp/, and package-install places them together, so no extra path setup is needed.

From source, add the repository root to load-path and keep dictionaries/ and native/ at that root:

(add-to-list 'load-path "/path/to/emacs-kp")
(require 'ekp)
(require 'ekp)   ; buffer/region commands

Byte-compiling is strongly recommended — the Elisp engine is about 10× faster compiled.

Quick Start

(require 'ekp)

;; Justify a paragraph to 600 pixels
(insert (ekp-pixel-justify "Your paragraph text here..." 600))

;; Find the best width in a range; returns (justified-text . width)
(ekp-pixel-range-justify "Your text" 400 800)

Multiline strings are treated as one paragraph per line; blank lines are preserved.

cd native && make PROFILE=portable # default; produces ekp.dylib/.so/.dll
(ekp-c-module-load)     ; prints "ekp-c module loaded (version 1.6, N threads)"
(ekp-c-module-build)    ; prompts for portable/native/debug/sanitize

Once loaded (and since ekp-use-c-module defaults to t), all justification calls automatically use the C engine. The Elisp and C engines produce identical output; Elisp is the always-available path when no module is enabled or C returns no result. An enabled module signal is surfaced as a backend contract failure. If the module on disk is older than the Elisp code expects, loading refuses with a message asking you to rebuild.

Automatic live append has a separate ekp-auto-justify-native-append switch, enabled by default. When a compatible module is already loaded, auto-mode may use it for the prepared append DP even if ekp-use-c-module is nil; full string/buffer layout still follows ekp-use-c-module. Set the new switch to nil to force pure-Elisp live append, or when the module is unavailable it falls back automatically.

Complete usage and interface contracts.

Development

After cloning, run make setup-hooks. Before submitting a change, run make check; make structure-check is the fast organization gate.

docs/architecture.md · CHANGELOG.md

make check runs structure checks, compilation and the public acceptance scenarios listed in tests/acceptance.json. make test runs the same public API suite. The inventory covers every maintained Lisp test. GUI and performance checks use separate targets.

Source layout

Add the repository root to load-path and require ekp. The root entry loads the implementation in lisp/ and documents the supported public APIs in its Commentary. Package archives include both the root entry and lisp/.