diff --git a/tp-tests.el b/tp-tests.el index 8c1ef8a..b125dcf 100644 --- a/tp-tests.el +++ b/tp-tests.el @@ -3082,8 +3082,9 @@ text content but different properties, the properties should be updated." ;;; ============================================================ (ert-deftest tp-test-tp-text-with-embedded-properties-string () - "Test that tp-set with tp-text overrides embedded properties on strings." - ;; When tp-text is a propertized string and tp-set is used, props override embedded + "Test that tp-set with tp-text preserves embedded properties on strings." + ;; When tp-text is a propertized string, embedded properties should be preserved + ;; (props still override embedded if there's a conflict) (let* ((propertized-text (copy-sequence "Hello")) (_ (put-text-property 0 5 'custom-prop 'embedded-value propertized-text)) (result (tp-set "X" 'tp-text propertized-text 'face 'bold))) @@ -3091,8 +3092,8 @@ text content but different properties, the properties should be updated." (should (equal result "Hello")) ;; The face property from props should be applied (should (equal (tp-at 0 'face result) 'bold)) - ;; tp-set overrides - embedded custom-prop should NOT be present - (should (null (tp-at 0 'custom-prop result))))) + ;; tp-set now preserves embedded props + (should (equal (tp-at 0 'custom-prop result) 'embedded-value)))) (ert-deftest tp-test-tp-add-with-embedded-properties-string () "Test that tp-add with tp-text merges embedded properties on strings." @@ -3108,15 +3109,15 @@ text content but different properties, the properties should be updated." (should (equal (tp-at 0 'custom-prop result) 'embedded-value)))) (ert-deftest tp-test-tp-text-with-embedded-face-string () - "Test that tp-set with tp-text overrides embedded face on strings." + "Test that tp-set with tp-text preserves embedded face on strings." (let* ((propertized-text (copy-sequence "Hello")) (_ (put-text-property 0 5 'face 'italic propertized-text)) ;; Set tp-text with its own face, and also specify help-echo (result (tp-set "X" 'tp-text propertized-text 'help-echo "tip"))) ;; The text content should be from tp-text (should (equal result "Hello")) - ;; tp-set overrides - embedded face should NOT be present (no face in props) - (should (null (tp-at 0 'face result))) + ;; tp-set now preserves embedded face + (should (equal (tp-at 0 'face result) 'italic)) ;; The help-echo from props should be applied (should (equal (tp-at 0 'help-echo result) "tip")))) @@ -3134,7 +3135,7 @@ text content but different properties, the properties should be updated." (should (equal (tp-at 0 'help-echo result) "tip")))) (ert-deftest tp-test-tp-text-with-embedded-properties-buffer () - "Test that tp-set with tp-text overrides embedded properties in buffers." + "Test that tp-set with tp-text preserves embedded properties in buffers." (tp-test-with-temp-buffer (insert "Original") (let* ((propertized-text (copy-sequence "New")) @@ -3144,12 +3145,12 @@ text content but different properties, the properties should be updated." (should (equal (buffer-substring-no-properties 1 4) "New")) ;; The face from props should be applied (should (equal (tp-at 1 'face) 'bold)) - ;; tp-set overrides embedded props - custom-prop should NOT be present - (should (null (tp-at 1 'custom-prop)))))) + ;; tp-set now preserves embedded props + (should (equal (tp-at 1 'custom-prop) 'embedded-value))))) (ert-deftest tp-test-tp-text-with-mixed-properties () - "Test that tp-set with tp-text overrides embedded properties." - ;; tp-set should override embedded props, not merge them + "Test that tp-set with tp-text preserves embedded properties." + ;; tp-set now preserves embedded props (props still take precedence for conflicts) (let* ((propertized-text (copy-sequence "ABCD")) ;; Set a property at position 0 (_ (put-text-property 0 4 'region-type 'start propertized-text)) @@ -3159,11 +3160,11 @@ text content but different properties, the properties should be updated." ;; The face from props should be applied uniformly (should (equal (tp-at 0 'face result) 'bold)) (should (equal (tp-at 3 'face result) 'bold)) - ;; tp-set overrides embedded props - region-type should NOT be present - (should (null (tp-at 0 'region-type result))))) + ;; tp-set now preserves embedded props + (should (equal (tp-at 0 'region-type result) 'start)))) (ert-deftest tp-test-tp-reset-with-embedded-properties () - "Test that tp-reset ignores embedded text properties entirely." + "Test that tp-reset preserves embedded text properties from tp-text." (let* ((propertized-text (copy-sequence "Test")) (_ (put-text-property 0 4 'custom-prop 'value propertized-text)) (result (tp-reset "X" 'tp-text propertized-text 'face 'bold))) @@ -3171,8 +3172,8 @@ text content but different properties, the properties should be updated." (should (equal result "Test")) ;; The face from props should be applied (should (equal (tp-at 0 'face result) 'bold)) - ;; tp-reset ignores embedded props - custom-prop should NOT be present - (should (null (tp-at 0 'custom-prop result))))) + ;; tp-reset now preserves embedded props from tp-text + (should (equal (tp-at 0 'custom-prop result) 'value)))) (ert-deftest tp-test-tp-add-with-embedded-properties () "Test that tp-add with embedded text properties preserves them." diff --git a/tp.el b/tp.el index f7239e8..036253b 100644 --- a/tp.el +++ b/tp.el @@ -1147,9 +1147,10 @@ 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). MERGE-MODE controls how embedded text properties in tp-text are handled: - :merge - embedded properties are merged with props (tp-add behavior) - :override or nil - props override embedded properties (tp-set behavior) - :reset - embedded properties are ignored, only props used (tp-reset behavior) + All modes now preserve embedded text properties from tp-text. + :merge - embedded properties are merged with props, with face merging (tp-add) + :override or nil - props take precedence over embedded properties (tp-set) + :reset - props take precedence over embedded properties (tp-reset) Returns (PROPS NEW-END NEW-OBJECT) where PROPS is the updated props, 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)." @@ -1197,15 +1198,14 @@ NEW-OBJECT is the new string object (only different for strings with tp-text)." tp-text-val)) tp-text-val)) ;; Handle embedded text properties based on merge-mode: - ;; :merge - merge embedded props with props (tp-add) - ;; :override/nil - props take precedence, don't merge (tp-set) - ;; :reset - ignore embedded props entirely (tp-reset) + ;; All modes now preserve embedded text properties from tp-text. + ;; :merge - merge embedded props with props, with face merging (tp-add) + ;; :override/nil - props take precedence over embedded props (tp-set) + ;; :reset - props take precedence over embedded props (tp-reset) + ;; In all cases, use tp--merge-string-props-into-plist which handles + ;; props taking precedence and special face merging when needed. (result-props - (if (eq merge-mode :merge) - ;; tp-add: merge embedded properties with props - (tp--merge-string-props-into-plist final-text props) - ;; tp-set/:override or tp-reset: just use props as-is - props))) + (tp--merge-string-props-into-plist final-text props))) (if (stringp object) ;; For strings: create a new string with tp-text content ;; Strip properties - result-props will be applied by the caller @@ -1425,7 +1425,7 @@ Returns: For buffers, (START . END) cons. For strings, the result string." (defun tp-reset (start-or-string &optional end-or-prop props-or-val &rest rest) "Completely replace all text properties with PROPS. Like `tp-set' but replaces ALL existing properties. -For tp-text, embedded text properties are ignored - only props are used. +For tp-text, embedded text properties are preserved (props override if there's a conflict). **String Modification Behavior:** - Entire string form (tp-reset STRING ...): Returns a NEW propertized string