Subject: bug#13994: End of buffer error for forward-sexp

From: Andreas Röhler <[email-masked]>
Date: Mon, 29 Apr 2013 14:43:47 +0200

Am 18.03.2013 22:54, schrieb Aaron S. Hawley:
> I would like C-M-f (`forward-sexp') to signal an error when reaching
> the beginning or end of a buffer.  When running a keyboard macro that
> contains this command, it should reach an error condition of "End of
> buffer".  If wish to run C-0 C-x e on a file full of S-expressions and
> have the macro end when an error is reached.  Currently, my macro puts
> Emacs in an infinite loop.
>
> I've attached a patch that adds these error conditions.  I also need
> to correct my email address in the ChangeLog.
>
> What I wrote isn't every strict.  I only catch the condition when the
> function is started from beginning or end of buffer.  If the user
> gives an argument for more S-expressions than there are between the
> beginning of the buffer there is no error triggered.  This was a
> compromise but also a simpler patch to contribute.  I've added the
> unit tests I wrote to implement.   I hope they're helpful.
>
> I'm not sure why this was never the case in the first place, nor do I
> know what the consequence of fixing it is.  I'm not sure if the lack
> of an error is necessary in the 112 libraries where this function is
> used in Emacs (and probably many times more in libraries outside of
> Emacs!).  I'm hoping that after the release Emacs 24.3, now is a good
> time to install this in trunk and find out.
>
> Thanks,
> /a
>
> === modified file 'lisp/ChangeLog'
> --- lisp/ChangeLog	2013-03-18 19:44:15 +0000
> +++ lisp/ChangeLog	2013-03-18 20:37:01 +0000
> @@ -1,3 +1,5 @@
> +2013-03-18  Aaron S. Hawley  <[email-masked]>
> +
> +        * emacs-lisp/lisp.el (forward-sexp): Signal an error when end of
> +        buffer or beginning of buffer reached.
> +
> @@ -1974,7 +1979,7 @@
>   	(js--multi-line-declaration-indentation): New function.
>   	(js--proper-indentation): Use it.
>
> -2013-01-11  Aaron S. Hawley  <[email-masked]>
> +2013-01-11  Aaron S. Hawley  <[email-masked]>
>
>   	* calc/calc.el (calc-highlight-selections-with-faces)
>   	 (calc-dispatch):
>
> === modified file 'lisp/emacs-lisp/lisp.el'
> --- lisp/emacs-lisp/lisp.el	2013-01-01 09:11:05 +0000
> +++ lisp/emacs-lisp/lisp.el	2013-03-18 19:38:50 +0000
> @@ -58,6 +58,10 @@
>     (or arg (setq arg 1))
>     (if forward-sexp-function
>         (funcall forward-sexp-function arg)
> +    (when (and (> arg 0) (eobp))
> +      (signal 'end-of-buffer nil))
> +    (when (and (< arg 0) (bobp))
> +      (signal 'beginning-of-buffer nil))
>       (goto-char (or (scan-sexps (point) arg) (buffer-end arg)))
>       (if (< arg 0) (backward-prefix-chars))))
>
>
> === added file 'test/automated/sexp-tests.el'
> --- test/automated/sexp-tests.el	1970-01-01 00:00:00 +0000
> +++ test/automated/sexp-tests.el	2013-03-18 21:51:52 +0000
> @@ -0,0 +1,98 @@
> +;;; sexp-tests.el --- Test S-expression support in Emacs
> +
> +;; Copyright (C) 2013  Aaron S. Hawley
> +
> +;; Author: Aaron S. Hawley <[email-masked]>
> +;; Keywords: internal
> +
> +;; This program is free software; you can redistribute it and/or modify
> +;; it under the terms of the GNU General Public License as published by
> +;; the Free Software Foundation, either version 3 of the License, or
> +;; (at your option) any later version.
> +
> +;; This program is distributed in the hope that it will be useful,
> +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +;; GNU General Public License for more details.
> +
> +;; You should have received a copy of the GNU General Public License
> +;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +;;; Commentary:
> +
> +;; Testing of `forward-sexp'.
> +
> +;;; Code:
> +
> +(require 'ert)
> +
> +(ert-deftest sexp-forward-1 ()
> +  "Test basics of \\[forward-sexp]."
> +  (with-temp-buffer
> +    (insert "()")
> +    (goto-char (point-min))
> +    (should (null
> +             (forward-sexp 1)))))
> +
> +(ert-deftest sexp-backward-1 ()
> +  "Test basics of \\[backward-sexp]."
> +  (with-temp-buffer
> +    (insert "()")
> +    (should (null
> +             (forward-sexp -1)))))
> +
> +(ert-deftest sexp-forward-1-error-eobp ()
> +  "Test error when \\[forward-sexp] at `eobp'."
> +  (with-temp-buffer
> +    (insert "()")
> +    (should-error
> +     (forward-sexp 1))))
> +
> +(ert-deftest sexp-backward-1-error-eobp ()
> +  "Test error when \\[backward-sexp] at `bobp'."
> +  (with-temp-buffer
> +    (insert "()")
> +    (goto-char (point-min))
> +    (should-error
> +     (forward-sexp -1))))
> +
> +(ert-deftest sexp-forward-2-eobp-no-error ()
> +  "Test lack of error when \\[forward-sexp] beyond `eobp'."
> +  (with-temp-buffer
> +    (insert "()")
> +    (goto-char (point-min))
> +    (should (null
> +     (forward-sexp 2)))
> +    (should (eobp))))
> +
> +(ert-deftest sexp-backward-2-bobp-no-error ()
> +  "Test lack of error when \\[backward-sexp] beyond `bobp'."
> +  (with-temp-buffer
> +    (insert "()")
> +    (should (null
> +     (forward-sexp -2)))
> +    (should (bobp))))
> +
> +(ert-deftest sexp-forward-2-eobp-subsequent-error ()
> +  "Test error when \\[forward-sexp] when started from `eobp'."
> +  (with-temp-buffer
> +    (insert "()")
> +    (goto-char (point-min))
> +    (should (null
> +     (forward-sexp 2)))
> +    (should (eobp))
> +    (should-error
> +     (forward-sexp 1))))
> +
> +(ert-deftest sexp-backward-2-bobp-subsequent-error ()
> +  "Test error when \\[backward-sexp] when started from `bobp'."
> +  (with-temp-buffer
> +    (insert "()")
> +    (should (null
> +     (forward-sexp -2)))
> +    (should (bobp))
> +    (should-error
> +     (forward-sexp -1))))
> +
> +(provide 'sexp-tests)
> +;;; sexp-tests.el ends here
>

IIRC that was the default at XEmacs. Very annoying, as beginning or EOB are hitted quit often. Than the debugger starts.

For now, what about writing

(if (forward-sexp)
     DO-SOMEthing
   (message "%s" "nil"))

Best regards,

Andreas