Simplify reactive deps: remove tp-layer-templates, store only reactive props
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
parent
072b1b3d7d
commit
c22b596883
46
tp-tests.el
46
tp-tests.el
@ -1872,6 +1872,17 @@ Returns list of (START END VALUE) intervals."
|
||||
'($color $bg)))
|
||||
(should (null (tp--collect-reactive-symbols '(face bold)))))
|
||||
|
||||
(ert-deftest tp-test-extract-reactive-props ()
|
||||
"Test tp--extract-reactive-props extracts only properties using a reactive var."
|
||||
;; Single reactive property
|
||||
(should (equal (tp--extract-reactive-props '(help-echo "test" face (:foreground $color)) '$color)
|
||||
'(face (:foreground $color))))
|
||||
;; Multiple properties, only one uses the variable
|
||||
(should (equal (tp--extract-reactive-props '(help-echo "test" face (:foreground $color :background "green")) '$color)
|
||||
'(face (:foreground $color :background "green"))))
|
||||
;; No properties use the variable
|
||||
(should (null (tp--extract-reactive-props '(help-echo "test" face bold) '$color))))
|
||||
|
||||
(ert-deftest tp-test-resolve-reactive-symbols ()
|
||||
"Test tp--resolve-reactive-symbols replaces $foo with variable values."
|
||||
;; Use defvar to create dynamically-bound variables
|
||||
@ -1899,10 +1910,14 @@ Returns list of (START END VALUE) intervals."
|
||||
;; Check the layer is defined with resolved value
|
||||
(let ((props (cdr (assoc 'test-reactive-layer tp-layer-alist))))
|
||||
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
||||
;; Check the template is stored
|
||||
(should (assoc 'test-reactive-layer tp-layer-templates))
|
||||
;; Check the dependency is registered
|
||||
(should (assoc 'tp-test-var-color tp-reactive-deps)))
|
||||
;; Check the dependency is registered with only reactive props
|
||||
(should (assoc 'tp-test-var-color tp-reactive-deps))
|
||||
;; Check the stored reactive props only contain the face property
|
||||
(let* ((deps (cdr (assoc 'tp-test-var-color tp-reactive-deps)))
|
||||
(layer-dep (assoc 'test-reactive-layer deps)))
|
||||
(should layer-dep)
|
||||
;; The stored props should be just the reactive portion
|
||||
(should (plist-get (cdr layer-dep) 'face))))
|
||||
;; Cleanup
|
||||
(makunbound 'tp-test-var-color))))
|
||||
|
||||
@ -1957,10 +1972,8 @@ Returns list of (START END VALUE) intervals."
|
||||
(tp-define-layer test-reactive-reset
|
||||
(face (:foreground $tp-test-reset-color)))
|
||||
(should tp-reactive-deps)
|
||||
(should tp-layer-templates)
|
||||
(tp-reactive-reset)
|
||||
(should-not tp-reactive-deps)
|
||||
(should-not tp-layer-templates))
|
||||
(should-not tp-reactive-deps))
|
||||
;; Cleanup
|
||||
(makunbound 'tp-test-reset-color))))
|
||||
|
||||
@ -1975,8 +1988,7 @@ Returns list of (START END VALUE) intervals."
|
||||
(face (:foreground $tp-test-reset2-color)))
|
||||
(should tp-reactive-deps)
|
||||
(tp-layer-reset)
|
||||
(should-not tp-reactive-deps)
|
||||
(should-not tp-layer-templates))
|
||||
(should-not tp-reactive-deps))
|
||||
;; Cleanup
|
||||
(makunbound 'tp-test-reset2-color))))
|
||||
|
||||
@ -1996,10 +2008,12 @@ Returns list of (START END VALUE) intervals."
|
||||
;; Check the non-reactive layer is defined
|
||||
(let ((props (cdr (assoc 'test-reactive-group-second tp-layer-alist))))
|
||||
(should (equal (plist-get (plist-get props 'face) :foreground) "blue")))
|
||||
;; Check the template is stored for reactive layer
|
||||
(should (assoc 'test-reactive-group-first tp-layer-templates))
|
||||
;; Non-reactive layer should not have template
|
||||
(should-not (assoc 'test-reactive-group-second tp-layer-templates)))
|
||||
;; Check the reactive layer is registered in tp-reactive-deps
|
||||
(should (assoc 'tp-test-group-color tp-reactive-deps))
|
||||
;; The reactive layer should be in the dependencies
|
||||
(let* ((deps (cdr (assoc 'tp-test-group-color tp-reactive-deps)))
|
||||
(layer-dep (assoc 'test-reactive-group-first deps)))
|
||||
(should layer-dep)))
|
||||
;; Cleanup
|
||||
(makunbound 'tp-test-group-color))))
|
||||
|
||||
@ -2012,10 +2026,12 @@ Returns list of (START END VALUE) intervals."
|
||||
(progn
|
||||
(tp-define-layer test-undef-reactive
|
||||
(face (:foreground $tp-test-undef-color)))
|
||||
(should (assoc 'test-undef-reactive tp-layer-templates))
|
||||
;; Check the dependency is registered
|
||||
(should (assoc 'tp-test-undef-color tp-reactive-deps))
|
||||
(let* ((deps (cdr (assoc 'tp-test-undef-color tp-reactive-deps)))
|
||||
(layer-dep (assoc 'test-undef-reactive deps)))
|
||||
(should layer-dep))
|
||||
(tp-undefine-layer 'test-undef-reactive)
|
||||
(should-not (assoc 'test-undef-reactive tp-layer-templates))
|
||||
;; Dependency should be cleaned up if no other layers use it
|
||||
(should-not (cdr (assoc 'tp-test-undef-color tp-reactive-deps))))
|
||||
;; Cleanup
|
||||
|
||||
63
tp.el
63
tp.el
@ -53,13 +53,10 @@ Stores layer group definitions, where each group contains multiple layer names."
|
||||
|
||||
(defvar tp-reactive-deps nil
|
||||
"Alist mapping reactive variables to their dependent layers.
|
||||
Each element is (VARIABLE-SYMBOL . ((LAYER-NAME . PROPERTY-SPEC) ...)).
|
||||
PROPERTY-SPEC is the original property specification containing the variable.")
|
||||
|
||||
(defvar tp-layer-templates nil
|
||||
"Alist mapping layer names to their template property specifications.
|
||||
Each element is (LAYER-NAME . TEMPLATE-PLIST).
|
||||
TEMPLATE-PLIST contains symbols starting with $ that need to be resolved.")
|
||||
Each element is (VARIABLE-SYMBOL . ((LAYER-NAME . REACTIVE-PROPS) ...)).
|
||||
REACTIVE-PROPS contains only the property key-value pairs that use this variable.
|
||||
For example, for (define-tp my-layer (help-echo \"test\" face (:foreground $color))),
|
||||
only (face (:foreground $color)) is stored, not the help-echo.")
|
||||
|
||||
(defvar tp-reactive-enabled t
|
||||
"Non-nil means reactive text property updates are enabled.")
|
||||
@ -89,6 +86,16 @@ Returns a list of reactive symbols found."
|
||||
(tp--collect-reactive-symbols (cdr form))))
|
||||
(t nil)))
|
||||
|
||||
(defun tp--extract-reactive-props (plist reactive-var)
|
||||
"Extract only the properties from PLIST that use REACTIVE-VAR.
|
||||
Returns a plist containing only the key-value pairs that reference REACTIVE-VAR.
|
||||
REACTIVE-VAR should be the $-prefixed symbol (e.g., $my-color)."
|
||||
(let ((result nil))
|
||||
(cl-loop for (key val) on plist by #'cddr
|
||||
when (member reactive-var (tp--collect-reactive-symbols val))
|
||||
do (setq result (plist-put result key val)))
|
||||
result))
|
||||
|
||||
(defun tp--resolve-reactive-symbols (form &optional override-alist)
|
||||
"Recursively resolve all reactive symbols in FORM to their values.
|
||||
Reactive symbols ($foo) are replaced with the value of the variable foo.
|
||||
@ -110,32 +117,29 @@ override the current variable values (used during watcher callbacks)."
|
||||
|
||||
(defun tp--register-reactive-deps (layer-name reactive-symbols template-props)
|
||||
"Register REACTIVE-SYMBOLS as dependencies for LAYER-NAME.
|
||||
TEMPLATE-PROPS is the original property specification with reactive symbols."
|
||||
;; Store the template for this layer
|
||||
(if (assoc layer-name tp-layer-templates)
|
||||
(setf (cdr (assoc layer-name tp-layer-templates)) template-props)
|
||||
(push (cons layer-name template-props) tp-layer-templates))
|
||||
;; Register each reactive symbol's dependency
|
||||
TEMPLATE-PROPS is the original property specification with reactive symbols.
|
||||
Only the reactive portions of the properties are stored for each variable."
|
||||
;; Register each reactive symbol's dependency with only its relevant properties
|
||||
(dolist (rsym reactive-symbols)
|
||||
(let* ((var-sym (tp--reactive-var-symbol rsym))
|
||||
;; Extract only the properties that use this specific reactive variable
|
||||
(reactive-props (tp--extract-reactive-props template-props rsym))
|
||||
(existing (assoc var-sym tp-reactive-deps)))
|
||||
(if existing
|
||||
;; Update or add this layer to existing dependencies
|
||||
(let ((layer-entry (assoc layer-name (cdr existing))))
|
||||
(if layer-entry
|
||||
;; Update existing entry with new template-props
|
||||
(setf (cdr layer-entry) template-props)
|
||||
;; Update existing entry with new reactive-props
|
||||
(setf (cdr layer-entry) reactive-props)
|
||||
;; Add new layer entry
|
||||
(push (cons layer-name template-props) (cdr existing))))
|
||||
(push (cons layer-name reactive-props) (cdr existing))))
|
||||
;; Create new dependency entry and add watcher
|
||||
(push (cons var-sym (list (cons layer-name template-props))) tp-reactive-deps)
|
||||
(push (cons var-sym (list (cons layer-name reactive-props))) tp-reactive-deps)
|
||||
;; Add variable watcher for this variable
|
||||
(add-variable-watcher var-sym #'tp--reactive-variable-watcher)))))
|
||||
|
||||
(defun tp--unregister-reactive-deps (layer-name)
|
||||
"Unregister all reactive dependencies for LAYER-NAME."
|
||||
;; Remove from templates
|
||||
(setq tp-layer-templates (assq-delete-all layer-name tp-layer-templates))
|
||||
;; Collect variables that need watcher removal
|
||||
(let ((vars-to-clean nil))
|
||||
;; First pass: remove layer from dependencies and collect empty vars
|
||||
@ -170,12 +174,18 @@ Only 'set' operations trigger updates because:
|
||||
(override-alist (list (cons symbol newval))))
|
||||
(dolist (dep deps)
|
||||
(let* ((layer-name (car dep))
|
||||
(template (cdr (assoc layer-name tp-layer-templates))))
|
||||
(when template
|
||||
;; Resolve the template with the new value override
|
||||
(let ((resolved-props (tp--resolve-reactive-symbols template override-alist)))
|
||||
;; Update the layer definition using the helper function
|
||||
(tp--set-layer-props layer-name resolved-props)
|
||||
;; Get the reactive props stored directly in the dependency
|
||||
(reactive-props (cdr dep)))
|
||||
(when reactive-props
|
||||
;; Resolve the reactive props with the new value override
|
||||
(let ((resolved-props (tp--resolve-reactive-symbols reactive-props override-alist)))
|
||||
;; Update only the reactive properties in the layer definition
|
||||
(let ((current-props (cdr (assoc layer-name tp-layer-alist))))
|
||||
(when current-props
|
||||
;; Merge the resolved reactive props into the current layer props
|
||||
(cl-loop for (key val) on resolved-props by #'cddr
|
||||
do (setq current-props (plist-put current-props key val)))
|
||||
(tp--set-layer-props layer-name current-props)))
|
||||
;; Update all text regions with this layer
|
||||
(tp--update-layer-regions layer-name))))))))
|
||||
|
||||
@ -206,8 +216,7 @@ Re-applies the layer properties using tp-search-map and tp-add."
|
||||
(let ((var-sym (car dep)))
|
||||
(remove-variable-watcher var-sym #'tp--reactive-variable-watcher)))
|
||||
;; Clear registries
|
||||
(setq tp-reactive-deps nil)
|
||||
(setq tp-layer-templates nil))
|
||||
(setq tp-reactive-deps nil))
|
||||
|
||||
|
||||
;;; Core Property Functions
|
||||
|
||||
Loading…
Reference in New Issue
Block a user