From 347abb601eefaf203b14730e5366d76dc19db1c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 7 Jan 2026 03:26:47 +0000 Subject: [PATCH] Improve tp--apply-props-to-string to handle partial range correctly Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com> --- tp-tests.el | 7 ++++++- tp.el | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tp-tests.el b/tp-tests.el index 46c2de1..33b44db 100644 --- a/tp-tests.el +++ b/tp-tests.el @@ -4060,7 +4060,12 @@ Regression test for: (tp-set \"emacs\" 'face nil) erroring with (ert-deftest tp-test-set-preserves-text-property-intervals () "Test that tp-set preserves text property intervals when adding new properties. When a string has different properties at different positions, adding a new -property should preserve the original interval structure." +property should preserve the original interval structure. + +Test string: \" button \" (8 characters, positions 0-7) + - Position 0-1: display property (first space character) + - Position 1-7: no display property (text \"button \") + - Position 7-8: display property (last space character)" (let ((original #(" button " 0 1 (display (space :width (4))) 7 8 (display (space :width (4)))))) (let ((result (tp-set original 'face '(:foreground "red")))) diff --git a/tp.el b/tp.el index 36c5149..e696a97 100644 --- a/tp.el +++ b/tp.el @@ -1316,7 +1316,7 @@ Supports multiple calling conventions: (defun tp--apply-props-to-string (str start end props &optional merge-mode) "Apply PROPS to string STR from START to END, returning a NEW string. This function does not modify the original string. -Preserves the original text property intervals by using `propertize'. +Preserves the original text property intervals. MERGE-MODE controls how properties are applied: nil or :set - Set properties, preserving existing unspecified ones @@ -1352,9 +1352,18 @@ Returns a new propertized string." (put-text-property pos next-change key new-val result) (setq pos next-change))))) result)) - ;; nil/:set - use propertize which creates a new copy and preserves existing properties + ;; nil/:set - set properties while preserving existing ones + ;; If applying to the entire string, use propertize for efficiency + ;; Otherwise, use copy-sequence + put-text-property to apply to specific range (t - (apply #'propertize str props))))) + (if (and (= start 0) (= end len)) + ;; Entire string: use propertize which creates a new copy and preserves existing properties + (apply #'propertize str props) + ;; Partial range: copy string and apply properties to the range + (let ((result (copy-sequence str))) + (cl-loop for (key val) on props by #'cddr + do (put-text-property start end key val result)) + result)))))) ;;;============================================================================ ;;; Layer 2: Core Property Functions - Set/Reset/Add