* lisp/org.el (org-next-block): Ring the bell right before throwing a user error for when no block is found, if called interactively. * testing/lisp/test-org.el (test-org/next-block): Test that the bell rings if and only if called interactively. * etc/ORG-NEWS (~org-next-block~ rings the bell if no block is found): Announce the change and give an example use-case. --- etc/ORG-NEWS | 10 ++++++++++ lisp/org.el | 8 ++++++-- testing/lisp/test-org.el | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 5b5908629..e1ced84e5 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -676,6 +676,16 @@ will be defined as empty and not produce any metadata if their corresponding ~org-latex-with-author~, ~org-latex-with-title~, or ~org-latex-with-creator~ option is set to ~nil~. +*** ~org-next-block~ rings the bell if no block is found + +It is now possible to call the ~org-next-block~ function interactively +from a keyboard macro that runs until the bell rings. For example, if +the user customizes ~org-edit-src-content-indentation~, they can run a +keyboard macro that updates all source blocks in a file, without Emacs +looping forever. The change affects ~org-next-block~ and its callers, +including functions ~org-previous-block~, ~org-babel-next-src-block~, +and ~org-babel-previous-src-block~. + * Version 9.7 ** Important announcements and breaking changes diff --git a/lisp/org.el b/lisp/org.el index 21622523b..9d48cdd66 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -20170,7 +20170,9 @@ (defun org-next-block (arg &optional backward block-regexp) returns. Return point at beginning of the opening line of found block. -Throw an error if no block is found." + +Throw an error if no block is found. When called interactively, +ring the bell before throwing." (interactive "p") (let ((re (or block-regexp "^[ \t]*#\\+BEGIN")) (case-fold-search t) @@ -20190,13 +20192,15 @@ (defun org-next-block (arg &optional backward block-regexp) example-block export-block quote-block special-block src-block verse-block)) (<= (match-beginning 0) - (org-element-post-affiliated element))) + (org-element-post-affiliated element))) (setq last-element element) (cl-decf count)))) (if (= count 0) (prog1 (goto-char (org-element-post-affiliated last-element)) (save-match-data (org-fold-show-context))) (goto-char origin) + (when (called-interactively-p 'any) + (ding)) (user-error "No %s code blocks" (if backward "previous" "further"))))) (defun org-previous-block (arg &optional block-regexp) diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 36dea35b7..cf3e0b40b 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -5652,6 +5652,20 @@ (ert-deftest test-org/next-block () (should-error (org-test-with-temp-text "Paragraph" (org-next-block 1))) + ;; Ring the bell when no block is found. + (should-error + (org-test-with-temp-text "Paragraph" + (define-error 'ding "Ring my bell!") + (cl-letf (((symbol-function 'ding) + (lambda () (signal 'ding nil)))) + (funcall-interactively #'org-next-block 1))) + :type 'ding) + ;; Ring the bell only when called interactively. + (should-error + (org-test-with-temp-text "Paragraph" + (let ((ring-bell-function (lambda () (signal 'ding nil)))) + (org-next-block 1))) + :type 'user-error) ;; With an argument, skip many blocks at once. (should (org-test-with-temp-text -- 2.50.1