Box layout, rendering and incremental publication engine for Emacs text interfaces
  • Emacs Lisp 92.5%
  • Python 7%
  • Makefile 0.3%
  • Swift 0.2%
Find a file
Kinneyzhang f3c3401efb
Some checks are pending
Repository structure / structure (push) Waiting to run
fix(viewport): a message borrows lines, it does not freeze the viewport
A page mounted in a small window kept that size after the frame grew: the mount
still reported the old rows, so it drew a small block in a large window.

`ebox--viewport-transient-space-borrow-p' answers "a message is showing" for any
frame, and the resize path treated that as borrowed space and skipped the
refit.  A message only takes the echo area's line or two, so only a small height
drop can be borrowed; a bigger one is the user resizing and is measured again,
message or not.

Validation: make check — 184 tests, 179 as expected, 5 skipped, none unexpected;
tool tests OK.  Reproduced on a 40x17 mount in a frame grown to 205x51: the page
stayed laid out for 40 rows before and follows the window after.
2026-11-08 15:45:41 +08:00
.githooks chore(git): enforce logical commits and structured messages 2026-09-13 11:15:13 +08:00
.github/workflows chore(scripts): sync shared workspace tooling 2026-10-13 01:37:24 +08:00
benchmarks test(ebox): cover modal backdrop filtering in the property matrix 2026-10-15 21:05:12 +08:00
docs fix(measure): size the line from body fonts instead of shrinking CJK 2026-11-06 16:52:00 +08:00
lisp fix(viewport): a message borrows lines, it does not freeze the viewport 2026-11-08 15:45:41 +08:00
native/emoji feat(ebox): add rounded backgrounds, image insets and emoji images 2026-10-09 22:42:36 +08:00
scripts fix(viewport): a message borrows lines, it does not freeze the viewport 2026-11-08 15:45:41 +08:00
tests fix(measure): size the line from body fonts instead of shrinking CJK 2026-11-06 16:52:00 +08:00
.editorconfig chore: establish consistent repository and acceptance policy 2026-09-13 11:10:49 +08:00
.gitignore chore: establish consistent repository and acceptance policy 2026-09-13 11:10:49 +08:00
AGENTS.md docs(agents): note that node bounds follow the box, not the text 2026-11-01 21:43:55 +08:00
CHANGELOG.md fix(measure): size the line from body fonts instead of shrinking CJK 2026-11-06 16:52:00 +08:00
CHANGELOG.zh-CN.md fix(measure): size the line from body fonts instead of shrinking CJK 2026-11-06 16:52:00 +08:00
ebox.el fix(measure): size the line from body fonts instead of shrinking CJK 2026-11-06 16:52:00 +08:00
LICENSE Prepare standalone distribution and harden clipping and interaction 2026-09-10 00:22:34 +08:00
Makefile build(ebox): add a native compilation target 2026-10-08 21:10:57 +08:00
README.md docs(ebox): link the manual through its published site 2026-10-13 00:11:40 +08:00
README.zh-CN.md docs(ebox): link the manual through its published site 2026-10-13 00:11:40 +08:00
release-dependencies.json chore: adopt the GitHub origin in links and tooling 2026-10-13 00:48:59 +08:00

Ebox

中文

Ebox is a retained text-layout engine for Emacs buffers. It builds mutable node trees of text, box, row, column, flex, grid and image nodes, computes ECSS-backed styles, lays them out in pixel-aware horizontal geometry and line-based vertical geometry, and writes the result into an Emacs buffer. Once mounted, callers mutate the same tree; Ebox tracks dirty nodes and rewrites only the buffer lines and line parts that changed.

Use Ebox directly when a package needs low-level layout and buffer rendering. Use the sibling ETAF package when an application also needs components, reactive state or application lifecycle services.

Capabilities

  • Build retained trees with ebox-node-create, ebox-text-create or the author DSL consumed by ebox-build.
  • Mount a root in a buffer with ebox-mount or render detached output with ebox-render.
  • Update nodes in place with text, property, state and child-list mutations; ebox-with-batch coalesces many mutations into one flush.
  • Style nodes with inline properties and ECSS scopes, then query mounted trees with selectors.
  • Compose rows, columns, flex and grid containers; measure text and prepared character-grid images.
  • Provide native Emacs interaction through text properties: keymaps, help, pointer shapes, hover content, focus, activation, scrolling and input sessions.
  • Refit mounted buffers when their viewport changes and observe each flush with update reports.

Prerequisites

Dependency Required for
Emacs 29.1 or newer All Ebox use.
ECSS 0.1.0 or newer Style schema, selectors, cascade and scopes.
Optional chafa or ffmpeg executables Text-mode image conversion before falling back to placeholders.

Ebox has no native module. Image preparation may also use Emacs graphical image support when it is available.

Installation from a source checkout

Add ECSS and Ebox source roots to load-path, then require the package entry:

(add-to-list 'load-path "/path/to/ecss")
(add-to-list 'load-path "/path/to/ebox")
(require 'ebox)

For interactive speed, run make native in the checkout after each update. It byte-compiles Ebox and stores native code in your eln-cache, which Emacs loads in place of the bytecode without further configuration, even when JIT native compilation is disabled. A source file edited later runs as bytecode until the next make native.

Checkout users require only ebox; implementation files under lisp/ are private. The authoritative API inventory is the Commentary in ebox.el, and workflows are in the ETAF Reference Manual.

Minimal working example

The following example was verified with python3 scripts/elisp.py run -p ebox from the workspace root.

(require 'ebox)

(let* ((root
        (ebox-build
         '(column :padding ((lh 1) (ch 2))
                  :border ((px 1) solid "#8A93A6")
                  (text :color "#263244" "Hello Ebox")
                  (row :item-gap (ch 1)
                       (box "Left")
                       (box "Right")))))
       (buffer (ebox-render-to-buffer "*Ebox Example*" root
                                      :width 480 :height 12)))
  (with-current-buffer buffer
    (buffer-substring-no-properties (point-min) (point-max))))

ebox-render-to-buffer mounts the retained root. Later calls such as ebox-node-set-text, ebox-node-set-props and ebox-node-insert mutate that same tree and flush the affected buffer lines.

Documentation

Checks

From the workspace root:

make -C ebox structure-check
make -C ebox check

make -C ebox check includes structure validation, byte compilation and the public acceptance scenarios listed by the package.

License

Ebox is distributed under GPL-3.0-or-later. See LICENSE.