No description
  • Emacs Lisp 79.7%
  • C 13.2%
  • Python 5.4%
  • Shell 1%
  • Makefile 0.7%
Find a file
Kinneyzhang 1bfaae86c7
Some checks failed
Repository structure / structure (push) Has been cancelled
fix(scripts): check secondary jj workspaces
AGENTS.md sends parallel work to `jj workspace add` checkouts, which have
no Git index. The repository checker walked `.jj` metadata and every
ignored file there, so structure-check failed in every such checkout.

The inventory now uses `jj file list`, which snapshots new files and
honors ignore rules, and skips `.jj` in the plain directory fallback.
`--staged` accepts an index-less jj workspace only when `@` is empty and
then checks that sealed working copy.

Validation: python3 -m unittest discover -s tests/tools (70 tests OK);
python3 scripts/workspace.py check OK from a secondary workspace tree.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-25 15:55:54 +08:00
.githooks chore(git): enforce logical commits and structured messages 2026-09-13 11:15:12 +08:00
.github/workflows refactor(api)!: expose the root entry and enforce public contracts 2026-09-13 12:55:21 +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 test(api)!: retain only public contract acceptance 2026-09-13 13:28:25 +08:00
examples refactor(api)!: expose the root entry and enforce public contracts 2026-09-13 12:55:21 +08:00
lisp chore(git): standardize laycat and aliyun delivery 2026-09-13 13:52:53 +08:00
native test(api)!: retain only public contract acceptance 2026-09-13 13:28:25 +08:00
scripts fix(scripts): check secondary jj workspaces 2026-09-25 15:55:54 +08:00
tests build(workspace): remove retired TP provider paths 2026-09-18 17:05:22 +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 refactor(api)!: expose the root entry and enforce public contracts 2026-09-13 12:55:21 +08:00
COPYING Keep license and README files in package root 2026-09-13 10:02:03 +08:00
ekp.el chore(git): standardize laycat and aliyun delivery 2026-09-13 13:52:53 +08:00
Makefile build(workspace): remove retired TP provider paths 2026-09-18 17:05:22 +08:00
README.md chore(policy): use scoped workspace development instructions 2026-09-13 23:34:25 +08:00
README.zh-CN.md chore(policy): use scoped workspace development instructions 2026-09-13 23:34:25 +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

Clone the repository and add its repository root to load-path. Keep dictionaries/ and native/ at the repository 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/.