Commit Graph

14 Commits

Author SHA1 Message Date
Kinneyzhang
edc51194b6 chore: migrate conditional bindings for Emacs 31 2026-08-26 00:09:44 +08:00
Kinneyzhang
0d35358e05 refactor(tp)!: implement retained reactive runtime
Replace the legacy managed layer renderer with one independent retained/reactive text runtime. TP now owns exact dependencies, stable objects, marker-backed mounts, property contribution composition, atomic publication, rollback, and direct text-property facades without ECSS or Ebox dependencies.\n\nBREAKING CHANGE: remove tp-render, tp-stack, scan-driven managed layers, inline runtime metadata, TP-owned CSS cascade APIs, and dollar-variable declarations.\n\nVerified: 290/290 ERT, shuffled 290/290 (seed 20260806), 8/8 doctests, WERROR compile-all, checkdoc, package-lint, diff-check, and isolated TP-only load.
2026-08-07 00:39:50 +08:00
Kinneyzhang
ef31a67beb feat(tp): add schema-driven cascade engine
Introduce the pure TP 1.0 property schema, selector, cascade, custom-property, computed-value, provenance, and Emacs projection kernel. Compile static legacy layer definitions into canonical named styles without freezing parameterized or reactive definitions.\n\nVerified with 667 ERT tests, 92 doctests, shuffled seed 20260806, and compile-all with warnings as errors.
2026-08-06 02:12:32 +08:00
Kinneyzhang
972b6d4e4c Complete text-property facade and managed lifecycle
Add canonical query semantics, managed metadata and transactions, overlay-aware lookup, reproducible benchmarks, and synchronized API documentation.
2026-07-28 22:42:55 +08:00
Kinneyzhang
8c28361640 Add prefix-conforming define aliases and export the group props plural
API-NAME-02: tp-define-layer, tp-define-group and tp-define-palette
are new permanent aliases of define-tp, define-tps and
define-tp-palette, each with a real docstring and the defun indent
spec, so C-h f tp-TAB finds the library's definition macros and
package-prefix review passes.  The historical names stay forever;
zero callers change.

API-SYM-01: tp-group-props-with-args is now public, delegating to
the private implementation, mirroring tp-layer-props-with-args -
multi-argument parameterized groups are a public feature (reachable
via tp-put-layer specs) and previously had no public introspection
path.  All four -with-arg/-with-args docstrings now cross-reference
their singular/plural sibling (calling out the one-character name
difference) and their layer/group counterpart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 02:34:31 +08:00
Kinneyzhang
e870b87941 Move the anonymous-layer counter and name generator into tp-layer
tp--anonymous-layer-counter and tp--generate-anonymous-layer-name
lived in tp-core, two modules below their only caller
tp--anonymous-layer-name-for - and the counter was tp-core's only
piece of mutable non-defcustom state.  Anonymous-layer naming is layer
machinery, so move both into tp-layer.el right beside the registry and
the interning function.  tp-core is now pure utilities plus defcustoms.

Also document a deliberate asymmetry that was easy to mistake for an
oversight: tp-layer-reset clears the anonymous-layer registry but the
counter INTENTIONALLY survives it.  Detached strings can outlive a
reset while still carrying tp-anon-N property values, so the counter
must keep increasing monotonically - a post-reset anonymous layer must
never be minted under a name a stale string still holds.  The comment
protects the future registry refactor from "fixing" this wrongly.

Internal symbols only; no API or behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 02:09:58 +08:00
Kinneyzhang
95fb4ae862 Delete the dead layer-expansion pair in tp-layer
tp--expand-layer-to-props-list and tp--expand-props-to-remove were an
orphaned early draft of "expand a layer name into the property keys it
contributes": nothing calls them - the only reference in the whole
tree (sources, tests, doctest, README) is the pair calling each other.
The maintained equivalent of this logic is the inline expansion in
tp-ops's tp--remove-property, which is what tp-remove actually runs;
if deduplication is ever wanted, that copy is the one to extract.

