branch: externals/compat commit 757ea1d68f66115236d1faf9768682a9db957c48 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
Fix and test replace-regexp/string-in-region --- NEWS.org | 6 ++--- compat-28.el | 44 ++++++++++++++++++---------------- compat-tests.el | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 24 deletions(-) diff --git a/NEWS.org b/NEWS.org index 2b3a605420..f3717a7670 100644 --- a/NEWS.org +++ b/NEWS.org @@ -3,10 +3,8 @@ * Development - Add multiple new tests for existing APIs. -- Fix the ~setq-local~ compatibility macro. -- Fix the ~proper-list-p~ compatibility function. -- Fix the ~prop-match-p~ compatibility function. -- Fix the ~file-name-concat~ compatibility function. +- Fix bugs in compatibility functions: ~setq-local~, ~proper-list-p, prop-match-p, + ~file-name-concat~, ~replace-regexp-in-region~, ~replace-string-in-region~. - Add new Emacs 29 APIs. Most of these are still untested and may change. If you intend to use an API please be extra careful and if possible contribute test cases. All untested functions are marked as ~<UNTESTED>~ in the Compat diff --git a/compat-28.el b/compat-28.el index 33d52f966d..419c19de91 100644 --- a/compat-28.el +++ b/compat-28.el @@ -311,7 +311,7 @@ Point in BUFFER will be placed after the inserted text." (with-current-buffer buffer (insert-buffer-substring current start end)))) -(compat-defun replace-string-in-region (string replacement &optional start end) ;; <UNTESTED> +(compat-defun replace-string-in-region (string replacement &optional start end) ;; <OK> "Replace STRING with REPLACEMENT in the region from START to END. The number of replaced occurrences are returned, or nil if STRING doesn't exist in the region. @@ -328,17 +328,19 @@ Comparisons and replacements are done with fixed case." (error "End after end of buffer")) (setq end (point-max))) (save-excursion - (let ((matches 0) - (case-fold-search nil)) - (goto-char start) - (while (search-forward string end t) - (delete-region (match-beginning 0) (match-end 0)) - (insert replacement) - (setq matches (1+ matches))) - (and (not (zerop matches)) - matches)))) - -(compat-defun replace-regexp-in-region (regexp replacement &optional start end) ;; <UNTESTED> + (goto-char start) + (save-restriction + (narrow-to-region start end) + (let ((matches 0) + (case-fold-search nil)) + (while (search-forward string nil t) + (delete-region (match-beginning 0) (match-end 0)) + (insert replacement) + (setq matches (1+ matches))) + (and (not (zerop matches)) + matches))))) + +(compat-defun replace-regexp-in-region (regexp replacement &optional start end) ;; <OK> "Replace REGEXP with REPLACEMENT in the region from START to END. The number of replaced occurrences are returned, or nil if REGEXP doesn't exist in the region. @@ -363,14 +365,16 @@ REPLACEMENT can use the following special elements: (error "End after end of buffer")) (setq end (point-max))) (save-excursion - (let ((matches 0) - (case-fold-search nil)) - (goto-char start) - (while (re-search-forward regexp end t) - (replace-match replacement t) - (setq matches (1+ matches))) - (and (not (zerop matches)) - matches)))) + (goto-char start) + (save-restriction + (narrow-to-region start end) + (let ((matches 0) + (case-fold-search nil)) + (while (re-search-forward regexp nil t) + (replace-match replacement t) + (setq matches (1+ matches))) + (and (not (zerop matches)) + matches))))) (compat-defun buffer-local-boundp (symbol buffer) ;; <OK> "Return non-nil if SYMBOL is bound in BUFFER. diff --git a/compat-tests.el b/compat-tests.el index 1866b33be4..00236a0770 100644 --- a/compat-tests.el +++ b/compat-tests.el @@ -802,6 +802,80 @@ (should-equal '[1 2 3] (compat-call sort '[1 2 3] #'<)) (should-equal '[1 2 3] (compat-call sort '[3 2 1] #'<))) +(ert-deftest replace-string-in-region () + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-string-in-region "foo" "new" (point-min) (point-max)) + 2)) + (should (equal (buffer-string) "new bar zot newbar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-string-in-region "foo" "new" (point-min) 14) + 1)) + (should (equal (buffer-string) "new bar zot foobar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should-error (replace-string-in-region "foo" "new" (point-min) 30))) + + (with-temp-buffer + (insert "Foo bar zot foobar") + (should (= (replace-string-in-region "Foo" "new" (point-min)) + 1)) + (should (equal (buffer-string) "new bar zot foobar"))) + + (with-temp-buffer + (insert "foo bar baz") + (should (= (replace-string-in-region "ba" "quux corge grault" (point-min)) + 2)) + (should (equal (buffer-string) + "foo quux corge graultr quux corge graultz"))) + + (with-temp-buffer + (insert "foo bar bar") + (should (= (replace-string-in-region " bar" "" (point-min) 8) + 1)) + (should (equal (buffer-string) + "foo bar")))) + +(ert-deftest replace-regexp-in-region () + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-regexp-in-region "fo+" "new" (point-min) (point-max)) + 2)) + (should (equal (buffer-string) "new bar zot newbar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-regexp-in-region "fo+" "new" (point-min) 14) + 1)) + (should (equal (buffer-string) "new bar zot foobar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should-error (replace-regexp-in-region "fo+" "new" (point-min) 30))) + + (with-temp-buffer + (insert "Foo bar zot foobar") + (should (= (replace-regexp-in-region "Fo+" "new" (point-min)) + 1)) + (should (equal (buffer-string) "new bar zot foobar"))) + + (with-temp-buffer + (insert "foo bar baz") + (should (= (replace-regexp-in-region "ba." "quux corge grault" (point-min)) + 2)) + (should (equal (buffer-string) + "foo quux corge grault quux corge grault"))) + + (with-temp-buffer + (insert "foo bar bar") + (should (= (replace-regexp-in-region " bar" "" (point-min) 8) + 1)) + (should (equal (buffer-string) + "foo bar")))) + (ert-deftest string-split () (should-equal '("a" "b" "c") (split-string "a b c")) (should-equal '("a" "b" "c") (string-split "a b c")))