Add support for deeply nested sub-properties and multiple key extraction in tp-get
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
parent
b31077e486
commit
3f7f8cd9b9
14
README.md
14
README.md
@ -312,6 +312,12 @@ For range and entire string queries, returns a list of `(START END VALUE)` inter
|
|||||||
(tp-get START END '(PROPERTY) OBJECT)
|
(tp-get START END '(PROPERTY) OBJECT)
|
||||||
(tp-get START END '(PROPERTY SUB-KEY ...) OBJECT)
|
(tp-get START END '(PROPERTY SUB-KEY ...) OBJECT)
|
||||||
|
|
||||||
|
;; Range with deeply nested property path
|
||||||
|
(tp-get START END '(PROPERTY SUB-KEY SUB-SUB-KEY ...) OBJECT)
|
||||||
|
|
||||||
|
;; Range extracting multiple keys from nested property
|
||||||
|
(tp-get START END '(PROPERTY SUB-KEY (KEY1 KEY2 ...)) OBJECT)
|
||||||
|
|
||||||
;; Range - all properties (returns list of intervals)
|
;; Range - all properties (returns list of intervals)
|
||||||
(tp-get START END)
|
(tp-get START END)
|
||||||
(tp-get START END OBJECT)
|
(tp-get START END OBJECT)
|
||||||
@ -320,6 +326,7 @@ For range and entire string queries, returns a list of `(START END VALUE)` inter
|
|||||||
(tp-get STRING)
|
(tp-get STRING)
|
||||||
(tp-get STRING PROPERTY)
|
(tp-get STRING PROPERTY)
|
||||||
(tp-get STRING PROPERTY SUB-KEY ...)
|
(tp-get STRING PROPERTY SUB-KEY ...)
|
||||||
|
(tp-get STRING PROPERTY SUB-KEY '(KEY1 KEY2 ...))
|
||||||
(tp-get STRING '(PROPERTY SUB-KEY ...))
|
(tp-get STRING '(PROPERTY SUB-KEY ...))
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -348,6 +355,13 @@ For range and entire string queries, returns a list of `(START END VALUE)` inter
|
|||||||
;; Get with property path as list
|
;; Get with property path as list
|
||||||
(tp-get 5 20 '(face :underline :style) my-string) ; => ((5 20 wave))
|
(tp-get 5 20 '(face :underline :style) my-string) ; => ((5 20 wave))
|
||||||
|
|
||||||
|
;; Get deeply nested property from entire string
|
||||||
|
(tp-get str 'face :underline :color) ; => ((0 5 "green") (6 11 "yellow"))
|
||||||
|
|
||||||
|
;; Get multiple keys from nested property
|
||||||
|
(tp-get str 'face :underline '(:color :style))
|
||||||
|
;; => ((0 5 (:color "green" :style wave)) (6 11 (:color "yellow" :style line)))
|
||||||
|
|
||||||
;; Get all properties from range
|
;; Get all properties from range
|
||||||
(tp-get 1 10) ; => ((1 6 (face bold help-echo "test")))
|
(tp-get 1 10) ; => ((1 6 (face bold help-echo "test")))
|
||||||
|
|
||||||
|
|||||||
14
README_CN.md
14
README_CN.md
@ -311,6 +311,12 @@ tp.el 提供三个主要的属性设置函数,每个有不同的语义:
|
|||||||
(tp-get START END '(PROPERTY) OBJECT)
|
(tp-get START END '(PROPERTY) OBJECT)
|
||||||
(tp-get START END '(PROPERTY SUB-KEY ...) OBJECT)
|
(tp-get START END '(PROPERTY SUB-KEY ...) OBJECT)
|
||||||
|
|
||||||
|
;; 范围 - 深层嵌套属性路径
|
||||||
|
(tp-get START END '(PROPERTY SUB-KEY SUB-SUB-KEY ...) OBJECT)
|
||||||
|
|
||||||
|
;; 范围 - 从嵌套属性中提取多个键
|
||||||
|
(tp-get START END '(PROPERTY SUB-KEY (KEY1 KEY2 ...)) OBJECT)
|
||||||
|
|
||||||
;; 范围 - 所有属性(返回区间列表)
|
;; 范围 - 所有属性(返回区间列表)
|
||||||
(tp-get START END)
|
(tp-get START END)
|
||||||
(tp-get START END OBJECT)
|
(tp-get START END OBJECT)
|
||||||
@ -319,6 +325,7 @@ tp.el 提供三个主要的属性设置函数,每个有不同的语义:
|
|||||||
(tp-get STRING)
|
(tp-get STRING)
|
||||||
(tp-get STRING PROPERTY)
|
(tp-get STRING PROPERTY)
|
||||||
(tp-get STRING PROPERTY SUB-KEY ...)
|
(tp-get STRING PROPERTY SUB-KEY ...)
|
||||||
|
(tp-get STRING PROPERTY SUB-KEY '(KEY1 KEY2 ...))
|
||||||
(tp-get STRING '(PROPERTY SUB-KEY ...))
|
(tp-get STRING '(PROPERTY SUB-KEY ...))
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -347,6 +354,13 @@ tp.el 提供三个主要的属性设置函数,每个有不同的语义:
|
|||||||
;; 使用列表形式的属性路径
|
;; 使用列表形式的属性路径
|
||||||
(tp-get 5 20 '(face :underline :style) my-string) ; => ((5 20 wave))
|
(tp-get 5 20 '(face :underline :style) my-string) ; => ((5 20 wave))
|
||||||
|
|
||||||
|
;; 从整个字符串获取深层嵌套属性
|
||||||
|
(tp-get str 'face :underline :color) ; => ((0 5 "green") (6 11 "yellow"))
|
||||||
|
|
||||||
|
;; 从嵌套属性中获取多个键
|
||||||
|
(tp-get str 'face :underline '(:color :style))
|
||||||
|
;; => ((0 5 (:color "green" :style wave)) (6 11 (:color "yellow" :style line)))
|
||||||
|
|
||||||
;; 获取范围内的所有属性
|
;; 获取范围内的所有属性
|
||||||
(tp-get 1 10) ; => ((1 6 (face bold help-echo "test")))
|
(tp-get 1 10) ; => ((1 6 (face bold help-echo "test")))
|
||||||
|
|
||||||
|
|||||||
33
tp-tests.el
33
tp-tests.el
@ -1239,5 +1239,38 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(should (equal (car intervals) '(0 5 bold)))
|
(should (equal (car intervals) '(0 5 bold)))
|
||||||
(should (equal (cadr intervals) '(12 17 italic))))))
|
(should (equal (cadr intervals) '(12 17 italic))))))
|
||||||
|
|
||||||
|
(ert-deftest tp-test-get-deeply-nested-property ()
|
||||||
|
"Test tp-get with deeply nested property path."
|
||||||
|
(let ((str (copy-sequence "Hello World")))
|
||||||
|
(put-text-property 0 5 'face '(:foreground "red" :underline (:color "green" :style wave)) str)
|
||||||
|
(put-text-property 6 11 'face '(:foreground "blue" :underline (:color "yellow" :style line)) str)
|
||||||
|
;; Test deeply nested single key from entire string
|
||||||
|
(let ((intervals (tp-get str 'face :underline :color)))
|
||||||
|
(should (= (length intervals) 2))
|
||||||
|
(should (equal (caddr (car intervals)) "green"))
|
||||||
|
(should (equal (caddr (cadr intervals)) "yellow")))
|
||||||
|
;; Test range with deeply nested key
|
||||||
|
(let ((intervals (tp-get 0 7 '(face :underline :color) str)))
|
||||||
|
(should (= (length intervals) 2))
|
||||||
|
(should (equal (caddr (car intervals)) "green")))))
|
||||||
|
|
||||||
|
(ert-deftest tp-test-get-multiple-nested-keys ()
|
||||||
|
"Test tp-get with multiple keys from nested property."
|
||||||
|
(let ((str (copy-sequence "Hello World")))
|
||||||
|
(put-text-property 0 5 'face '(:foreground "red" :underline (:color "green" :style wave)) str)
|
||||||
|
(put-text-property 6 11 'face '(:foreground "blue" :underline (:color "yellow" :style line)) str)
|
||||||
|
;; Test extracting multiple keys from entire string
|
||||||
|
(let ((intervals (tp-get str 'face :underline '(:color :style))))
|
||||||
|
(should (= (length intervals) 2))
|
||||||
|
(let ((val1 (caddr (car intervals)))
|
||||||
|
(val2 (caddr (cadr intervals))))
|
||||||
|
(should (equal (plist-get val1 :color) "green"))
|
||||||
|
(should (eq (plist-get val1 :style) 'wave))
|
||||||
|
(should (equal (plist-get val2 :color) "yellow"))
|
||||||
|
(should (eq (plist-get val2 :style) 'line))))
|
||||||
|
;; Test range with multiple keys
|
||||||
|
(let ((intervals (tp-get 0 7 '(face :underline (:color :style)) str)))
|
||||||
|
(should (= (length intervals) 2)))))
|
||||||
|
|
||||||
(provide 'tp-ert-tests)
|
(provide 'tp-ert-tests)
|
||||||
;;; tp-ert-tests.el ends here
|
;;; tp-ert-tests.el ends here
|
||||||
|
|||||||
15
tp.el
15
tp.el
@ -398,13 +398,26 @@ Return the modified object (string) or region (START . END) for buffer."
|
|||||||
(defun tp--get-nested (value path)
|
(defun tp--get-nested (value path)
|
||||||
"Get nested value from VALUE following PATH.
|
"Get nested value from VALUE following PATH.
|
||||||
PATH is a list of keys/symbols to traverse nested structures.
|
PATH is a list of keys/symbols to traverse nested structures.
|
||||||
Supports plists, alists, and special display property formats."
|
Supports plists, alists, and special display property formats.
|
||||||
|
|
||||||
|
If an element in PATH is a list of keys, extract those keys from the
|
||||||
|
current value and return a plist with those keys.
|
||||||
|
Example: (tp--get-nested \\='(:a 1 :b 2 :c 3) \\='((:a :b))) => (:a 1 :b 2)"
|
||||||
(if (null path)
|
(if (null path)
|
||||||
value
|
value
|
||||||
(let* ((key (car path))
|
(let* ((key (car path))
|
||||||
(rest (cdr path))
|
(rest (cdr path))
|
||||||
(next-value
|
(next-value
|
||||||
(cond
|
(cond
|
||||||
|
;; Key is a list of keys - extract multiple keys from value
|
||||||
|
((and (listp key) (not (null key)))
|
||||||
|
(when (and (listp value) (keywordp (car value)))
|
||||||
|
(let ((result nil))
|
||||||
|
(dolist (k (reverse key))
|
||||||
|
(let ((v (plist-get value k)))
|
||||||
|
(when v
|
||||||
|
(setq result (plist-put result k v)))))
|
||||||
|
result)))
|
||||||
;; Value is a plist with keyword keys
|
;; Value is a plist with keyword keys
|
||||||
((and (listp value) (keywordp (car value)))
|
((and (listp value) (keywordp (car value)))
|
||||||
(plist-get value key))
|
(plist-get value key))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user