Keeping a second, uncalled implementation of layer expansion around
invites the two to drift apart silently, so remove the 67 dead lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 02:08:41 +08:00
Kinneyzhang
117c714b97 Signal clear arity errors for wrong-arity parameterized-layer calls
Multi-argument parameterized layers silently mis-handled every
wrong-arity call:
- Missing args: cl-progv (since its Emacs 27 rewrite) binds
  parameters beyond the supplied values to nil, never leaving them
  unbound, so (tp-set "s" '(two-arg-layer "red")) quietly produced
  (:foreground "red" :background nil) - while the docstring of
  tp-layer-props-with-args falsely promised an unbound-variable
  error.
- Excess flat-form args fell into extra-props and were applied as
  garbage text-property KEYS with value nil ("green" as a property
  name).
- The stack path (tp-push-layer with one arg for a two-parameter
  layer) fell through tp--normalize-layer-spec's named-inline branch,
  building an odd-length plist and dying with the cryptic "Odd length
  text property list".

Fixes, per site:
- tp-layer-props-with-args checks (length args) against the arglist
  and signals "tp layer NAME takes N argument(s), got M"; its
  docstring now documents the explicit error instead of the
  impossible unbound-parameter story.  Extra values remain ignored
  in this direct call, per the documented contract.
- tp--resolve-props signals the same error after the arity split when
  fewer values were available (covering parameterized groups too),
  and rejects flat-form excess positional args whose first extra
  element is not a symbol (i.e. can never be a property key).
- tp--normalize-layer-spec signals "tp layer NAME expects N args,
  got M" for any parameterized-layer arity mismatch instead of
  falling through to the named-inline branch.

Correct-arity flat, wrapped, extra-props and group behavior is
unchanged (covered by controls in the new tests, which port the
review's verify-arg1 probe).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 01:49:47 +08:00
Kinneyzhang
b49e2740e8 Make GC liveness and track-buffer scans stack-aware; GC moves to tp-layer
tp--buffer-has-layer-region-p tested liveness with a direct tp-name
property search, which only sees the rendered top layer of each run.
A layer buried below a pushed top, or hidden via tp-hide-layer, keeps
its tp-name inside the tp-layers storage property, so:
- tp-gc-anonymous-layers undefined layers a live buffer still held,
  destroying their definitions and reactive deps; pop/show later
  resurfaced text whose reactivity was permanently dead;
- tp-reactive-track-buffer (the documented remedy for the
  string-insertion registration gap) never registered buried or
  hidden layers either, so the gap-closer itself had the gap.

Fix:
- tp-reactive.el gains the shared stack-aware scan
  tp-reactive--buffer-layer-names: a tp--map-intervals walk that
  collects the direct tp-name of each run plus the tp-name of every
  plist inside the run's tp-layers value (read as a plain list of
  plists, so tp-reactive needs nothing from the stack module).
  tp-reactive-track-buffer is rewritten on it.
- tp--buffer-has-layer-region-p is rewritten on the same scan and
  moves - together with tp-gc-anonymous-layers (autoload kept) - from
  tp-render.el into tp-layer.el beside tp--anonymous-layer-registry,
  so the whole anonymous-layer lifecycle (mint, intern, undefine,
  collect) lives in one module and tp-render sheds its only
  non-rendering responsibility.  tp-render's tp--map-layer-buffers
  keeps calling the predicate downward.

Regression tests port the review's gc1/xm02 probes: buried-under-push
kept alive with reactivity surviving a later pop; hidden layer kept
alive with show+setq re-rendering; track-buffer registering buried
and all-hidden layers from inserted strings.  Existing tests cover
the visible-kept and killed-buffer-collected control cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 01:44:06 +08:00
Kinneyzhang
c6fbccf659 Move the layer-stack storage codec from tp-stack down to tp-layer
Behavior-preserving relocation of tp--stack-hidden-p,
tp--stack-props-to-list and tp--stack-build-props into tp-layer.el,
beside their existing dependencies tp--layer-stack-to-list and
tp--build-layer-props.  The codec's only inputs are dash/seq/plist
utilities, so it sits naturally at the layer-definition level, and
the move lets the reactive re-render engine (tp-render.el, which may
not require tp-stack) read and write stack storage without
duplicating format knowledge - the prerequisite for making reactive
updates write through to hidden/buried layer storage.  tp-stack keeps
calling the codec downward; no callers change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 01:36:31 +08:00
Kinneyzhang
507ccf798c Integrate 0.3.0 feature tracks: reactive perf, stack visibility, search/API
Reactive performance (tp-reactive/tp-render/tp-ops): layer->buffer
registry replaces full buffer-list scans on reactive updates, with a
conservative unknown->learning-scan fallback, kill-buffer pruning,
and tp-reactive-track-buffer to close the propertized-string-insert
gap; minimal-diff tp-text replacement preserves point and markers and
makes identical-text updates true no-ops; tp-gc-anonymous-layers
collects interned anonymous layers no registered buffer still shows.

Stack capabilities (tp-stack): tp-hide-layer/tp-show-layer visibility
(hidden layers stay in the stack but do not render; hiding the top
reveals the next visible layer), tp-lower-layer, tp-rotate-layer
DIRECTION/COUNT, tp-layer-stack-at, and modified-run-count returns
with NOERROR options.

Search and layer APIs (tp-search/tp-layer): SUBEXP capture groups and
START/END bounds for tp-regexp-*/tp-match-*, PREDICATE/NOT-CURRENT
exposure on tp-forward/tp-backward/-do (defaults keep 0.2.0 semantics),
multi-argument parameterized layers (define-tp/define-tps arglists of
any arity, tp-layer-props-with-args, tp-layer-arglist), and the
interactive tp-describe-layer.

79 new regression tests; combined suite 522/522 green, shuffled run
green, doctests 63/63, byte-compile clean with warnings-as-errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 00:32:47 +08:00
Kinneyzhang
36328a1cca Phase 1: CI matrix, zero-warning compile, shuffled runner, autoloads
Byte-compile warnings swept 57 -> 0 across all modules, tests, and
doctest (docstring rewraps and quoting, defvar declarations for the
reactive test variables, prefixed doctest counters, dead-binding
removal, one impossible eq -> equal in a face-merge assertion) with
behavior preserved. GitHub Actions workflow runs an Emacs 28.1/29.4/
30.1 matrix: compile-all with warnings-as-errors, the 443-test suite,
a genuinely shuffled-order rerun (tp-run-shuffled.el runs each test
individually; ERT's member selector cannot reorder), and the 63
README doctests. Makefile gains WERROR, compile-all, and
test-shuffled. Autoload cookies added for the four interactive
commands and the define-tp/define-tps macros. package-lint: 0
findings (main file tp.el); draft MELPA recipe in docs/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 23:46:52 +08:00
Kinneyzhang
ceb0dfb0bc Fix confirmed bugs in layer, stack, search, and reactive-render modules
35 fixes across tp-layer.el, tp-stack.el, tp-search.el, tp-reactive.el
and tp-render.el, each empirically reproduced before and after:
layer-definition resolution/cycles/copying/cleanup, clipped region-local
stack mutators, symmetric backward search matching, length-changing
replacements, and reactive re-render correctness (replace-not-accumulate,
buffer-local isolation, batching union, per-interval props).

Adds four per-module regression suites (100 new tests); combined suite
is 438/438 green. tp-test-backward updated to the now-symmetric backward
matching contract it previously codified inverted. The string-vs-buffer
shortfall divergence in tp-forward-do/tp-backward-do is documented in
CHANGELOG as a known divergence rather than changed. Adds CHANGELOG.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 20:01:20 +08:00
Kinneyzhang
5e5017a726 Split tp.el monolith into layered modules (behavior-preserving)
tp.el (4866 lines) is now an umbrella over nine modules with an
enforceable dependency order: tp-core -> tp-reactive -> tp-layer ->
tp-ops -> tp-search -> tp-render -> tp-stack -> tp-palette ->
tp-builtins.  Upward dependencies are inverted through four hook
variables installed by tp-render.el.

Also: require text-property-search (fixes tp-backward void-function),
clip tp-intervals to the requested range, add the shared clipping
interval walker tp--map-intervals and tp-face-properties, remove
synced-conflict junk files, byte-compilation now succeeds (define-tp
macroexpansion previously failed at compile time).

All 280 legacy tests pass plus 8 new tp-core tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 17:13:44 +08:00