- Emacs Lisp 95.4%
- Python 2.5%
- Swift 1.1%
- Shell 0.8%
- Makefile 0.2%
|
Some checks are pending
Repository structure / structure (push) Waiting to run
A failed refresh kept its interval, so an offline reader or an expired login retried on every tick, and a backend offering a version token had nowhere to keep it. The cache now records failures through note-success/note-failure: an unknown error backs the next attempt off (the interval, then double, capped at max-backoff) and a stop-code (auth, blocked) pauses background refreshes until a load succeeds. `put ... :version` keeps an opaque token, `touch` refreshes an entry after a not-modified reply without touching its rows, and armed/busy accessors keep the surface explicit. The module is also listed in the Makefile sources. Validation: make check (277 acceptance tests including eight list-cache scenarios, structure/API/tool checks). |
||
|---|---|---|
| .githooks | ||
| .github/workflows | ||
| benchmarks | ||
| docs | ||
| examples | ||
| lisp | ||
| scripts | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CHANGELOG.zh-CN.md | ||
| etaf.el | ||
| Makefile | ||
| README.md | ||
| README.zh-CN.md | ||
ETAF
Source layout: add the repository root to load-path and use
(require 'etaf). The supported API and usage notes are in
etaf.el; implementation modules live in lisp/.
ETAF builds text applications from reusable Components above the independent Ebox layout and rendering engine.
Start with etaf-view and etaf-mount. Properties precede children in
(name :property value ... child ...); property values are ordinary Elisp.
Evaluate the complete example, switch to *etaf-hello*, and activate “Say hello”:
;;; -*- lexical-binding: t; -*-
(require 'etaf)
(etaf-mount
"*etaf-hello*"
(etaf-view
(column
(text :font-weight 'bold "Hello")
(box :ref 'hello :role 'button :tab-index 0
:on-press (lambda () (message "Hello ETAF"))
"Say hello"))))
A Component receives declared props and optional content through slots. Use the
exact name passed to etaf-define-component; the registry creates no aliases.
(expr FORM) evaluates one child expression. In a structural child position it
may return nil, text, a typed Host or Component View, or a proper sequence of
those values. Inside text, an expression must return a string.
;;; -*- lexical-binding: t; -*-
(require 'etaf)
(etaf-define-component demo-card (&key title)
:view
(column
(text :font-weight 'bold (expr title))
(slot)
(slot :name 'footer)))
(etaf-mount
"*etaf-card*"
(etaf-view
(demo-card :title "Account"
(text "Connected")
(slot :name 'footer (text "Footer")))))
Use :bindings to initialize named state once per retained instance. The View
and its callbacks use these handles directly. Add :setup for lifecycle work;
:render and etaf-node remain available for programmatic View construction.
;;; -*- lexical-binding: t; -*-
(require 'etaf)
(etaf-define-component demo-counter ()
:bindings ((count (etaf-ref 0)))
:view
(column
(text (expr (format "Count: %d" (etaf-value count))))
(box :role 'button :tab-index 0
:on-press (lambda () (cl-incf (etaf-value count)))
"Increment")))
(etaf-mount "*etaf-counter*" (etaf-view (demo-counter)))
Keep etaf-value reads inside the property or expr that should update. Event
callbacks capture the named handles and the current render's lexical props.
Use a lexical-binding .el file for reusable application code. etaf-node is
available for programmatic View builders. Context, Data, Behavior, and named
Actions are optional capabilities; simple callbacks need no Action registration.
Use exact catalog names such as etaf-button after (require 'etaf-ui).
Core does not load .etaf files: Playground treats them as inert structure,
with its explicit companion registration handling executable Elisp.
Performance records
ETAF provides an independent, opt-in, application-neutral timing recorder. It consumes public Runtime observer reports without advice or private cross-package probes. Runtime operations such as Event, Action, mount, flush, and unmount are recorded automatically; Ebox rendering and publication, Data, Resource, and SQLite stages inside the same operation are correlated by sequence.
(require 'etaf)
;; In a buffer with a mounted ETAF Runtime:
(etaf-performance-mode 1)
;; Use any mounted ETAF application normally.
(etaf-performance-show)
For an interactive capture, run M-x etaf-performance-clear first. After
reproducing the operations, press c in the panel (or run
M-x etaf-performance-copy-report) to copy a complete report. Press w (or
run M-x etaf-performance-export) to save the same report as an .eld file.
The portable report includes the Emacs/display environment, power source,
low-power mode, native-JIT state, system load, grouped p50/p95/max, individual
operations, GC deltas, and ordered provider stages. The panel header exposes
the same environment context so a machine-wide slowdown is not mistaken for
one package hotspot.
The *ETAF Performance* panel shows operation IDs, generation changes, total
latency, GC deltas, and each flat provider stage in sequence. Provider stages
may overlap, so they are not presented as exclusive/self time. Records are
bounded by etaf-performance-max-records; disabling the mode only detaches the
Runtime observer and never rewrites functions. etaf-performance-summary
computes operation p50/p95/max statistics on demand, while
etaf-performance-operation-stage-summary groups one operation's flat stages
by provider category. etaf-performance-records returns defensive operation
and stage snapshots; caller mutation cannot rewrite retained history.
Pass a numeric observer runtime ID to etaf-performance-records to select one
mount's history even when a buffer name is reused. Summary and report functions
use all retained records when called without an argument; an explicit nil
means an empty selection. The exported environment describes report generation,
not each historical operation. These synchronous operation durations do not
measure physical input-to-presentation latency; use the GUI measurement entry
in README.md for per-action condition checks.
Use etaf-performance-call-operation or
etaf-performance-with-operation to trace an arbitrary operation that has no
built-in public boundary. Both delegate to the same Runtime operation boundary;
they do not create a second timer.
Executable examples
The examples/ directory contains three core-only best-practice applications: retained state and Actions, Data Controller ownership, and Resource error/cleanup lifecycle. They are byte-compiled and driven through mounted public event paths by make check.
(add-to-list 'load-path "/path/to/github/etaf/examples")
(require 'etaf)
(etaf-counter-example-open)
Documentation
- Architecture · 中文架构
- User guide · 中文用户指南
- Implementation plan · 中文实施计划
- Module-boundary proposal (unimplemented) · 模块边界提案(未实现)
- Best-practice examples · 中文示例
Independent packages
| Package | Role |
|---|---|
etaf-ui |
Official Component catalog: Button, Checkbox, Label, Panel, and DataGrid. |
etaf-db |
Database backend package, currently providing SQLite; the Data Controller remains in ETAF core. |
etaf-playground |
ETAF examples, with the UI catalog loaded only when requested. |
ebox-playground |
Ebox-only layout examples, independent from ETAF. |
There is no separate etaf-data install: Data is a core ETAF capability. There is no generic etaf-adapters package: other databases, services, files, or ORMs should provide concrete Data Source packages with explicit names.
Load and verify
Install ECSS before Ebox, then install ETAF. ETAF declares ECSS directly to
preserve deferred cascade values when resolving Theme tokens. Rendering and Host
final-accept authority use Ebox's public contracts. The renderer requires Ebox
framework SPI v3 and ebox-publication/v1; a missing, malformed, or incompatible
provider fails during ETAF bootstrap. ETAF snapshots one immutable render port
for the Emacs process.
During development, load the sibling Ebox checkout before ETAF:
(add-to-list 'load-path "/path/to/github/ecss")
(add-to-list 'load-path "/path/to/github/ebox")
(add-to-list 'load-path "/path/to/github/etaf")
(require 'etaf)
Run the complete local gate:
make check EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
The core gate byte-compiles the implementation, runs the core/Data/Resource tests, and checks documentation/API boundaries. Run make check in the sibling etaf-ui, etaf-db, etaf-playground, and ebox-playground repositories for their independent gates; none is loaded by the core facade.
Development
After cloning, run make setup-hooks. Before submitting a change, run make check; make structure-check is the fast organization gate.
docs/manual.md · 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 etaf. 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/.