Refactor tp-text handling to improve code reuse and clarity

- Updated tp--handle-tp-text-property to accept preserve-props parameter
- Replaced inefficient nth-based loop with cl-loop in tp-set
- Fixed loop structure in tp--replace-reactive-text-in-buffer
- Made tp-reset use the helper function instead of duplicated code

Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-28 09:15:45 +00:00
parent d75070824a
commit af5ba6b214

83
tp.el
View File

@ -497,10 +497,8 @@ WHERE specifies which buffers to update:
NEW-TEXT is the new text to replace with. NEW-TEXT is the new text to replace with.
PROPS are the properties to apply to the new text." PROPS are the properties to apply to the new text."
(goto-char (point-min)) (goto-char (point-min))
(let ((match t)) (let ((match (text-property-search-forward 'tp-name layer-name t)))
(while match (while match
(setq match (text-property-search-forward 'tp-name layer-name t))
(when match
(let* ((m-start (prop-match-beginning match)) (let* ((m-start (prop-match-beginning match))
(m-end (prop-match-end match)) (m-end (prop-match-end match))
(old-text (buffer-substring-no-properties m-start m-end))) (old-text (buffer-substring-no-properties m-start m-end)))
@ -512,12 +510,16 @@ PROPS are the properties to apply to the new text."
(insert new-text) (insert new-text)
;; Apply the layer properties (including tp-text and tp-name) to new text ;; Apply the layer properties (including tp-text and tp-name) to new text
(let ((new-end (+ m-start (length new-text)))) (let ((new-end (+ m-start (length new-text))))
(set-text-properties m-start new-end props)))))))) (set-text-properties m-start new-end props))))
;; Search for next match
(setq match (text-property-search-forward 'tp-name layer-name t)))))
(defun tp--handle-tp-text-property (start end props object) (defun tp--handle-tp-text-property (start end props object &optional preserve-props)
"Handle tp-text property in PROPS for region from START to END in OBJECT. "Handle tp-text property in PROPS for region from START to END in OBJECT.
If tp-text is nil, initialize it to the current text in the region. 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
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) where PROPS is the updated props and NEW-END is
the new end position after any text replacement." the new end position after any text replacement."
(if (not (plist-member props 'tp-text)) (if (not (plist-member props 'tp-text))
@ -548,10 +550,11 @@ the new end position after any text replacement."
;; Same text, no replacement needed ;; Same text, no replacement needed
(list props end) (list props end)
;; Need to replace text ;; Need to replace text
(let ((existing-props (if object (let ((existing-props (when preserve-props
(if object
(with-current-buffer object (with-current-buffer object
(text-properties-at start)) (text-properties-at start))
(text-properties-at start)))) (text-properties-at start)))))
(save-excursion (save-excursion
(if object (if object
(with-current-buffer object (with-current-buffer object
@ -564,16 +567,10 @@ the new end position after any text replacement."
(goto-char start) (goto-char start)
(insert tp-text-val)))) (insert tp-text-val))))
(let ((new-end (+ start (length tp-text-val)))) (let ((new-end (+ start (length tp-text-val))))
;; Re-apply existing properties to new text region ;; Re-apply existing properties to new text region if preserving
(when existing-props (when existing-props
(let ((i 0) (cl-loop for (key val) on existing-props by #'cddr
(len (length existing-props))) do (put-text-property start new-end key val object)))
(while (< i len)
(put-text-property start new-end
(nth i existing-props)
(nth (1+ i) existing-props)
object)
(setq i (+ i 2)))))
(list props new-end))))))) (list props new-end)))))))
;; Other types - return unchanged ;; Other types - return unchanged
(t (list props end)))))) (t (list props end))))))
@ -666,18 +663,12 @@ 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
(pcase-let ((`(,new-props ,new-finish) (pcase-let ((`(,new-props ,new-finish)
(tp--handle-tp-text-property start finish props object))) (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))
;; Apply properties individually (preserves other properties) ;; Apply properties individually (preserves other properties)
(let ((len (length props)) (cl-loop for (key val) on props by #'cddr
(i 0)) do (put-text-property start finish key val object))
(while (< i len)
(put-text-property start finish
(nth i props)
(nth (1+ i) props)
object)
(setq i (+ i 2))))
(if (stringp object) (if (stringp object)
object object
(cons start finish)))) (cons start finish))))
@ -717,40 +708,11 @@ 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
;; Note: for tp-reset we don't preserve existing props on text replacement ;; Pass nil for preserve-props since tp-reset replaces all properties
;; since tp-reset is meant to completely replace all properties (pcase-let ((`(,new-props ,new-finish)
(when (plist-member props 'tp-text) (tp--handle-tp-text-property start finish props object nil)))
(let ((tp-text-val (plist-get props 'tp-text))) (setq props new-props)
(cond (setq finish new-finish))
;; tp-text is nil - initialize it to the current text
((null tp-text-val)
(let ((current-text (if (stringp object)
(substring object start finish)
(if object
(with-current-buffer object
(buffer-substring-no-properties start finish))
(buffer-substring-no-properties start finish)))))
(setq props (plist-put props 'tp-text current-text))))
;; tp-text has a string value - replace the text in the region
((stringp tp-text-val)
(unless (stringp object)
(let ((old-text (if object
(with-current-buffer object
(buffer-substring-no-properties start finish))
(buffer-substring-no-properties start finish))))
(unless (equal old-text tp-text-val)
(save-excursion
(if object
(with-current-buffer object
(let ((inhibit-read-only t))
(delete-region start finish)
(goto-char start)
(insert tp-text-val)))
(let ((inhibit-read-only t))
(delete-region start finish)
(goto-char start)
(insert tp-text-val))))
(setq finish (+ start (length tp-text-val))))))))))
;; 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)
@ -871,8 +833,9 @@ 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
;; Pass t for preserve-props since tp-add preserves existing properties
(pcase-let ((`(,new-props ,new-finish) (pcase-let ((`(,new-props ,new-finish)
(tp--handle-tp-text-property start finish props object))) (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))
;; Process each property with deep merging ;; Process each property with deep merging