Update tp-forward-do/tp-backward-do docs and tests for "last match only" behavior

Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-16 04:01:57 +00:00
parent ed8baf3970
commit 47b6505d51
4 changed files with 96 additions and 81 deletions

View File

@ -885,11 +885,10 @@ Search forward/backward N times for text with PROPERTY.
(tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT POINT N) (tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT POINT N)
``` ```
Search forward/backward N times for text with PROPERTY and apply FUNCTION to matched text. Search forward/backward N times for text with PROPERTY and apply FUNCTION **only to the last match**.
- **FUNCTION** receives the matched text as its only argument. The return value - **FUNCTION** receives the matched text as its first argument. Optionally, FUNCTION can accept two additional arguments: START and END, representing the start and end positions of the match. The return value of FUNCTION replaces the matched text in the string or buffer.
of FUNCTION replaces the matched text in the string or buffer. - **N** is the number of searches, defaulting to 1. The function searches N times but only applies FUNCTION to the last (Nth) match found.
- **N** is the number of searches, defaulting to 1.
- **OBJECT** can be a buffer or string; nil defaults to current buffer. - **OBJECT** can be a buffer or string; nil defaults to current buffer.
- **POINT** is the starting position for search; for buffers nil means current point, - **POINT** is the starting position for search; for buffers nil means current point,
for strings nil means 0 (forward) or end of string (backward). for strings nil means 0 (forward) or end of string (backward).
@ -898,7 +897,7 @@ Search forward/backward N times for text with PROPERTY and apply FUNCTION to mat
**Examples:** **Examples:**
```elisp ```elisp
;; Upcase matched text in buffer (starting from current point) ;; Upcase only the last (2nd) match in buffer
(with-temp-buffer (with-temp-buffer
(insert "hello world test") (insert "hello world test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
@ -906,17 +905,17 @@ Search forward/backward N times for text with PROPERTY and apply FUNCTION to mat
(goto-char 1) (goto-char 1)
(tp-forward-do #'upcase 'marker nil nil nil 2) (tp-forward-do #'upcase 'marker nil nil nil 2)
(buffer-string)) (buffer-string))
;; => "HELLO world TEST" ;; => "hello world TEST" ; Only the 2nd match is upcased
;; Upcase matched text in string (starting from position 0) ;; Upcase only the last (2nd) match in string
(let ((my-string (copy-sequence "hello world hello"))) (let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string) (tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string) (tp-set 12 17 '(marker t) my-string)
(tp-forward-do #'upcase 'marker nil my-string nil 2) (tp-forward-do #'upcase 'marker nil my-string nil 2)
my-string) my-string)
;; => "HELLO world HELLO" ;; => "hello world HELLO" ; Only the 2nd match is upcased
;; Start search from specific position ;; Start search from specific position (only 1 match found and transformed)
(let ((my-string (copy-sequence "hello world hello"))) (let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string) (tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string) (tp-set 12 17 '(marker t) my-string)
@ -924,17 +923,18 @@ Search forward/backward N times for text with PROPERTY and apply FUNCTION to mat
my-string) my-string)
;; => "hello world HELLO" ; Only matches from position 6 onward ;; => "hello world HELLO" ; Only matches from position 6 onward
;; Custom transformation ;; Using function with start and end parameters
(with-temp-buffer (with-temp-buffer
(insert "hello world test") (insert "hello world test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t))
(goto-char 1) (goto-char 1)
(tp-forward-do (tp-forward-do
(lambda (text) (lambda (text start end)
(concat "[" text "]")) (format "[%d-%d]%s" start end text))
'marker nil nil nil 1) 'marker nil nil nil 2)
(buffer-string)) (buffer-string))
;; => "[hello] world test" ;; => "hello world [13-17]test" ; Only the last match is transformed
``` ```
--- ---

View File

@ -884,10 +884,10 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
(tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT POINT N) (tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT POINT N)
``` ```
向前/向后搜索 N 次具有 PROPERTY 的文本,并对匹配的文本应用 FUNCTION 向前/向后搜索 N 次具有 PROPERTY 的文本,**仅对最后一次匹配应用 FUNCTION**
- **FUNCTION** 接收匹配到的文本作为唯一参数。FUNCTION 的返回值将替换字符串或缓冲区中的匹配文本。 - **FUNCTION** 接收匹配到的文本作为第一个参数。可选地FUNCTION 可以接受两个额外的参数START 和 END表示匹配的起始和结束位置。FUNCTION 的返回值将替换字符串或缓冲区中的匹配文本。
- **N** 是搜索次数,默认为 1。 - **N** 是搜索次数,默认为 1。该函数会搜索 N 次,但仅对找到的最后(第 N 次)匹配应用 FUNCTION。
- **OBJECT** 可以是缓冲区或字符串nil 默认为当前缓冲区。 - **OBJECT** 可以是缓冲区或字符串nil 默认为当前缓冲区。
- **POINT** 是搜索的起始位置;对于缓冲区 nil 表示当前位置,对于字符串 nil 表示 0向前或字符串末尾向后 - **POINT** 是搜索的起始位置;对于缓冲区 nil 表示当前位置,对于字符串 nil 表示 0向前或字符串末尾向后
- 返回成功匹配的数量。 - 返回成功匹配的数量。
@ -895,7 +895,7 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
**示例:** **示例:**
```elisp ```elisp
;; 将缓冲区中匹配的文本转为大写(从当前位置开始) ;; 仅将最后一次(第 2 次)匹配的文本转为大写
(with-temp-buffer (with-temp-buffer
(insert "hello world test") (insert "hello world test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
@ -903,17 +903,17 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
(goto-char 1) (goto-char 1)
(tp-forward-do #'upcase 'marker nil nil nil 2) (tp-forward-do #'upcase 'marker nil nil nil 2)
(buffer-string)) (buffer-string))
;; => "HELLO world TEST" ;; => "hello world TEST" ; 仅第 2 次匹配被转为大写
;; 将字符串中匹配的文本转为大写(从位置 0 开始) ;; 仅将最后一次(第 2 次)匹配的文本转为大写
(let ((my-string (copy-sequence "hello world hello"))) (let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string) (tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string) (tp-set 12 17 '(marker t) my-string)
(tp-forward-do #'upcase 'marker nil my-string nil 2) (tp-forward-do #'upcase 'marker nil my-string nil 2)
my-string) my-string)
;; => "HELLO world HELLO" ;; => "hello world HELLO" ; 仅第 2 次匹配被转为大写
;; 从特定位置开始搜索 ;; 从特定位置开始搜索(仅找到 1 次匹配并转换)
(let ((my-string (copy-sequence "hello world hello"))) (let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string) (tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string) (tp-set 12 17 '(marker t) my-string)
@ -921,17 +921,18 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
my-string) my-string)
;; => "hello world HELLO" ; 只处理位置 6 之后的匹配 ;; => "hello world HELLO" ; 只处理位置 6 之后的匹配
;; 自定义转换 ;; 使用带有 start 和 end 参数的函数
(with-temp-buffer (with-temp-buffer
(insert "hello world test") (insert "hello world test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t))
(goto-char 1) (goto-char 1)
(tp-forward-do (tp-forward-do
(lambda (text) (lambda (text start end)
(concat "[" text "]")) (format "[%d-%d]%s" start end text))
'marker nil nil nil 1) 'marker nil nil nil 2)
(buffer-string)) (buffer-string))
;; => "[hello] world test" ;; => "hello world [13-17]test" ; 仅最后一次匹配被转换
``` ```
--- ---

View File

@ -643,22 +643,23 @@
(should (equal (cadr matches) '(0 5 t)))))) (should (equal (cadr matches) '(0 5 t))))))
(ert-deftest tp-test-forward-do () (ert-deftest tp-test-forward-do ()
"Test tp-forward-do applies function to matched text." "Test tp-forward-do applies function only to the last match."
(tp-test-with-temp-buffer (tp-test-with-temp-buffer
(insert "hello World test") (insert "hello World test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t)) (tp-set 13 17 '(marker t))
(goto-char 1) (goto-char 1)
(skip-unless (fboundp 'text-property-search-forward)) (skip-unless (fboundp 'text-property-search-forward))
;; Test that function receives text and can transform it ;; Test that function is applied only to the last (2nd) match
(let ((count (tp-forward-do #'upcase 'marker nil nil nil 2))) (let ((count (tp-forward-do #'upcase 'marker nil nil nil 2)))
(should (= count 2)) (should (= count 2))
;; Check that text was upcased ;; First match should NOT be upcased
(should (equal (buffer-substring 1 6) "HELLO")) (should (equal (buffer-substring 1 6) "hello"))
;; Only the last (2nd) match should be upcased
(should (equal (buffer-substring 13 17) "TEST"))))) (should (equal (buffer-substring 13 17) "TEST")))))
(ert-deftest tp-test--forward-do () (ert-deftest tp-test--forward-do ()
"Test tp--forward-do applies function to matches (internal API)." "Test tp--forward-do applies function only to the last match (internal API)."
(tp-test-with-temp-buffer (tp-test-with-temp-buffer
(insert "Hello World Test") (insert "Hello World Test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
@ -670,25 +671,28 @@
(lambda (match obj) (lambda (match obj)
(push (prop-match-beginning match) result)) (push (prop-match-beginning match) result))
'marker nil nil nil 2) 'marker nil nil nil 2)
(should (= (length result) 2))))) ;; Only the last match should be processed
(should (= (length result) 1))
(should (= (car result) 13)))))
(ert-deftest tp-test-backward-do () (ert-deftest tp-test-backward-do ()
"Test tp-backward-do applies function to matched text." "Test tp-backward-do applies function only to the last match."
(tp-test-with-temp-buffer (tp-test-with-temp-buffer
(insert "hello World test") (insert "hello World test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t)) (tp-set 13 17 '(marker t))
(goto-char 18) (goto-char 18)
(skip-unless (fboundp 'text-property-search-backward)) (skip-unless (fboundp 'text-property-search-backward))
;; Test that function receives text and can transform it ;; Test that function is applied only to the last (2nd) match
(let ((count (tp-backward-do #'upcase 'marker nil nil nil 2))) (let ((count (tp-backward-do #'upcase 'marker nil nil nil 2)))
(should (= count 2)) (should (= count 2))
;; Check that text was upcased ;; Only the last (2nd) match should be upcased
(should (equal (buffer-substring 1 6) "HELLO")) (should (equal (buffer-substring 1 6) "HELLO"))
(should (equal (buffer-substring 13 17) "TEST"))))) ;; First match (searched backward) should NOT be upcased
(should (equal (buffer-substring 13 17) "test")))))
(ert-deftest tp-test--backward-do () (ert-deftest tp-test--backward-do ()
"Test tp--backward-do applies function to matches (internal API)." "Test tp--backward-do applies function only to the last match (internal API)."
(tp-test-with-temp-buffer (tp-test-with-temp-buffer
(insert "Hello World Test") (insert "Hello World Test")
(tp-set 1 6 '(marker t)) (tp-set 1 6 '(marker t))
@ -700,29 +704,33 @@
(lambda (match obj) (lambda (match obj)
(push (prop-match-beginning match) result)) (push (prop-match-beginning match) result))
'marker nil nil nil 2) 'marker nil nil nil 2)
(should (= (length result) 2))))) ;; Only the last match should be processed
(should (= (length result) 1))
(should (= (car result) 1)))))
(ert-deftest tp-test-forward-do-on-string () (ert-deftest tp-test-forward-do-on-string ()
"Test tp-forward-do works on string objects." "Test tp-forward-do applies only to the last match on string objects."
(let ((str (copy-sequence "hello World hello"))) (let ((str (copy-sequence "hello World hello")))
(tp-set 0 5 '(marker t) str) (tp-set 0 5 '(marker t) str)
(tp-set 12 17 '(marker t) str) (tp-set 12 17 '(marker t) str)
(let ((count (tp-forward-do #'upcase 'marker nil str nil 2))) (let ((count (tp-forward-do #'upcase 'marker nil str nil 2)))
(should (= count 2)) (should (= count 2))
;; Check that text was upcased ;; First match should NOT be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "hello"))
;; Only the last (2nd) match should be upcased
(should (equal (substring str 12 17) "HELLO"))))) (should (equal (substring str 12 17) "HELLO")))))
(ert-deftest tp-test-backward-do-on-string () (ert-deftest tp-test-backward-do-on-string ()
"Test tp-backward-do works on string objects." "Test tp-backward-do applies only to the last match on string objects."
(let ((str (copy-sequence "hello World hello"))) (let ((str (copy-sequence "hello World hello")))
(tp-set 0 5 '(marker t) str) (tp-set 0 5 '(marker t) str)
(tp-set 12 17 '(marker t) str) (tp-set 12 17 '(marker t) str)
(let ((count (tp-backward-do #'upcase 'marker nil str nil 2))) (let ((count (tp-backward-do #'upcase 'marker nil str nil 2)))
(should (= count 2)) (should (= count 2))
;; Check that text was upcased ;; Only the last (2nd) match should be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "HELLO"))
(should (equal (substring str 12 17) "HELLO"))))) ;; First match (searched backward) should NOT be upcased
(should (equal (substring str 12 17) "hello")))))
(ert-deftest tp-test-forward-do-with-point () (ert-deftest tp-test-forward-do-with-point ()
"Test tp-forward-do with point parameter." "Test tp-forward-do with point parameter."
@ -751,7 +759,7 @@
(should (equal (substring str 12 17) "hello"))))) (should (equal (substring str 12 17) "hello")))))
(ert-deftest tp-test-forward-do-with-start-end () (ert-deftest tp-test-forward-do-with-start-end ()
"Test tp-forward-do passes optional start and end to function." "Test tp-forward-do passes optional start and end to function for last match only."
(let ((str (copy-sequence "hello World hello")) (let ((str (copy-sequence "hello World hello"))
(starts nil) (starts nil)
(ends nil)) (ends nil))
@ -764,15 +772,15 @@
(upcase txt)) (upcase txt))
'marker nil str nil 2))) 'marker nil str nil 2)))
(should (= count 2)) (should (= count 2))
;; Check positions were passed correctly ;; Check only the last match positions were passed
(should (equal (sort starts #'<) '(0 12))) (should (equal starts '(12)))
(should (equal (sort ends #'<) '(5 17))) (should (equal ends '(17)))
;; Check text was upcased ;; Only the last match should be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "hello"))
(should (equal (substring str 12 17) "HELLO"))))) (should (equal (substring str 12 17) "HELLO")))))
(ert-deftest tp-test-forward-do-with-start-only () (ert-deftest tp-test-forward-do-with-start-only ()
"Test tp-forward-do passes start when function accepts 2 args." "Test tp-forward-do passes start to function for last match only when function accepts 2 args."
(let ((str (copy-sequence "hello World hello")) (let ((str (copy-sequence "hello World hello"))
(starts nil)) (starts nil))
(tp-set 0 5 '(marker t) str) (tp-set 0 5 '(marker t) str)
@ -783,24 +791,25 @@
(upcase txt)) (upcase txt))
'marker nil str nil 2))) 'marker nil str nil 2)))
(should (= count 2)) (should (= count 2))
;; Check start positions were passed correctly ;; Check only the last match start position was passed
(should (equal (sort starts #'<) '(0 12))) (should (equal starts '(12)))
;; Check text was upcased ;; Only the last match should be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "hello"))
(should (equal (substring str 12 17) "HELLO"))))) (should (equal (substring str 12 17) "HELLO")))))
(ert-deftest tp-test-forward-do-backward-compat () (ert-deftest tp-test-forward-do-backward-compat ()
"Test tp-forward-do works with single-argument functions (backward compat)." "Test tp-forward-do applies only to last match with single-argument functions."
(let ((str (copy-sequence "hello World hello"))) (let ((str (copy-sequence "hello World hello")))
(tp-set 0 5 '(marker t) str) (tp-set 0 5 '(marker t) str)
(tp-set 12 17 '(marker t) str) (tp-set 12 17 '(marker t) str)
;; Use #'upcase which only takes one argument ;; Use #'upcase which only takes one argument
(tp-forward-do #'upcase 'marker nil str nil 2) (tp-forward-do #'upcase 'marker nil str nil 2)
(should (equal (substring str 0 5) "HELLO")) ;; Only the last match should be upcased
(should (equal (substring str 0 5) "hello"))
(should (equal (substring str 12 17) "HELLO")))) (should (equal (substring str 12 17) "HELLO"))))
(ert-deftest tp-test-backward-do-with-start-end () (ert-deftest tp-test-backward-do-with-start-end ()
"Test tp-backward-do passes optional start and end to function." "Test tp-backward-do passes optional start and end to function for last match only."
(let ((str (copy-sequence "hello World hello")) (let ((str (copy-sequence "hello World hello"))
(starts nil) (starts nil)
(ends nil)) (ends nil))
@ -813,15 +822,15 @@
(upcase txt)) (upcase txt))
'marker nil str nil 2))) 'marker nil str nil 2)))
(should (= count 2)) (should (= count 2))
;; Check positions were passed correctly ;; Check only the last match positions were passed
(should (equal (sort starts #'<) '(0 12))) (should (equal starts '(0)))
(should (equal (sort ends #'<) '(5 17))) (should (equal ends '(5)))
;; Check text was upcased ;; Only the last match should be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "HELLO"))
(should (equal (substring str 12 17) "HELLO"))))) (should (equal (substring str 12 17) "hello")))))
(ert-deftest tp-test-backward-do-with-start-only () (ert-deftest tp-test-backward-do-with-start-only ()
"Test tp-backward-do passes start when function accepts 2 args." "Test tp-backward-do passes start to function for last match only when function accepts 2 args."
(let ((str (copy-sequence "hello World hello")) (let ((str (copy-sequence "hello World hello"))
(starts nil)) (starts nil))
(tp-set 0 5 '(marker t) str) (tp-set 0 5 '(marker t) str)
@ -832,21 +841,22 @@
(upcase txt)) (upcase txt))
'marker nil str nil 2))) 'marker nil str nil 2)))
(should (= count 2)) (should (= count 2))
;; Check start positions were passed correctly ;; Check only the last match start position was passed
(should (equal (sort starts #'<) '(0 12))) (should (equal starts '(0)))
;; Check text was upcased ;; Only the last match should be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "HELLO"))
(should (equal (substring str 12 17) "HELLO"))))) (should (equal (substring str 12 17) "hello")))))
(ert-deftest tp-test-backward-do-backward-compat () (ert-deftest tp-test-backward-do-backward-compat ()
"Test tp-backward-do works with single-argument functions (backward compat)." "Test tp-backward-do applies only to last match with single-argument functions."
(let ((str (copy-sequence "hello World hello"))) (let ((str (copy-sequence "hello World hello")))
(tp-set 0 5 '(marker t) str) (tp-set 0 5 '(marker t) str)
(tp-set 12 17 '(marker t) str) (tp-set 12 17 '(marker t) str)
;; Use #'upcase which only takes one argument ;; Use #'upcase which only takes one argument
(tp-backward-do #'upcase 'marker nil str nil 2) (tp-backward-do #'upcase 'marker nil str nil 2)
;; Only the last match should be upcased
(should (equal (substring str 0 5) "HELLO")) (should (equal (substring str 0 5) "HELLO"))
(should (equal (substring str 12 17) "HELLO")))) (should (equal (substring str 12 17) "hello"))))
(ert-deftest tp-test-search-on-string () (ert-deftest tp-test-search-on-string ()
"Test tp-search finds all matching properties in a string." "Test tp-search finds all matching properties in a string."

24
tp.el
View File

@ -1023,7 +1023,7 @@ Returns the number of successful matches."
matches))))) matches)))))
(defun tp-forward-do (function property &optional value object point n) (defun tp-forward-do (function property &optional value object point n)
"Search forward N times for text with PROPERTY and apply FUNCTION to each match. "Search forward N times for text with PROPERTY and apply FUNCTION only to the last match.
FUNCTION receives the matched text as its first argument. Optionally, FUNCTION receives the matched text as its first argument. Optionally,
FUNCTION can accept two additional arguments: START and END, representing FUNCTION can accept two additional arguments: START and END, representing
@ -1032,7 +1032,8 @@ it receives (TEXT START). If it accepts 3 or more arguments, it receives
(TEXT START END). The return value of FUNCTION replaces the matched text (TEXT START END). The return value of FUNCTION replaces the matched text
in the string or buffer. in the string or buffer.
N is the number of searches, defaulting to 1. N is the number of searches, defaulting to 1. The function searches N times
but only applies FUNCTION to the last (Nth) match found.
VALUE is the optional value to match. VALUE is the optional value to match.
OBJECT can be a buffer or string; nil defaults to current buffer. OBJECT can be a buffer or string; nil defaults to current buffer.
POINT is the starting position for search; for buffers nil means current point, POINT is the starting position for search; for buffers nil means current point,
@ -1046,14 +1047,15 @@ If the replacement is shorter, only that portion will be replaced.
If the replacement is longer, it will be truncated. If the replacement is longer, it will be truncated.
Example: Example:
;; Upcase all matched text ;; Upcase only the last (2nd) match
(setq my-string (copy-sequence \"hello world hello\")) (setq my-string (copy-sequence \"hello world hello\"))
(tp-set 0 5 \\='(marker t) my-string) (tp-set 0 5 \\='(marker t) my-string)
(tp-set 12 17 \\='(marker t) my-string) (tp-set 12 17 \\='(marker t) my-string)
(tp-forward-do #\\='upcase \\='marker nil my-string nil 3) (tp-forward-do #\\='upcase \\='marker nil my-string nil 2)
;; => \"hello world HELLO\" - only the 2nd match is upcased
;; Use start and end positions ;; Use start and end positions
(tp-forward-do (lambda (txt start end) (format \"[%d-%d]%s\" start end txt)) (tp-forward-do (lambda (txt start end) (format \"[%d-%d]%s\" start end txt))
\\='marker nil my-string nil 3)" \\='marker nil my-string nil 2)"
(let ((arity (func-arity function))) (let ((arity (func-arity function)))
(tp--forward-do (tp--forward-do
(lambda (match obj) (lambda (match obj)
@ -1137,7 +1139,7 @@ Returns the number of successful matches."
matches))))) matches)))))
(defun tp-backward-do (function property &optional value object point n) (defun tp-backward-do (function property &optional value object point n)
"Search backward N times for text with PROPERTY and apply FUNCTION to each match. "Search backward N times for text with PROPERTY and apply FUNCTION only to the last match.
FUNCTION receives the matched text as its first argument. Optionally, FUNCTION receives the matched text as its first argument. Optionally,
FUNCTION can accept two additional arguments: START and END, representing FUNCTION can accept two additional arguments: START and END, representing
@ -1146,7 +1148,8 @@ it receives (TEXT START). If it accepts 3 or more arguments, it receives
(TEXT START END). The return value of FUNCTION replaces the matched text (TEXT START END). The return value of FUNCTION replaces the matched text
in the string or buffer. in the string or buffer.
N is the number of searches, defaulting to 1. N is the number of searches, defaulting to 1. The function searches N times
but only applies FUNCTION to the last (Nth) match found.
VALUE is the optional value to match. VALUE is the optional value to match.
OBJECT can be a buffer or string; nil defaults to current buffer. OBJECT can be a buffer or string; nil defaults to current buffer.
POINT is the starting position for search; for buffers nil means current point, POINT is the starting position for search; for buffers nil means current point,
@ -1160,14 +1163,15 @@ If the replacement is shorter, only that portion will be replaced.
If the replacement is longer, it will be truncated. If the replacement is longer, it will be truncated.
Example: Example:
;; Upcase all matched text ;; Upcase only the last (2nd) match
(setq my-string (copy-sequence \"hello world hello\")) (setq my-string (copy-sequence \"hello world hello\"))
(tp-set 0 5 \\='(marker t) my-string) (tp-set 0 5 \\='(marker t) my-string)
(tp-set 12 17 \\='(marker t) my-string) (tp-set 12 17 \\='(marker t) my-string)
(tp-backward-do #\\='upcase \\='marker nil my-string nil 3) (tp-backward-do #\\='upcase \\='marker nil my-string nil 2)
;; => \"hello world HELLO\" - only the 2nd (last) match is upcased
;; Use start and end positions ;; Use start and end positions
(tp-backward-do (lambda (txt start end) (format \"[%d-%d]%s\" start end txt)) (tp-backward-do (lambda (txt start end) (format \"[%d-%d]%s\" start end txt))
\\='marker nil my-string nil 3)" \\='marker nil my-string nil 2)"
(let ((arity (func-arity function))) (let ((arity (func-arity function)))
(tp--backward-do (tp--backward-do
(lambda (match obj) (lambda (match obj)