Add tp-member: plist-member-style property lookup

Like tp-at but distinguishes a property present with value nil from an
absent property, returning (PROPERTY VALUE) or nil.  Covered by four
new tests in tp-ops-tests.el; full suite 338/338 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kinneyzhang 2026-07-26 19:33:34 +08:00
parent 49cb8d8062
commit 08b5d9aa1c
2 changed files with 45 additions and 0 deletions

View File

@ -250,5 +250,33 @@
(should (<= (nth 1 iv) 4)))
(should (equal intervals '((2 4 (face bold))))))))
;;; tp-member
(ert-deftest tp-ops-test-member-present ()
"tp-member returns (PROPERTY VALUE) when the property is present."
(let ((str (copy-sequence "hello")))
(tp-set 0 5 '(face bold) str)
(should (equal (tp-member 0 'face str) '(face bold)))))
(ert-deftest tp-ops-test-member-present-nil-value ()
"tp-member distinguishes a nil value from an absent property."
(let ((str (copy-sequence "hello")))
(tp-set 0 5 '(face nil) str)
(should (equal (tp-member 0 'face str) '(face nil)))))
(ert-deftest tp-ops-test-member-absent ()
"tp-member returns nil for an absent property."
(let ((str (copy-sequence "hello")))
(tp-set 0 5 '(help-echo "tip") str)
(should (equal (tp-member 0 'face str) nil))))
(ert-deftest tp-ops-test-member-buffer ()
"tp-member works on buffer positions."
(with-temp-buffer
(insert "hello")
(put-text-property 1 6 'my-prop nil)
(should (equal (tp-member 1 'my-prop) '(my-prop nil)))
(should (equal (tp-member 1 'other) nil))))
(provide 'tp-ops-tests)
;;; tp-ops-tests.el ends here

View File

@ -538,6 +538,23 @@ Examples:
prop-value))
(text-properties-at pos obj))))
(defun tp-member (pos property &optional object)
"Return (PROPERTY VALUE) if PROPERTY is present at POS in OBJECT.
Return nil when the property is absent. Unlike `tp-at' (which
returns nil both for an absent property and for a property whose
value is nil), this distinguishes \"present with value nil\" from
\"not present\", like `plist-member' does for plists.
OBJECT is a string or buffer; nil means the current buffer.
Examples:
(tp-member 1 \\='face) ;; => (face bold) when face is bold
(tp-member 1 \\='face) ;; => (face nil) when face is present but nil
(tp-member 1 \\='face) ;; => nil when face is absent"
(let ((plist (text-properties-at pos object)))
(when-let ((cell (plist-member plist property)))
(list (car cell) (cadr cell)))))
(defun tp--remove-sub (start end property sub-property &optional object)
"Remove SUB-PROPERTY from PROPERTY between START and END in OBJECT."
(let* ((pos start))