Fix tp-text to update when text properties differ even if text is same

- Added `tp--equal-including-string-properties` helper function that uses
  `equal-including-properties` for strings to properly detect changes in
  text properties when the text content is the same
- Updated `tp--reactive-variable-watcher` to use this new comparison function
- Updated `tp--replace-reactive-text-in-buffer` to use `tp-add` when text
  content is the same but properties may differ
- Added test `tp-test-tp-text-same-text-different-properties` to verify
  the fix

Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-01-05 19:14:59 +00:00
parent cdc14f3759
commit 467a4c16f4
2 changed files with 47 additions and 5 deletions

View File

@ -3038,6 +3038,34 @@ the inserted text should be that string, not the source text."
(ignore-errors (makunbound 'tp-test-name-part2))
(ignore-errors (makunbound 'tp-test-full-text)))))
(ert-deftest tp-test-tp-text-same-text-different-properties ()
"Test tp-text updates when text is same but properties differ.
When the reactive variable changes to a propertized string with the same
text content but different properties, the properties should be updated."
(tp-test-with-temp-buffer
(defvar tp-test-same-text nil "Test variable for same text different props.")
(setq tp-test-same-text "emacs")
(unwind-protect
(progn
(define-tp test-same-text-layer ()
:props '(face (:foreground "green") tp-text $tp-test-same-text))
;; Apply layer to text
(insert "placeholder text here")
(tp-set 1 17 'test-same-text-layer)
;; Initial text should be "emacs" with foreground green
(should (equal (buffer-substring-no-properties 1 6) "emacs"))
(should (equal (plist-get (tp-at 1 'face) :foreground) "green"))
;; Change the reactive variable to same text but different properties
(setq tp-test-same-text (propertize "emacs" 'face 'bold))
;; Text should still be "emacs"
(should (equal (buffer-substring-no-properties 1 6) "emacs"))
;; Face should now include bold from the propertized string
(let ((face-val (tp-at 1 'face)))
(should (or (eq face-val 'bold)
(and (listp face-val) (memq 'bold face-val))))))
;; Cleanup
(makunbound 'tp-test-same-text))))
;;; ============================================================
;;; tp-text with Embedded Text Properties Tests
;;; ============================================================

24
tp.el
View File

@ -258,6 +258,15 @@ Scans the entire string, not just position 0."
(and (stringp str)
(not (null (object-intervals str)))))
(defun tp--equal-including-string-properties (a b)
"Compare A and B for equality, considering string text properties.
If either A or B is a string, uses `equal-including-properties' to ensure
text properties are considered in the comparison.
Otherwise, uses standard `equal'."
(if (or (stringp a) (stringp b))
(equal-including-properties a b)
(equal a b)))
(defun tp--parse-face-list (face-list)
"Parse a mixed face list into symbols and a plist.
FACE-LIST can be a mix of:
@ -621,8 +630,11 @@ Only 'set' operations trigger updates because:
- 'defvaralias': Aliasing, the actual value change will trigger a separate 'set'
When `tp--batch-update-active' is non-nil, buffer updates are deferred until
the batch completes. Layer definitions are still updated immediately."
(when (and (not (equal (symbol-value symbol) newval))
the batch completes. Layer definitions are still updated immediately.
Uses `tp--equal-including-string-properties' for comparison to properly detect
changes in text properties when the text content is the same."
(when (and (not (tp--equal-including-string-properties (symbol-value symbol) newval))
(eq operation 'set))
(tp-debug-log "Variable %s changed: %S -> %S (where: %s)"
symbol (symbol-value symbol) newval
@ -998,9 +1010,11 @@ Text properties embedded in NEW-TEXT are merged with PROPS."
(let* ((m-start (prop-match-beginning match))
(m-end (prop-match-end match))
(old-text (buffer-substring-no-properties m-start m-end)))
;; Only replace if text content is different
(unless (equal old-text (substring-no-properties new-text))
;; Delete old text and insert new (without properties)
(if (equal old-text (substring-no-properties new-text))
;; Text content is the same, but properties may differ
;; Use tp-add to update properties (merges embedded props from new-text)
(tp-add m-start m-end merged-props)
;; Text content is different - delete old text and insert new
(delete-region m-start m-end)
(goto-char m-start)
(insert (substring-no-properties new-text))