From c6fbccf659ed6ef6344736e985794549d909895d Mon Sep 17 00:00:00 2001 From: Kinneyzhang Date: Mon, 27 Jul 2026 01:36:31 +0800 Subject: [PATCH] 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 --- tp-layer.el | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tp-stack.el | 54 ---------------------------------------------- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/tp-layer.el b/tp-layer.el index 69efa07..45f39f3 100644 --- a/tp-layer.el +++ b/tp-layer.el @@ -1429,6 +1429,68 @@ First element is top layer, rest are in tp-layers." (cons top belows) belows)) +;;; Layer stack storage codec +;; +;; The encoding/decoding of a layer stack into raw text properties +;; lives here, beside `tp--build-layer-props' / `tp--layer-stack-to-list', +;; so both the stack operations (tp-stack.el) and the reactive +;; re-render engine (tp-render.el) can read and write stack storage +;; without duplicating format knowledge or requiring each other. + +(defun tp--stack-hidden-p (layer) + "Return non-nil when the layer plist LAYER is flagged hidden. +A layer is hidden when its plist carries a non-nil `tp-hidden' entry; +see `tp-hide-layer'." + (and (plist-get layer 'tp-hidden) t)) + +(defun tp--stack-props-to-list (props) + "Return the ordered layer stack stored in raw text properties PROPS. +The result is a list of layer plists, top layer first, including +hidden layers (flagged with a non-nil `tp-hidden' entry) at their +stack position. Returns nil for bare text. + +This is the inverse of `tp--stack-build-props': when any entry of the +`tp-layers' bookkeeping property is hidden, that property holds the +whole ordered stack and the direct properties are only a render cache +of the topmost non-hidden layer; otherwise the direct properties are +the top layer and `tp-layers' holds the layers below it. Direct +property edits made outside the stack API (for example `tp-set') are +therefore discarded by the next stack operation while any layer is +hidden." + (let* ((idx (-elem-index 'tp-layers props)) + (top (if idx + (-remove-at-indices (list idx (1+ idx)) props) + props)) + (belows (plist-get props 'tp-layers))) + (if (seq-some #'tp--stack-hidden-p belows) + belows + (tp--layer-stack-to-list top belows)))) + +(defun tp--stack-build-props (layer-list) + "Build text properties from LAYER-LIST (top layer first). +Like `tp--build-layer-props', but the `tp-layers' entry is only added +when there are below-layers, so single-layer stacks do not carry a +garbage (tp-layers nil) property. Consumers must therefore tolerate +an absent `tp-layers' property (both `plist-get' and +`tp--stack-map-region' do). + +When any layer in LAYER-LIST is hidden (non-nil `tp-hidden' entry, +see `tp-hide-layer'), the storage switches to full-stack mode: the +direct properties are those of the topmost non-hidden layer (or no +layer properties at all when every layer is hidden) and the +`tp-layers' property holds the complete ordered LAYER-LIST. +`tp--stack-props-to-list' reverses either representation." + (cond + ((null layer-list) nil) + ((seq-some #'tp--stack-hidden-p layer-list) + (append (seq-find (lambda (layer) + (not (tp--stack-hidden-p layer))) + layer-list) + (list 'tp-layers layer-list))) + ((null (cdr layer-list)) (copy-sequence (car layer-list))) + (t (append (car layer-list) + (list 'tp-layers (cdr layer-list)))))) + (defun tp--describe-layer-data (name) "Collect description data for layer NAME as a plist. Returns nil when NAME is not registered in `tp-layer-alist'. diff --git a/tp-stack.el b/tp-stack.el index d5e8984..70a7014 100644 --- a/tp-stack.el +++ b/tp-stack.el @@ -51,41 +51,12 @@ buffers)." (seq-take (cdr rest) n))) (t (error "Invalid layer arguments: %S" (cons start-or-string rest))))) -(defun tp--stack-hidden-p (layer) - "Return non-nil when the layer plist LAYER is flagged hidden. -A layer is hidden when its plist carries a non-nil `tp-hidden' entry; -see `tp-hide-layer'." - (and (plist-get layer 'tp-hidden) t)) - (defun tp--plist-remove (plist key) "Return a copy of PLIST without KEY and its value. Comparison uses `eq'. PLIST itself is not modified." (cl-loop for (k v) on plist by #'cddr unless (eq k key) append (list k v))) -(defun tp--stack-props-to-list (props) - "Return the ordered layer stack stored in raw text properties PROPS. -The result is a list of layer plists, top layer first, including -hidden layers (flagged with a non-nil `tp-hidden' entry) at their -stack position. Returns nil for bare text. - -This is the inverse of `tp--stack-build-props': when any entry of the -`tp-layers' bookkeeping property is hidden, that property holds the -whole ordered stack and the direct properties are only a render cache -of the topmost non-hidden layer; otherwise the direct properties are -the top layer and `tp-layers' holds the layers below it. Direct -property edits made outside the stack API (for example `tp-set') are -therefore discarded by the next stack operation while any layer is -hidden." - (let* ((idx (-elem-index 'tp-layers props)) - (top (if idx - (-remove-at-indices (list idx (1+ idx)) props) - props)) - (belows (plist-get props 'tp-layers))) - (if (seq-some #'tp--stack-hidden-p belows) - belows - (tp--layer-stack-to-list top belows)))) - (defun tp--stack-map-region (start end object function) "Call FUNCTION over each property run of [START, END) in OBJECT. @@ -109,31 +80,6 @@ previously property-less text." (funcall function i-start i-end (tp--stack-props-to-list props)))))) -(defun tp--stack-build-props (layer-list) - "Build text properties from LAYER-LIST (top layer first). -Like `tp--build-layer-props', but the `tp-layers' entry is only added -when there are below-layers, so single-layer stacks do not carry a -garbage (tp-layers nil) property. Consumers must therefore tolerate -an absent `tp-layers' property (both `plist-get' and -`tp--stack-map-region' do). - -When any layer in LAYER-LIST is hidden (non-nil `tp-hidden' entry, -see `tp-hide-layer'), the storage switches to full-stack mode: the -direct properties are those of the topmost non-hidden layer (or no -layer properties at all when every layer is hidden) and the -`tp-layers' property holds the complete ordered LAYER-LIST. -`tp--stack-props-to-list' reverses either representation." - (cond - ((null layer-list) nil) - ((seq-some #'tp--stack-hidden-p layer-list) - (append (seq-find (lambda (layer) - (not (tp--stack-hidden-p layer))) - layer-list) - (list 'tp-layers layer-list))) - ((null (cdr layer-list)) (copy-sequence (car layer-list))) - (t (append (car layer-list) - (list 'tp-layers (cdr layer-list)))))) - (defun tp--stack-register-layers (stack object) "Register OBJECT in the reactive buffer registry for every layer in STACK. STACK is a list of layer plists as stored by the stack operations.