changeset 104716:0e9469d1d59c

(fortran-start-prog-re): New constant, extracted from fortran-current-defun. (fortran-beginning-of-subprogram): Be more precise about finding the start, to avoid an infinite loop in end-of-defun. (Bug#4259) (fortran-end-of-subprogram): Simplify. (fortran-current-defun): Use fortran-start-prog-re.
author Glenn Morris <rgm@gnu.org>
date Sun, 30 Aug 2009 01:38:09 +0000
parents b4c0b272ac7a
children e6cb0ea1becf
files lisp/ChangeLog lisp/progmodes/fortran.el
diffstat 2 files changed, 55 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Sat Aug 29 22:27:19 2009 +0000
+++ b/lisp/ChangeLog	Sun Aug 30 01:38:09 2009 +0000
@@ -1,3 +1,12 @@
+2009-08-30  Glenn Morris  <rgm@gnu.org>
+
+	* progmodes/fortran.el (fortran-start-prog-re): New constant, extracted
+	from fortran-current-defun.
+	(fortran-beginning-of-subprogram): Be more precise about finding the
+	start, to avoid an infinite loop in end-of-defun.  (Bug#4259)
+	(fortran-end-of-subprogram): Simplify.
+	(fortran-current-defun): Use fortran-start-prog-re.
+
 2009-08-29  Juanma Barranquero  <lekktu@gmail.com>
 
 	* subr.el (do-after-load-evaluation): Simplify.
--- a/lisp/progmodes/fortran.el	Sat Aug 29 22:27:19 2009 +0000
+++ b/lisp/progmodes/fortran.el	Sun Aug 30 01:38:09 2009 +0000
@@ -1,8 +1,8 @@
 ;;; fortran.el --- Fortran mode for GNU Emacs
 
 ;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
-;;               2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-;;               Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;;   Free Software Foundation, Inc.
 
 ;; Author: Michael D. Prange <prange@erl.mit.edu>
 ;; Maintainer: Glenn Morris <rgm@gnu.org>
@@ -330,6 +330,13 @@
 (defconst fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
   "Regexp matching the start of an IF statement.")
 
+;; Note fortran-current-defun uses the subgroups.
+(defconst fortran-start-prog-re
+  "^[ \t]*\\(program\\|subroutine\\|function\
+\\|[ \ta-z0-9*()]*[ \t]+function\\|\
+\\(block[ \t]*data\\)\\)"
+  "Regexp matching the start of a subprogram, from the line start.")
+
 (defconst fortran-end-prog-re1
   "end\
 \\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
@@ -1182,37 +1189,47 @@
                                          (+ fortran-line-length
                                             (line-beginning-position)))))))
 
-;; Note that you can't just check backwards for `subroutine' &c in
-;; case of un-marked main programs not at the start of the file.
+;; This is more complex than first expected because the beginning of a
+;; main program may be implicit (ie not marked by a PROGRAM statement).
+;; This would be fine (we could just go to bob in the absence of a match),
+;; except it need not even be the first subprogram in the file (eg it
+;; could follow a subroutine).  Hence we have to search for END
+;; statements instead.
+;; cf fortran-beginning-of-block, f90-beginning-of-subprogram
+;; Note that unlike the latter, we don't have to worry about nested
+;; subprograms (?).
+;; FIXME push-mark?
 (defun fortran-beginning-of-subprogram ()
   "Move point to the beginning of the current Fortran subprogram."
   (interactive)
-  (save-match-data
-    (let ((case-fold-search t))
-      (beginning-of-line -1)
-      (if (catch 'ok
-            (while (re-search-backward fortran-end-prog-re nil 'move)
-              (if (fortran-check-end-prog-re)
-                  (throw 'ok t))))
-          (forward-line)))))
+  (let ((case-fold-search t))
+    ;; If called already at the start of subprogram, go to the previous.
+    (beginning-of-line (if (bolp) 0 1))
+    (save-match-data
+      (or (looking-at fortran-start-prog-re)
+          ;; This leaves us at bob if before the first subprogram.
+          (eq (fortran-previous-statement) 'first-statement)
+          (if (or (catch 'ok
+                    (while (re-search-backward fortran-end-prog-re nil 'move)
+                      (if (fortran-check-end-prog-re) (throw 'ok t))))
+                  ;; If the search failed, must be at bob.
+                  ;; First code line is the start of the subprogram.
+                  ;; FIXME use a more rigorous test, cf fortran-next-statement?
+                  ;; Though that needs to handle continuations too.
+                  (not (looking-at "^\\([ \t]*[0-9]\\|[ \t]+[^!#]\\)")))
+              (fortran-next-statement))))))
 
+;; This is simpler than f-beginning-of-s because the end of a
+;; subprogram is never implicit.
 (defun fortran-end-of-subprogram ()
   "Move point to the end of the current Fortran subprogram."
   (interactive)
-  (save-match-data
-    (let ((case-fold-search t))
-      (if (save-excursion               ; on END
-            (beginning-of-line)
-            (and (looking-at fortran-end-prog-re)
-                 (fortran-check-end-prog-re)))
-          (forward-line)
-        (beginning-of-line 2)
-        (when (catch 'ok
-                (while (re-search-forward fortran-end-prog-re nil 'move)
-                  (if (fortran-check-end-prog-re)
-                      (throw 'ok t))))
-          (goto-char (match-beginning 0))
-          (forward-line))))))
+  (let ((case-fold-search t))
+    (beginning-of-line)
+    (save-match-data
+      (while (and (re-search-forward fortran-end-prog-re nil 'move)
+                  (not (fortran-check-end-prog-re))))
+      (forward-line))))
 
 (defun fortran-previous-statement ()
   "Move point to beginning of the previous Fortran statement.
@@ -2137,19 +2154,16 @@
       (replace-match "" nil nil nil 1)
       (unless do-space (delete-horizontal-space)))))
 
-;; This code used to live in add-log.el, but this is a better place
-;; for it.
+;; This code used to live in add-log.el, but this is a better place for it.
 (defun fortran-current-defun ()
   "Function to use for `add-log-current-defun-function' in Fortran mode."
   (save-excursion
     ;; We must be inside function body for this to work.
     (fortran-beginning-of-subprogram)
-    (let ((case-fold-search t))         ; case-insensitive
+    (let ((case-fold-search t))
       ;; Search for fortran subprogram start.
       (if (re-search-forward
-           (concat "^[ \t]*\\(program\\|subroutine\\|function"
-                   "\\|[ \ta-z0-9*()]*[ \t]+function\\|"
-                   "\\(block[ \t]*data\\)\\)")
+           fortran-start-prog-re
            (save-excursion (fortran-end-of-subprogram)
                            (point))
            t)