Refactor tp-forward/backward and tp-search-do API
- tp-forward and tp-backward now support string objects - Renamed tp-forward-do to tp--forward-do (private) with string support - Renamed tp-backward-do to tp--backward-do (private) with string support - New public tp-forward-do and tp-backward-do: function receives matched text only - Renamed tp-search-do to tp--search-do (private) - New public tp-search-map: function receives matched text only - Updated English and Chinese documentation - Updated and added tests for all new functionality Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
parent
080239e3ce
commit
0b0bfedc6b
69
README.md
69
README.md
@ -88,12 +88,12 @@ A complete overview of all tp.el functions organized by category:
|
||||
|----------|-------------|
|
||||
| [`tp-search-forward`](#tp-search-forward--tp-search-backward) | Raw wrapper for text-property-search-forward |
|
||||
| [`tp-search-backward`](#tp-search-forward--tp-search-backward) | Raw wrapper for text-property-search-backward |
|
||||
| [`tp-forward`](#tp-forward--tp-backward) | Search forward N times for text with property |
|
||||
| [`tp-backward`](#tp-forward--tp-backward) | Search backward N times for text with property |
|
||||
| [`tp-forward-do`](#tp-forward-do--tp-backward-do) | Apply function to N forward matches |
|
||||
| [`tp-backward-do`](#tp-forward-do--tp-backward-do) | Apply function to N backward matches |
|
||||
| [`tp-forward`](#tp-forward--tp-backward) | Search forward N times for text with property (buffers and strings) |
|
||||
| [`tp-backward`](#tp-forward--tp-backward) | Search backward N times for text with property (buffers and strings) |
|
||||
| [`tp-forward-do`](#tp-forward-do--tp-backward-do) | Apply function to matched text for N forward matches |
|
||||
| [`tp-backward-do`](#tp-forward-do--tp-backward-do) | Apply function to matched text for N backward matches |
|
||||
| [`tp-search`](#tp-search---search-all-matches) | Search all matching properties in range or string |
|
||||
| [`tp-search-do`](#tp-search-do---apply-function-to-all-matches) | Apply function to all matching properties |
|
||||
| [`tp-search-map`](#tp-search-map---apply-function-to-matched-text) | Apply function to matched text for all matches |
|
||||
|
||||
#### Query Functions
|
||||
| Function | Description |
|
||||
@ -573,8 +573,9 @@ Search forward/backward N times for text with PROPERTY.
|
||||
|
||||
- **N** is the number of searches, defaulting to 1.
|
||||
- **VALUE** is the optional value to match.
|
||||
- **OBJECT** can be a buffer; nil defaults to current buffer.
|
||||
- Returns the prop-match object from the last successful search.
|
||||
- **OBJECT** can be a buffer or string; nil defaults to current buffer.
|
||||
- For buffers, returns the prop-match object from the last successful search.
|
||||
- For strings, returns a list of (START END VALUE) for all matches found.
|
||||
|
||||
**Examples:**
|
||||
|
||||
@ -587,6 +588,10 @@ Search forward/backward N times for text with PROPERTY.
|
||||
|
||||
;; Search forward 3 times
|
||||
(tp-forward 'marker nil nil 3)
|
||||
|
||||
;; Search in a string
|
||||
(tp-forward 'marker nil my-string 2)
|
||||
;; => ((0 5 t) (12 17 t))
|
||||
```
|
||||
|
||||
---
|
||||
@ -598,19 +603,27 @@ Search forward/backward N times for text with PROPERTY.
|
||||
(tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT N)
|
||||
```
|
||||
|
||||
Search forward/backward N times for text with PROPERTY and apply FUNCTION to each match.
|
||||
Search forward/backward N times for text with PROPERTY and apply FUNCTION to matched text.
|
||||
|
||||
- **FUNCTION** receives two arguments: the prop-match object and OBJECT.
|
||||
- **FUNCTION** receives the matched text as its only argument. The return value
|
||||
of FUNCTION replaces the matched text in the string or buffer.
|
||||
- **N** is the number of searches, defaulting to 1.
|
||||
- **OBJECT** can be a buffer or string; nil defaults to current buffer.
|
||||
- Returns the number of successful matches.
|
||||
|
||||
**Examples:**
|
||||
|
||||
```elisp
|
||||
;; Apply function to next 3 markers
|
||||
;; Upcase matched text in buffer
|
||||
(tp-forward-do #'upcase 'marker nil nil 3)
|
||||
|
||||
;; Upcase matched text in string
|
||||
(tp-forward-do #'upcase 'marker nil my-string 2)
|
||||
|
||||
;; Custom transformation
|
||||
(tp-forward-do
|
||||
(lambda (match obj)
|
||||
(message "Found at %d" (prop-match-beginning match)))
|
||||
(lambda (text)
|
||||
(concat "[" text "]"))
|
||||
'marker nil nil 3)
|
||||
```
|
||||
|
||||
@ -647,36 +660,36 @@ Returns a list of (START END VALUE) for all matching regions.
|
||||
|
||||
---
|
||||
|
||||
#### `tp-search-do` - Apply Function to All Matches
|
||||
#### `tp-search-map` - Apply Function to Matched Text
|
||||
|
||||
```elisp
|
||||
;; Buffer/string region
|
||||
(tp-search-do FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
(tp-search-map FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
|
||||
;; Entire string
|
||||
(tp-search-do FUNCTION STRING PROPERTY &optional VALUE)
|
||||
(tp-search-map FUNCTION STRING PROPERTY &optional VALUE)
|
||||
```
|
||||
|
||||
Execute FUNCTION on all matches of PROPERTY in a buffer/string range or entire string.
|
||||
Apply FUNCTION to matched text for all matches of PROPERTY.
|
||||
|
||||
- **FUNCTION** receives two arguments: the match (list of START END VALUE) and OBJECT.
|
||||
- **FUNCTION** receives the matched text as its only argument. The return value
|
||||
of FUNCTION replaces the matched text in the string or buffer.
|
||||
- Returns the number of matches processed.
|
||||
|
||||
**Examples:**
|
||||
|
||||
```elisp
|
||||
;; Process all markers in buffer range
|
||||
(tp-search-do
|
||||
(lambda (match obj)
|
||||
(message "Found at %d-%d with value %s"
|
||||
(car match) (cadr match) (caddr match)))
|
||||
1 100 'marker)
|
||||
;; Upcase all markers in string
|
||||
(tp-search-map #'upcase my-string 'marker)
|
||||
|
||||
;; Process all headings in string
|
||||
(tp-search-do
|
||||
(lambda (match obj)
|
||||
(upcase (substring obj (car match) (cadr match))))
|
||||
my-string 'type 'heading)
|
||||
;; Upcase all markers in buffer range
|
||||
(tp-search-map #'upcase 1 100 'marker)
|
||||
|
||||
;; Custom transformation
|
||||
(tp-search-map
|
||||
(lambda (text)
|
||||
(concat "[" text "]"))
|
||||
my-string 'marker)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
67
README_CN.md
67
README_CN.md
@ -87,12 +87,12 @@ tp.el 所有函数按类别组织的完整概览:
|
||||
|------|------|
|
||||
| [`tp-search-forward`](#tp-search-forward--tp-search-backward) | text-property-search-forward 的原始包装 |
|
||||
| [`tp-search-backward`](#tp-search-forward--tp-search-backward) | text-property-search-backward 的原始包装 |
|
||||
| [`tp-forward`](#tp-forward--tp-backward) | 向前搜索 N 次具有属性的文本 |
|
||||
| [`tp-backward`](#tp-forward--tp-backward) | 向后搜索 N 次具有属性的文本 |
|
||||
| [`tp-forward-do`](#tp-forward-do--tp-backward-do) | 对 N 个向前匹配应用函数 |
|
||||
| [`tp-backward-do`](#tp-forward-do--tp-backward-do) | 对 N 个向后匹配应用函数 |
|
||||
| [`tp-forward`](#tp-forward--tp-backward) | 向前搜索 N 次具有属性的文本(支持缓冲区和字符串) |
|
||||
| [`tp-backward`](#tp-forward--tp-backward) | 向后搜索 N 次具有属性的文本(支持缓冲区和字符串) |
|
||||
| [`tp-forward-do`](#tp-forward-do--tp-backward-do) | 对 N 个向前匹配的文本应用函数 |
|
||||
| [`tp-backward-do`](#tp-forward-do--tp-backward-do) | 对 N 个向后匹配的文本应用函数 |
|
||||
| [`tp-search`](#tp-search---搜索所有匹配) | 在范围或字符串中搜索所有匹配的属性 |
|
||||
| [`tp-search-do`](#tp-search-do---对所有匹配应用函数) | 对所有匹配的属性应用函数 |
|
||||
| [`tp-search-map`](#tp-search-map---对匹配文本应用函数) | 对所有匹配的文本应用函数 |
|
||||
|
||||
#### 查询函数
|
||||
| 函数 | 描述 |
|
||||
@ -572,8 +572,9 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
|
||||
|
||||
- **N** 是搜索次数,默认为 1。
|
||||
- **VALUE** 是可选的匹配值。
|
||||
- **OBJECT** 可以是缓冲区;nil 默认为当前缓冲区。
|
||||
- 返回最后一次成功搜索的 prop-match 对象。
|
||||
- **OBJECT** 可以是缓冲区或字符串;nil 默认为当前缓冲区。
|
||||
- 对于缓冲区,返回最后一次成功搜索的 prop-match 对象。
|
||||
- 对于字符串,返回所有匹配的 (START END VALUE) 列表。
|
||||
|
||||
**示例:**
|
||||
|
||||
@ -586,6 +587,10 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
|
||||
|
||||
;; 向前搜索 3 次
|
||||
(tp-forward 'marker nil nil 3)
|
||||
|
||||
;; 在字符串中搜索
|
||||
(tp-forward 'marker nil my-string 2)
|
||||
;; => ((0 5 t) (12 17 t))
|
||||
```
|
||||
|
||||
---
|
||||
@ -597,19 +602,26 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
|
||||
(tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT N)
|
||||
```
|
||||
|
||||
向前/向后搜索 N 次具有 PROPERTY 的文本,并对每个匹配应用 FUNCTION。
|
||||
向前/向后搜索 N 次具有 PROPERTY 的文本,并对匹配的文本应用 FUNCTION。
|
||||
|
||||
- **FUNCTION** 接收两个参数:prop-match 对象和 OBJECT。
|
||||
- **FUNCTION** 接收匹配到的文本作为唯一参数。FUNCTION 的返回值将替换字符串或缓冲区中的匹配文本。
|
||||
- **N** 是搜索次数,默认为 1。
|
||||
- **OBJECT** 可以是缓冲区或字符串;nil 默认为当前缓冲区。
|
||||
- 返回成功匹配的数量。
|
||||
|
||||
**示例:**
|
||||
|
||||
```elisp
|
||||
;; 对下 3 个 marker 应用函数
|
||||
;; 将缓冲区中匹配的文本转为大写
|
||||
(tp-forward-do #'upcase 'marker nil nil 3)
|
||||
|
||||
;; 将字符串中匹配的文本转为大写
|
||||
(tp-forward-do #'upcase 'marker nil my-string 2)
|
||||
|
||||
;; 自定义转换
|
||||
(tp-forward-do
|
||||
(lambda (match obj)
|
||||
(message "在 %d 处找到" (prop-match-beginning match)))
|
||||
(lambda (text)
|
||||
(concat "[" text "]"))
|
||||
'marker nil nil 3)
|
||||
```
|
||||
|
||||
@ -646,36 +658,35 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
|
||||
|
||||
---
|
||||
|
||||
#### `tp-search-do` - 对所有匹配应用函数
|
||||
#### `tp-search-map` - 对匹配文本应用函数
|
||||
|
||||
```elisp
|
||||
;; 缓冲区/字符串区域
|
||||
(tp-search-do FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
(tp-search-map FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
|
||||
;; 整个字符串
|
||||
(tp-search-do FUNCTION STRING PROPERTY &optional VALUE)
|
||||
(tp-search-map FUNCTION STRING PROPERTY &optional VALUE)
|
||||
```
|
||||
|
||||
在缓冲区/字符串范围或整个字符串中对所有 PROPERTY 匹配执行 FUNCTION。
|
||||
对所有 PROPERTY 匹配的文本应用 FUNCTION。
|
||||
|
||||
- **FUNCTION** 接收两个参数:匹配(START END VALUE 列表)和 OBJECT。
|
||||
- **FUNCTION** 接收匹配到的文本作为唯一参数。FUNCTION 的返回值将替换字符串或缓冲区中的匹配文本。
|
||||
- 返回处理的匹配数量。
|
||||
|
||||
**示例:**
|
||||
|
||||
```elisp
|
||||
;; 处理缓冲区范围内的所有 marker
|
||||
(tp-search-do
|
||||
(lambda (match obj)
|
||||
(message "在 %d-%d 处找到,值为 %s"
|
||||
(car match) (cadr match) (caddr match)))
|
||||
1 100 'marker)
|
||||
;; 将字符串中所有 marker 文本转为大写
|
||||
(tp-search-map #'upcase my-string 'marker)
|
||||
|
||||
;; 处理字符串中的所有标题
|
||||
(tp-search-do
|
||||
(lambda (match obj)
|
||||
(upcase (substring obj (car match) (cadr match))))
|
||||
my-string 'type 'heading)
|
||||
;; 将缓冲区范围内所有 marker 文本转为大写
|
||||
(tp-search-map #'upcase 1 100 'marker)
|
||||
|
||||
;; 自定义转换
|
||||
(tp-search-map
|
||||
(lambda (text)
|
||||
(concat "[" text "]"))
|
||||
my-string 'marker)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
116
tp-tests.el
116
tp-tests.el
@ -557,6 +557,16 @@
|
||||
(should match)
|
||||
(should (= (prop-match-beginning match) 7)))))
|
||||
|
||||
(ert-deftest tp-test-forward-on-string ()
|
||||
"Test tp-forward works on string objects."
|
||||
(let ((str (copy-sequence "Hello World Hello")))
|
||||
(tp-set 0 5 '(marker t) str)
|
||||
(tp-set 12 17 '(marker t) str)
|
||||
(let ((matches (tp-forward 'marker nil str 2)))
|
||||
(should (= (length matches) 2))
|
||||
(should (equal (car matches) '(0 5 t)))
|
||||
(should (equal (cadr matches) '(12 17 t))))))
|
||||
|
||||
(ert-deftest tp-test-forward-with-n ()
|
||||
"Test tp-forward with N parameter."
|
||||
(tp-test-with-temp-buffer
|
||||
@ -583,8 +593,34 @@
|
||||
(should match)
|
||||
(should (= (prop-match-beginning match) 1)))))
|
||||
|
||||
(ert-deftest tp-test-backward-on-string ()
|
||||
"Test tp-backward works on string objects."
|
||||
(let ((str (copy-sequence "Hello World Hello")))
|
||||
(tp-set 0 5 '(marker t) str)
|
||||
(tp-set 12 17 '(marker t) str)
|
||||
(let ((matches (tp-backward 'marker nil str 2)))
|
||||
(should (= (length matches) 2))
|
||||
;; Backward returns matches in reverse order
|
||||
(should (equal (car matches) '(12 17 t)))
|
||||
(should (equal (cadr matches) '(0 5 t))))))
|
||||
|
||||
(ert-deftest tp-test-forward-do ()
|
||||
"Test tp-forward-do applies function to matches."
|
||||
"Test tp-forward-do applies function to matched text."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "hello World test")
|
||||
(tp-set 1 6 '(marker t))
|
||||
(tp-set 13 17 '(marker t))
|
||||
(goto-char 1)
|
||||
(skip-unless (fboundp 'text-property-search-forward))
|
||||
;; Test that function receives text and can transform it
|
||||
(let ((count (tp-forward-do #'upcase 'marker nil nil 2)))
|
||||
(should (= count 2))
|
||||
;; Check that text was upcased
|
||||
(should (equal (buffer-substring 1 6) "HELLO"))
|
||||
(should (equal (buffer-substring 13 17) "TEST")))))
|
||||
|
||||
(ert-deftest tp-test--forward-do ()
|
||||
"Test tp--forward-do applies function to matches (internal API)."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "Hello World Test")
|
||||
(tp-set 1 6 '(marker t))
|
||||
@ -592,14 +628,29 @@
|
||||
(goto-char 1)
|
||||
(skip-unless (fboundp 'text-property-search-forward))
|
||||
(let ((result nil))
|
||||
(tp-forward-do
|
||||
(tp--forward-do
|
||||
(lambda (match obj)
|
||||
(push (prop-match-beginning match) result))
|
||||
'marker nil nil 2)
|
||||
(should (= (length result) 2)))))
|
||||
|
||||
(ert-deftest tp-test-backward-do ()
|
||||
"Test tp-backward-do applies function to matches."
|
||||
"Test tp-backward-do applies function to matched text."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "hello World test")
|
||||
(tp-set 1 6 '(marker t))
|
||||
(tp-set 13 17 '(marker t))
|
||||
(goto-char 18)
|
||||
(skip-unless (fboundp 'text-property-search-backward))
|
||||
;; Test that function receives text and can transform it
|
||||
(let ((count (tp-backward-do #'upcase 'marker nil nil 2)))
|
||||
(should (= count 2))
|
||||
;; Check that text was upcased
|
||||
(should (equal (buffer-substring 1 6) "HELLO"))
|
||||
(should (equal (buffer-substring 13 17) "TEST")))))
|
||||
|
||||
(ert-deftest tp-test--backward-do ()
|
||||
"Test tp--backward-do applies function to matches (internal API)."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "Hello World Test")
|
||||
(tp-set 1 6 '(marker t))
|
||||
@ -607,12 +658,34 @@
|
||||
(goto-char 18)
|
||||
(skip-unless (fboundp 'text-property-search-backward))
|
||||
(let ((result nil))
|
||||
(tp-backward-do
|
||||
(tp--backward-do
|
||||
(lambda (match obj)
|
||||
(push (prop-match-beginning match) result))
|
||||
'marker nil nil 2)
|
||||
(should (= (length result) 2)))))
|
||||
|
||||
(ert-deftest tp-test-forward-do-on-string ()
|
||||
"Test tp-forward-do works on string objects."
|
||||
(let ((str (copy-sequence "hello World hello")))
|
||||
(tp-set 0 5 '(marker t) str)
|
||||
(tp-set 12 17 '(marker t) str)
|
||||
(let ((count (tp-forward-do #'upcase 'marker nil str 2)))
|
||||
(should (= count 2))
|
||||
;; Check that text was upcased
|
||||
(should (equal (substring str 0 5) "HELLO"))
|
||||
(should (equal (substring str 12 17) "HELLO")))))
|
||||
|
||||
(ert-deftest tp-test-backward-do-on-string ()
|
||||
"Test tp-backward-do works on string objects."
|
||||
(let ((str (copy-sequence "hello World hello")))
|
||||
(tp-set 0 5 '(marker t) str)
|
||||
(tp-set 12 17 '(marker t) str)
|
||||
(let ((count (tp-backward-do #'upcase 'marker nil str 2)))
|
||||
(should (= count 2))
|
||||
;; Check that text was upcased
|
||||
(should (equal (substring str 0 5) "HELLO"))
|
||||
(should (equal (substring str 12 17) "HELLO")))))
|
||||
|
||||
(ert-deftest tp-test-search-on-string ()
|
||||
"Test tp-search finds all matching properties in a string."
|
||||
(let ((str (copy-sequence "Hello World Hello")))
|
||||
@ -645,13 +718,13 @@
|
||||
(should (equal (car matches) '(1 6 t)))
|
||||
(should (equal (cadr matches) '(13 18 t))))))
|
||||
|
||||
(ert-deftest tp-test-search-do-on-string ()
|
||||
"Test tp-search-do applies function to all matches in a string."
|
||||
(ert-deftest tp-test--search-do-on-string ()
|
||||
"Test tp--search-do applies function to all matches in a string (internal API)."
|
||||
(let ((str (copy-sequence "Hello World Hello")))
|
||||
(tp-set 0 5 '(marker t) str)
|
||||
(tp-set 12 17 '(marker t) str)
|
||||
(let ((result nil))
|
||||
(tp-search-do
|
||||
(tp--search-do
|
||||
(lambda (match obj)
|
||||
(push (car match) result))
|
||||
str 'marker)
|
||||
@ -659,14 +732,14 @@
|
||||
(should (member 0 result))
|
||||
(should (member 12 result)))))
|
||||
|
||||
(ert-deftest tp-test-search-do-in-range ()
|
||||
"Test tp-search-do applies function to all matches in a buffer range."
|
||||
(ert-deftest tp-test--search-do-in-range ()
|
||||
"Test tp--search-do applies function to all matches in a buffer range (internal API)."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "Hello World Hello")
|
||||
(tp-set 1 6 '(marker t))
|
||||
(tp-set 13 18 '(marker t))
|
||||
(let ((result nil))
|
||||
(tp-search-do
|
||||
(tp--search-do
|
||||
(lambda (match obj)
|
||||
(push (car match) result))
|
||||
1 18 'marker)
|
||||
@ -674,6 +747,29 @@
|
||||
(should (member 1 result))
|
||||
(should (member 13 result)))))
|
||||
|
||||
(ert-deftest tp-test-search-map-on-string ()
|
||||
"Test tp-search-map applies function to matched text in a string."
|
||||
(let ((str (copy-sequence "hello World hello")))
|
||||
(tp-set 0 5 '(marker t) str)
|
||||
(tp-set 12 17 '(marker t) str)
|
||||
(let ((count (tp-search-map #'upcase str 'marker)))
|
||||
(should (= count 2))
|
||||
;; Check that text was upcased
|
||||
(should (equal (substring str 0 5) "HELLO"))
|
||||
(should (equal (substring str 12 17) "HELLO")))))
|
||||
|
||||
(ert-deftest tp-test-search-map-in-range ()
|
||||
"Test tp-search-map applies function to matched text in a buffer range."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "hello World hello")
|
||||
(tp-set 1 6 '(marker t))
|
||||
(tp-set 13 18 '(marker t))
|
||||
(let ((count (tp-search-map #'upcase 1 18 'marker)))
|
||||
(should (= count 2))
|
||||
;; Check that text was upcased
|
||||
(should (equal (buffer-substring 1 6) "HELLO"))
|
||||
(should (equal (buffer-substring 13 18) "HELLO")))))
|
||||
|
||||
;;; ============================================================
|
||||
;;; Utility Function Tests
|
||||
;;; ============================================================
|
||||
|
||||
245
tp.el
245
tp.el
@ -1012,76 +1012,181 @@ VALUE, PREDICATE, and NOT-CURRENT work as in `text-property-search-backward'."
|
||||
|
||||
N is the number of searches, defaulting to 1.
|
||||
VALUE is the optional value to match.
|
||||
OBJECT can be a buffer; nil defaults to current buffer.
|
||||
OBJECT can be a buffer or string; nil defaults to current buffer.
|
||||
|
||||
Returns the prop-match object from the last successful search,
|
||||
or nil if not found.
|
||||
For buffers, returns the prop-match object from the last successful search.
|
||||
For strings, returns a list of (START END VALUE) for all matches found.
|
||||
|
||||
Uses `tp-search-forward' internally."
|
||||
(let ((count (or n 1))
|
||||
(result nil)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(setq result (tp-search-forward property value))))
|
||||
result))
|
||||
Uses `tp-search-forward' for buffers and `tp-search' for strings."
|
||||
(let ((count (or n 1)))
|
||||
(cond
|
||||
;; String object - use tp-search
|
||||
((stringp object)
|
||||
(let ((matches (tp-search object property value)))
|
||||
(seq-take matches count)))
|
||||
;; Buffer or nil
|
||||
(t
|
||||
(let ((result nil)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(setq result (tp-search-forward property value))))
|
||||
result)))))
|
||||
|
||||
(defun tp-backward (property &optional value object n)
|
||||
"Search backward N times for text with PROPERTY.
|
||||
|
||||
N is the number of searches, defaulting to 1.
|
||||
VALUE is the optional value to match.
|
||||
OBJECT can be a buffer; nil defaults to current buffer.
|
||||
OBJECT can be a buffer or string; nil defaults to current buffer.
|
||||
|
||||
Returns the prop-match object from the last successful search,
|
||||
or nil if not found.
|
||||
For buffers, returns the prop-match object from the last successful search.
|
||||
For strings, returns a list of (START END VALUE) for the last N matches
|
||||
in reverse order (from end to start).
|
||||
|
||||
Uses `tp-search-backward' internally."
|
||||
(let ((count (or n 1))
|
||||
(result nil)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(setq result (tp-search-backward property value))))
|
||||
result))
|
||||
Uses `tp-search-backward' for buffers and `tp-search' for strings."
|
||||
(let ((count (or n 1)))
|
||||
(cond
|
||||
;; String object - use tp-search and reverse
|
||||
((stringp object)
|
||||
(let ((matches (nreverse (tp-search object property value))))
|
||||
(seq-take matches count)))
|
||||
;; Buffer or nil
|
||||
(t
|
||||
(let ((result nil)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(setq result (tp-search-backward property value))))
|
||||
result)))))
|
||||
|
||||
(defun tp--forward-do (function property &optional value object n)
|
||||
"Internal: Search forward N times for PROPERTY and apply FUNCTION to each match.
|
||||
|
||||
FUNCTION receives two arguments: the prop-match object (or list for strings)
|
||||
and OBJECT.
|
||||
N is the number of searches, defaulting to 1.
|
||||
VALUE is the optional value to match.
|
||||
OBJECT can be a buffer or string; nil defaults to current buffer.
|
||||
|
||||
Returns the number of successful matches."
|
||||
(let ((count (or n 1)))
|
||||
(cond
|
||||
;; String object
|
||||
((stringp object)
|
||||
(let ((matches (seq-take (tp-search object property value) count)))
|
||||
(dolist (match matches)
|
||||
(funcall function match object))
|
||||
(length matches)))
|
||||
;; Buffer or nil
|
||||
(t
|
||||
(let ((matches 0)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(when-let ((match (tp-search-forward property value)))
|
||||
(funcall function match buf)
|
||||
(cl-incf matches))))
|
||||
matches)))))
|
||||
|
||||
(defun tp-forward-do (function property &optional value object n)
|
||||
"Search forward N times for text with PROPERTY and apply FUNCTION to each match.
|
||||
|
||||
FUNCTION receives two arguments: the prop-match object and OBJECT.
|
||||
FUNCTION receives the matched text as its only argument. The return value
|
||||
of FUNCTION replaces the matched text in the string or buffer.
|
||||
|
||||
N is the number of searches, defaulting to 1.
|
||||
VALUE is the optional value to match.
|
||||
OBJECT can be a buffer; nil defaults to current buffer.
|
||||
OBJECT can be a buffer or string; nil defaults to current buffer.
|
||||
|
||||
Returns the number of successful matches.
|
||||
|
||||
Example:
|
||||
;; Upcase all matched text
|
||||
(tp-forward-do #\\='upcase \\='marker nil my-string 3)"
|
||||
(tp--forward-do
|
||||
(lambda (match obj)
|
||||
(let* ((start (if (listp match) (car match) (prop-match-beginning match)))
|
||||
(end (if (listp match) (cadr match) (prop-match-end match)))
|
||||
(text (if (stringp obj)
|
||||
(substring obj start end)
|
||||
(buffer-substring start end)))
|
||||
(new-text (funcall function text)))
|
||||
(when (and new-text (not (equal new-text text)))
|
||||
(if (stringp obj)
|
||||
;; For strings, we need to replace in-place
|
||||
(progn
|
||||
(store-substring obj start new-text))
|
||||
;; For buffers, delete and insert
|
||||
(save-excursion
|
||||
(delete-region start end)
|
||||
(goto-char start)
|
||||
(insert new-text))))))
|
||||
property value object n))
|
||||
|
||||
(defun tp--backward-do (function property &optional value object n)
|
||||
"Internal: Search backward N times for PROPERTY and apply FUNCTION to each match.
|
||||
|
||||
FUNCTION receives two arguments: the prop-match object (or list for strings)
|
||||
and OBJECT.
|
||||
N is the number of searches, defaulting to 1.
|
||||
VALUE is the optional value to match.
|
||||
OBJECT can be a buffer or string; nil defaults to current buffer.
|
||||
|
||||
Returns the number of successful matches."
|
||||
(let ((count (or n 1))
|
||||
(matches 0)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(when-let ((match (tp-search-forward property value)))
|
||||
(funcall function match buf)
|
||||
(cl-incf matches))))
|
||||
matches))
|
||||
(let ((count (or n 1)))
|
||||
(cond
|
||||
;; String object - reverse the matches
|
||||
((stringp object)
|
||||
(let ((matches (seq-take (nreverse (tp-search object property value)) count)))
|
||||
(dolist (match matches)
|
||||
(funcall function match object))
|
||||
(length matches)))
|
||||
;; Buffer or nil
|
||||
(t
|
||||
(let ((matches 0)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(when-let ((match (tp-search-backward property value)))
|
||||
(funcall function match buf)
|
||||
(cl-incf matches))))
|
||||
matches)))))
|
||||
|
||||
(defun tp-backward-do (function property &optional value object n)
|
||||
"Search backward N times for text with PROPERTY and apply FUNCTION to each match.
|
||||
|
||||
FUNCTION receives two arguments: the prop-match object and OBJECT.
|
||||
FUNCTION receives the matched text as its only argument. The return value
|
||||
of FUNCTION replaces the matched text in the string or buffer.
|
||||
|
||||
N is the number of searches, defaulting to 1.
|
||||
VALUE is the optional value to match.
|
||||
OBJECT can be a buffer; nil defaults to current buffer.
|
||||
OBJECT can be a buffer or string; nil defaults to current buffer.
|
||||
|
||||
Returns the number of successful matches."
|
||||
(let ((count (or n 1))
|
||||
(matches 0)
|
||||
(buf (or object (current-buffer))))
|
||||
(with-current-buffer buf
|
||||
(dotimes (_ count)
|
||||
(when-let ((match (tp-search-backward property value)))
|
||||
(funcall function match buf)
|
||||
(cl-incf matches))))
|
||||
matches))
|
||||
Returns the number of successful matches.
|
||||
|
||||
Example:
|
||||
;; Upcase all matched text
|
||||
(tp-backward-do #\\='upcase \\='marker nil my-string 3)"
|
||||
(tp--backward-do
|
||||
(lambda (match obj)
|
||||
(let* ((start (if (listp match) (car match) (prop-match-beginning match)))
|
||||
(end (if (listp match) (cadr match) (prop-match-end match)))
|
||||
(text (if (stringp obj)
|
||||
(substring obj start end)
|
||||
(buffer-substring start end)))
|
||||
(new-text (funcall function text)))
|
||||
(when (and new-text (not (equal new-text text)))
|
||||
(if (stringp obj)
|
||||
;; For strings, we need to replace in-place
|
||||
(progn
|
||||
(store-substring obj start new-text))
|
||||
;; For buffers, delete and insert
|
||||
(save-excursion
|
||||
(delete-region start end)
|
||||
(goto-char start)
|
||||
(insert new-text))))))
|
||||
property value object n))
|
||||
|
||||
(defun tp-search (start-or-string &optional end-or-property property-or-value value object)
|
||||
"Search for all text with PROPERTY in a buffer/string range or entire string.
|
||||
@ -1157,16 +1262,16 @@ Each element contains the start position, end position, and property value."
|
||||
(nreverse results)))
|
||||
(t (error "Invalid first argument: %S" start-or-string))))
|
||||
|
||||
(defun tp-search-do (function start-or-string &optional end-or-property property-or-value value object)
|
||||
"Execute FUNCTION on all matches of PROPERTY in a buffer/string range or entire string.
|
||||
(defun tp--search-do (function start-or-string &optional end-or-property property-or-value value object)
|
||||
"Internal: Execute FUNCTION on all matches of PROPERTY.
|
||||
|
||||
This function supports two calling conventions:
|
||||
|
||||
1. Buffer/string region:
|
||||
(tp-search-do FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
(tp--search-do FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
|
||||
2. Entire string:
|
||||
(tp-search-do FUNCTION STRING PROPERTY &optional VALUE)
|
||||
(tp--search-do FUNCTION STRING PROPERTY &optional VALUE)
|
||||
|
||||
FUNCTION receives two arguments: the prop-match (list of START END VALUE) and OBJECT.
|
||||
Returns the number of matches processed."
|
||||
@ -1187,6 +1292,48 @@ Returns the number of matches processed."
|
||||
(funcall function match obj))
|
||||
(length matches)))
|
||||
|
||||
(defun tp-search-map (function start-or-string &optional end-or-property property-or-value value object)
|
||||
"Apply FUNCTION to matched text for all matches of PROPERTY.
|
||||
|
||||
This function supports two calling conventions:
|
||||
|
||||
1. Buffer/string region:
|
||||
(tp-search-map FUNCTION START END PROPERTY &optional VALUE OBJECT)
|
||||
|
||||
2. Entire string:
|
||||
(tp-search-map FUNCTION STRING PROPERTY &optional VALUE)
|
||||
|
||||
FUNCTION receives the matched text as its only argument. The return value
|
||||
of FUNCTION replaces the matched text in the string or buffer.
|
||||
|
||||
Returns the number of matches processed.
|
||||
|
||||
Example:
|
||||
;; Upcase all matched text
|
||||
(tp-search-map #\\='upcase my-string \\='marker)"
|
||||
(let ((obj (cond
|
||||
((stringp start-or-string) start-or-string)
|
||||
((numberp start-or-string) (or object (current-buffer)))
|
||||
(t nil))))
|
||||
(tp--search-do
|
||||
(lambda (match obj)
|
||||
(let* ((start (car match))
|
||||
(end (cadr match))
|
||||
(text (if (stringp obj)
|
||||
(substring obj start end)
|
||||
(buffer-substring start end)))
|
||||
(new-text (funcall function text)))
|
||||
(when (and new-text (not (equal new-text text)))
|
||||
(if (stringp obj)
|
||||
;; For strings, replace in-place
|
||||
(store-substring obj start new-text)
|
||||
;; For buffers, delete and insert
|
||||
(save-excursion
|
||||
(delete-region start end)
|
||||
(goto-char start)
|
||||
(insert new-text))))))
|
||||
start-or-string end-or-property property-or-value value object)))
|
||||
|
||||
|
||||
;;; Query Functions
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user