Fix tp-text to replace string content instead of preserving original

When using tp-set on a string with tp-text, the returned string now
contains the tp-text value instead of the original string content.
For example, (tp-set "2" 'tp-text "6") now returns "6" with properties.

- Updated tp--handle-tp-text-property to return new string object
- Updated tp-set, tp-reset, tp-add to handle the new return format
- Added test for string object tp-text replacement

Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-28 09:49:52 +00:00
parent af5ba6b214
commit 5d514011d1
2 changed files with 41 additions and 15 deletions

View File

@ -2959,6 +2959,17 @@ preserving the native text property behavior."
;; face should still be bold ;; face should still be bold
(should (eq (tp-at 1 'face) 'bold)))) (should (eq (tp-at 1 'face) 'bold))))
(ert-deftest tp-test-tp-text-string-object-replaces-content ()
"Test that tp-text on string object replaces the string content."
;; When tp-text is set on a string, the returned string should have
;; the tp-text value as its content, not the original string
(let ((result (tp-set "2" 'face '(:background "green") 'tp-text "6")))
;; The returned string should be "6", not "2"
(should (equal result "6"))
;; Properties should be applied
(should (equal (get-text-property 0 'face result) '(:background "green")))
(should (equal (get-text-property 0 'tp-text result) "6"))))
(ert-deftest tp-test-tp-text-string-replaces-text () (ert-deftest tp-test-tp-text-string-replaces-text ()
"Test that tp-text with string value replaces the text in the region." "Test that tp-text with string value replaces the text in the region."
(tp-test-with-temp-buffer (tp-test-with-temp-buffer

45
tp.el
View File

@ -520,11 +520,12 @@ If tp-text is nil, initialize it to the current text in the region.
If tp-text is a string different from current text, replace the text. If tp-text is a string different from current text, replace the text.
When PRESERVE-PROPS is non-nil, existing text properties are preserved When PRESERVE-PROPS is non-nil, existing text properties are preserved
on the replaced text (used by tp-set and tp-add). on the replaced text (used by tp-set and tp-add).
Returns (PROPS NEW-END) where PROPS is the updated props and NEW-END is Returns (PROPS NEW-END NEW-OBJECT) where PROPS is the updated props,
the new end position after any text replacement." NEW-END is the new end position after any text replacement, and
NEW-OBJECT is the new string object (only different for strings with tp-text)."
(if (not (plist-member props 'tp-text)) (if (not (plist-member props 'tp-text))
;; tp-text not in props - return unchanged ;; tp-text not in props - return unchanged
(list props end) (list props end object)
(let ((tp-text-val (plist-get props 'tp-text))) (let ((tp-text-val (plist-get props 'tp-text)))
(cond (cond
;; tp-text is nil - initialize it to the current text ;; tp-text is nil - initialize it to the current text
@ -535,12 +536,14 @@ the new end position after any text replacement."
(with-current-buffer object (with-current-buffer object
(buffer-substring-no-properties start end)) (buffer-substring-no-properties start end))
(buffer-substring-no-properties start end))))) (buffer-substring-no-properties start end)))))
(list (plist-put props 'tp-text current-text) end))) (list (plist-put props 'tp-text current-text) end object)))
;; tp-text has a string value - replace the text in the region ;; tp-text has a string value - replace the text in the region
((stringp tp-text-val) ((stringp tp-text-val)
(if (stringp object) (if (stringp object)
;; For strings, we can't change length, so just return as-is ;; For strings: create a new string with tp-text content
(list props end) ;; The new string replaces the original, with props applied
(let ((new-string (copy-sequence tp-text-val)))
(list props (length new-string) new-string))
;; For buffers: replace text and adjust end position ;; For buffers: replace text and adjust end position
(let ((old-text (if object (let ((old-text (if object
(with-current-buffer object (with-current-buffer object
@ -548,7 +551,7 @@ the new end position after any text replacement."
(buffer-substring-no-properties start end)))) (buffer-substring-no-properties start end))))
(if (equal old-text tp-text-val) (if (equal old-text tp-text-val)
;; Same text, no replacement needed ;; Same text, no replacement needed
(list props end) (list props end object)
;; Need to replace text ;; Need to replace text
(let ((existing-props (when preserve-props (let ((existing-props (when preserve-props
(if object (if object
@ -571,9 +574,9 @@ the new end position after any text replacement."
(when existing-props (when existing-props
(cl-loop for (key val) on existing-props by #'cddr (cl-loop for (key val) on existing-props by #'cddr
do (put-text-property start new-end key val object))) do (put-text-property start new-end key val object)))
(list props new-end))))))) (list props new-end object)))))))
;; Other types - return unchanged ;; Other types - return unchanged
(t (list props end)))))) (t (list props end object))))))
;;; Core Property Functions ;;; Core Property Functions
@ -662,10 +665,14 @@ Return the modified object (string) or region (START . END) for buffer."
(pcase-let ((`(,object ,start ,finish ,props) (pcase-let ((`(,object ,start ,finish ,props)
(tp--parse-args start-or-string end-or-prop props-or-val rest))) (tp--parse-args start-or-string end-or-prop props-or-val rest)))
;; Handle tp-text property specially using helper function ;; Handle tp-text property specially using helper function
(pcase-let ((`(,new-props ,new-finish) (pcase-let ((`(,new-props ,new-finish ,new-object)
(tp--handle-tp-text-property start finish props object t))) (tp--handle-tp-text-property start finish props object t)))
(setq props new-props) (setq props new-props)
(setq finish new-finish)) (setq finish new-finish)
(setq object new-object)
;; For strings with tp-text, start is always 0
(when (and (stringp object) (plist-member props 'tp-text))
(setq start 0)))
;; Apply properties individually (preserves other properties) ;; Apply properties individually (preserves other properties)
(cl-loop for (key val) on props by #'cddr (cl-loop for (key val) on props by #'cddr
do (put-text-property start finish key val object)) do (put-text-property start finish key val object))
@ -709,10 +716,14 @@ Return the modified object (string) or region (START . END) for buffer."
(tp--parse-args start-or-string end-or-prop props-or-val rest))) (tp--parse-args start-or-string end-or-prop props-or-val rest)))
;; Handle tp-text property specially using helper function ;; Handle tp-text property specially using helper function
;; Pass nil for preserve-props since tp-reset replaces all properties ;; Pass nil for preserve-props since tp-reset replaces all properties
(pcase-let ((`(,new-props ,new-finish) (pcase-let ((`(,new-props ,new-finish ,new-object)
(tp--handle-tp-text-property start finish props object nil))) (tp--handle-tp-text-property start finish props object nil)))
(setq props new-props) (setq props new-props)
(setq finish new-finish)) (setq finish new-finish)
(setq object new-object)
;; For strings with tp-text, start is always 0
(when (and (stringp object) (plist-member props 'tp-text))
(setq start 0)))
;; Completely replace all properties ;; Completely replace all properties
(set-text-properties start finish props object) (set-text-properties start finish props object)
(if (stringp object) (if (stringp object)
@ -834,10 +845,14 @@ Return the modified object (string) or region (START . END) for buffer."
(tp--parse-args start-or-string end-or-prop props-or-val rest))) (tp--parse-args start-or-string end-or-prop props-or-val rest)))
;; Handle tp-text property specially using helper function ;; Handle tp-text property specially using helper function
;; Pass t for preserve-props since tp-add preserves existing properties ;; Pass t for preserve-props since tp-add preserves existing properties
(pcase-let ((`(,new-props ,new-finish) (pcase-let ((`(,new-props ,new-finish ,new-object)
(tp--handle-tp-text-property start finish props object t))) (tp--handle-tp-text-property start finish props object t)))
(setq props new-props) (setq props new-props)
(setq finish new-finish)) (setq finish new-finish)
(setq object new-object)
;; For strings with tp-text, start is always 0
(when (and (stringp object) (plist-member props 'tp-text))
(setq start 0)))
;; Process each property with deep merging ;; Process each property with deep merging
(let ((pos start)) (let ((pos start))
(while (< pos finish) (while (< pos finish)