From 094f8f0f880bf6303105ffb9ef107f3096200314 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 10:29:03 +0000 Subject: [PATCH 2/4] Fix tp-text reactive variable synchronization when initial value is nil Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com> --- .gitignore | 1 + tp-tests.el | 43 +++++++++++++++++++++++++++++++++++++++++++ tp.el | 31 +++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/.gitignore b/.gitignore index ebf6bf9..5d830e3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ dash.el # Backup files *~ \#*\# +dash.el diff --git a/tp-tests.el b/tp-tests.el index 3448995..11008fe 100644 --- a/tp-tests.el +++ b/tp-tests.el @@ -3044,6 +3044,49 @@ preserving the native text property behavior." ;; Cleanup (makunbound 'tp-test-reactive-text)))) +(ert-deftest tp-test-tp-text-reactive-nil-initializes-variable () + "Test tp-text with nil reactive variable initializes the variable to source text. +When tp-text is bound to a reactive variable and that variable is nil, +the source text should be used and the reactive variable should be updated." + (tp-test-with-temp-buffer + (defvar tp-test-text-var nil "Test variable for tp-text initialization.") + (setq tp-test-text-var nil) + (unwind-protect + (progn + ;; Define layer with tp-text bound to a reactive variable + (tp-define-layer 'test-init-text-layer + :props '(face bold tp-text $tp-test-text-var)) + ;; Apply layer to string - variable is nil, so source text should be used + (let ((result (tp-set "2" 'test-init-text-layer))) + ;; Result should be the source text "2" + (should (equal result "2")) + ;; tp-test-text-var should now be "2" + (should (equal tp-test-text-var "2")) + ;; tp-text property should be "2" + (should (equal (tp-at 0 'tp-text result) "2"))) + ;; Now set the variable to a different value and test again + (setq tp-test-text-var "18") + ;; Redefine layer to reset resolved props + (tp-define-layer 'test-init-text-layer + :props '(face bold tp-text $tp-test-text-var)) + (let ((result (tp-set "2" 'test-init-text-layer))) + ;; Result should be the variable value "18", not source "2" + (should (equal result "18")) + ;; Variable should remain "18" + (should (equal tp-test-text-var "18")))) + ;; Cleanup + (makunbound 'tp-test-text-var)))) + +(ert-deftest tp-test-tp-text-direct-string-uses-specified-text () + "Test tp-text with direct string value uses that string, not source text. +When tp-text is set directly to a string (not a reactive variable), +the inserted text should be that string, not the source text." + (let ((result (tp-set "2" 'tp-text "23"))) + ;; Result should be "23", not "2" + (should (equal result "23")) + ;; tp-text property should be "23" + (should (equal (tp-at 0 'tp-text result) "23")))) + (ert-deftest tp-test-tp-text-reactive-computed () "Test tp-text with computed reactive variable." (tp-test-with-temp-buffer diff --git a/tp.el b/tp.el index 6e74eba..114b2b9 100644 --- a/tp.el +++ b/tp.el @@ -576,6 +576,26 @@ WHERE specifies which buffers to update: ;;; Layer 4: Reactive Text (tp-text property) ;;;============================================================================ +(defun tp--find-tp-text-reactive-var (layer-name) + "Find the reactive variable symbol used for tp-text in LAYER-NAME. +Returns the variable symbol (e.g., tp-test-counter) if tp-text uses a +reactive variable (e.g., $tp-test-counter), or nil if not found. +Searches through `tp-reactive-deps' to find the original reactive props." + (catch 'found + (dolist (dep tp-reactive-deps) + (let* ((var-sym (car dep)) + (layer-entry (assoc layer-name (cdr dep)))) + (when layer-entry + (let ((reactive-props (cdr layer-entry))) + ;; Check if tp-text in reactive-props uses this variable + (when (plist-member reactive-props 'tp-text) + (let ((tp-text-val (plist-get reactive-props 'tp-text))) + ;; Check if tp-text-val is a reactive symbol for this variable + (when (and (tp--reactive-symbol-p tp-text-val) + (eq (tp--reactive-var-symbol tp-text-val) var-sym)) + (throw 'found var-sym)))))))) + nil)) + (defun tp--update-reactive-text (layer-name &optional where) "Update text regions that have tp-text property with LAYER-NAME applied. This is called when a reactive variable bound to tp-text changes. @@ -644,6 +664,17 @@ NEW-OBJECT is the new string object (only different for strings with tp-text)." (with-current-buffer object (buffer-substring-no-properties start end)) (buffer-substring-no-properties start end))))) + ;; If tp-text uses a reactive variable, update that variable to match + ;; This ensures the reactive variable and buffer text stay in sync + (when-let ((layer-name (plist-get props 'tp-name))) + (when-let ((reactive-var (tp--find-tp-text-reactive-var layer-name))) + ;; Update the reactive variable with the current text (buffer-local) + (set reactive-var current-text) + ;; Also update the layer definition so future accesses see the new value + (let ((layer-props (cdr (assoc layer-name tp-layer-alist)))) + (when layer-props + (setf (cdr (assoc layer-name tp-layer-alist)) + (plist-put layer-props 'tp-text current-text)))))) (list (plist-put props 'tp-text current-text) end object))) ;; tp-text has a string value - replace the text in the region ((stringp tp-text-val) From fefe5873ed113c88874a487b0b8978cf915e4ddc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 10:31:31 +0000 Subject: [PATCH 3/4] Address code review feedback: use helper function for layer props update Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com> --- tp-tests.el | 5 ++++- tp.el | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tp-tests.el b/tp-tests.el index 11008fe..26cd768 100644 --- a/tp-tests.el +++ b/tp-tests.el @@ -3066,7 +3066,10 @@ the source text should be used and the reactive variable should be updated." (should (equal (tp-at 0 'tp-text result) "2"))) ;; Now set the variable to a different value and test again (setq tp-test-text-var "18") - ;; Redefine layer to reset resolved props + ;; Redefine layer to reset resolved props to the new variable value. + ;; This is necessary because the layer definition caches the resolved + ;; tp-text value, and we want to test the behavior when the variable + ;; already has a non-nil value at layer application time. (tp-define-layer 'test-init-text-layer :props '(face bold tp-text $tp-test-text-var)) (let ((result (tp-set "2" 'test-init-text-layer))) diff --git a/tp.el b/tp.el index 114b2b9..5eebd3e 100644 --- a/tp.el +++ b/tp.el @@ -668,13 +668,16 @@ NEW-OBJECT is the new string object (only different for strings with tp-text)." ;; This ensures the reactive variable and buffer text stay in sync (when-let ((layer-name (plist-get props 'tp-name))) (when-let ((reactive-var (tp--find-tp-text-reactive-var layer-name))) - ;; Update the reactive variable with the current text (buffer-local) + ;; Update the reactive variable with the current text + ;; Note: Using global `set` here because the layer definition is global. + ;; When the variable is changed, the reactive watcher will update all + ;; buffers that have this layer applied. (set reactive-var current-text) ;; Also update the layer definition so future accesses see the new value (let ((layer-props (cdr (assoc layer-name tp-layer-alist)))) (when layer-props - (setf (cdr (assoc layer-name tp-layer-alist)) - (plist-put layer-props 'tp-text current-text)))))) + (tp--set-layer-props layer-name + (plist-put layer-props 'tp-text current-text)))))) (list (plist-put props 'tp-text current-text) end object))) ;; tp-text has a string value - replace the text in the region ((stringp tp-text-val) From 09a22946299f51b06c58d548556ef36f0e7ac6b9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 10:32:18 +0000 Subject: [PATCH 4/4] Clean up duplicate entry in .gitignore Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com> --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5d830e3..ebf6bf9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ dash.el # Backup files *~ \#*\# -dash.el