]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/fortran.el
(grep-highlight-matches): Doc fix.
[gnu-emacs] / lisp / progmodes / fortran.el
index ecbe9a0241e3c8281fb08faf732da7572caa4626..88d41650c0721a4fa3433bd682a86295310d2158 100644 (file)
@@ -1,6 +1,6 @@
 ;;; fortran.el --- Fortran mode for GNU Emacs
 
-;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 2001
+;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 01, 03, 04
 ;;   Free Software Foundation, Inc.
 
 ;; Author: Michael D. Prange <prange@erl.mit.edu>
@@ -54,6 +54,7 @@
 ;; * Support any other extensions to f77 grokked by GNU Fortran I've missed.
 
 (eval-when-compile                     ; silence compiler
+  (defvar dabbrev-case-fold-search)
   (defvar imenu-case-fold-search)
   (defvar imenu-syntax-alist))
 
@@ -83,22 +84,11 @@ with a character in column 6."
   :type  'boolean
   :group 'fortran-indent)
 
-(defcustom fortran-tab-mode-string " TAB"
-  "*String to appear in mode line in TAB format buffers.
-Should have a leading space."
+(defcustom fortran-tab-mode-string "/t"
+  "*String to appear in mode line in TAB format buffers."
   :type  'string
   :group 'fortran-indent)
 
-(defvar fortran-tab-mode-minor-mode-string nil
-  "Internal variable used for `minor-mode-alist' in Fortran mode.
-Do not change the value of this variable - edit `fortran-tab-mode-string'
-instead.")
-(make-variable-buffer-local 'fortran-tab-mode-minor-mode-string)
-
-(add-to-list 'minor-mode-alist
-             '(fortran-tab-mode-minor-mode-string
-               (indent-tabs-mode fortran-tab-mode-minor-mode-string)))
-
 (defcustom fortran-do-indent 3
   "*Extra indentation applied to DO blocks."
   :type  'integer
@@ -247,10 +237,25 @@ See the variable `fortran-column-ruler-fixed' for fixed format mode."
 
 (defcustom fortran-break-before-delimiters t
   "*Non-nil causes filling to break lines before delimiters.
-Delimiters are whitespace, commas, quotes, and operators."
+Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
   :type  'boolean
   :group 'fortran)
 
+(defconst fortran-break-delimiters-re "[-+*/><=, \t]"
+  "Regexp matching delimiter characters at which lines may be broken.
+There are certain tokens comprised entirely of characters
+matching this regexp that should not be split, and these are
+specified by the constant `fortran-no-break-re'.")
+
+;; The ">=", etc F77 extensions are supported by g77.
+(defconst fortran-no-break-re
+  (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=") 'paren)
+  "Regexp specifying where not to break lines when filling.
+This regexp matches certain tokens comprised entirely of
+characters matching the regexp `fortran-break-delimiters-re' that should
+not be split by filling.  Each element is assumed to be two
+characters long.")
+
 (defcustom fortran-mode-hook nil
   "Hook run when entering Fortran mode."
   :type  'hook
@@ -429,6 +434,12 @@ These get fixed-format comments fontified.")
     table)
   "Syntax table used in Fortran mode.")
 
+(defvar fortran-gud-syntax-table
+  (let ((st (make-syntax-table fortran-mode-syntax-table)))
+    (modify-syntax-entry ?\n "." st)
+    st)
+  "Syntax table used to parse Fortran expressions for printing in GUD.")
+
 (defvar fortran-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map ";"        'fortran-abbrev-start)
@@ -677,8 +688,8 @@ with no args, if that value is non-nil."
   (set (make-local-variable 'comment-indent-function) 'fortran-comment-indent)
   (set (make-local-variable 'abbrev-all-caps) t)
   (set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill)
-  (setq fortran-tab-mode-minor-mode-string fortran-tab-mode-string)
   (set (make-local-variable 'indent-tabs-mode) (fortran-analyze-file-format))
+  (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string))
   (set (make-local-variable 'fill-column) 72)
   (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
   (set (make-local-variable 'font-lock-defaults)
@@ -701,9 +712,15 @@ with no args, if that value is non-nil."
   (set (make-local-variable 'add-log-current-defun-function)
        #'fortran-current-defun)
   (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
+  (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
   (run-hooks 'fortran-mode-hook))
 
 \f
+(defun fortran-gud-find-expr ()
+  ;; Consider \n as punctuation (end of expression).
+  (with-syntax-table fortran-gud-syntax-table
+    (gud-find-c-expr)))
+
 (defsubst fortran-comment-indent ()
   "Return the indentation appropriate for the current comment line.
 This is 0 for a line matching `fortran-comment-line-start-skip', else
@@ -711,8 +728,7 @@ the value of `comment-column' (leaving at least one space after code)."
   (if (looking-at fortran-comment-line-start-skip) 0
     (save-excursion
       (skip-chars-backward " \t")
-      (max (1+ (current-column))
-          comment-column))))
+      (max (1+ (current-column)) comment-column))))
 
 (defun fortran-indent-comment ()
   "Align or create comment on current line.
@@ -765,14 +781,14 @@ With non-nil ARG, uncomments the region."
     (goto-char beg-region)
     (beginning-of-line)
     (if arg
-        (let ((com (regexp-quote fortran-comment-region))) ;uncomment region
+        (let ((com (regexp-quote fortran-comment-region))) ; uncomment
           (if (looking-at com)
               (delete-region (point) (match-end 0)))
           (while (and (zerop (forward-line 1))
                       (< (point) end-region-mark))
             (if (looking-at com)
                 (delete-region (point) (match-end 0)))))
-      (insert fortran-comment-region) ;comment the region
+      (insert fortran-comment-region)   ; comment
       (while (and (zerop (forward-line 1))
                   (< (point) end-region-mark))
         (insert fortran-comment-region)))
@@ -785,13 +801,17 @@ With non-nil ARG, uncomments the region."
   "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
 Any other key combination is executed normally."
   (interactive "*")
-  (let (c)
-    (insert last-command-char)
-    (if (and abbrev-mode
-             (or (eq (setq c (read-event)) ??) ;insert char if not equal to `?'
-                 (eq c help-char)))
+  (insert last-command-char)
+  (let (char event)
+    (if (fboundp 'next-command-event) ; XEmacs
+        (setq event (next-command-event)
+              char (event-to-character event))
+      (setq event (read-event)
+            char event))
+    ;; Insert char if not equal to `?', or if abbrev-mode is off.
+    (if (and abbrev-mode (or (eq char ??) (eq char help-char)))
        (fortran-abbrev-help)
-      (setq unread-command-events (list c)))))
+      (setq unread-command-events (list event)))))
 
 (defun fortran-abbrev-help ()
   "List the currently defined abbrevs in Fortran mode."
@@ -813,9 +833,9 @@ Any other key combination is executed normally."
 
 (defun fortran-column-ruler ()
   "Insert a column ruler momentarily above current line, till next keystroke.
-The ruler is defined by the value of `fortran-column-ruler-fixed' when in fixed
-format mode, and `fortran-column-ruler-tab' when in TAB format mode.
-The key typed is executed unless it is SPC."
+The ruler is defined by the value of `fortran-column-ruler-fixed' in fixed
+format mode, and `fortran-column-ruler-tab' in TAB format mode.
+The next key typed is executed unless it is SPC."
   (interactive)
   (momentary-string-display
    (if indent-tabs-mode
@@ -876,8 +896,8 @@ See also `fortran-window-create'."
       (insert ?\n (match-string 0))
     (if indent-tabs-mode
        (insert ?\n ?\t (fortran-numerical-continuation-char))
-      (insert "\n " fortran-continuation-string))) ; Space after \n important
-  (fortran-indent-line))               ; when the cont string is C, c or *.
+      (insert "\n " fortran-continuation-string))) ; space after \n important
+  (fortran-indent-line))               ; when cont string is C, c or *
 
 (defun fortran-remove-continuation ()
   "Delete any Fortran continuation characters at point.
@@ -947,7 +967,6 @@ Auto-indent does not happen if a numeric ARG is used."
       (fortran-indent-line))))
 
 \f
-
 (defun fortran-check-end-prog-re ()
   "Check a preliminary match against `fortran-end-prog-re'."
   ;; Having got a possible match for the subprogram end, we need a
@@ -1104,7 +1123,7 @@ Return point or nil."
        (let ((count 1))
          (while (and (not (zerop count))
                      (not (eq (fortran-next-statement) 'last-statement))
-                     ;; Keep local to subprogram
+                     ;; Keep local to subprogram.
                      (not (and (looking-at fortran-end-prog-re)
                                (fortran-check-end-prog-re))))
            (skip-chars-forward " \t0-9")
@@ -1133,7 +1152,7 @@ Return point or nil.  Ignores labelled DO loops (ie DO 10 ... 10 CONTINUE)."
        (let ((count 1))
          (while (and (not (zerop count))
                      (not (eq (fortran-previous-statement) 'first-statement))
-                     ;; Keep local to subprogram
+                     ;; Keep local to subprogram.
                      (not (and (looking-at fortran-end-prog-re)
                                (fortran-check-end-prog-re))))
            (skip-chars-forward " \t0-9")
@@ -1184,7 +1203,7 @@ Return point or nil."
                   (save-excursion
                     (if (or
                          (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                         (let (then-test) ; Multi-line if-then.
+                         (let (then-test) ; multi-line if-then
                            (while
                                (and
                                 (zerop (forward-line 1))
@@ -1243,7 +1262,7 @@ Return point or nil."
                   (save-excursion
                     (if (or
                          (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
-                         (let (then-test) ; Multi-line if-then.
+                         (let (then-test) ; multi-line if-then
                            (while
                                (and
                                 (zerop (forward-line 1))
@@ -1338,9 +1357,9 @@ Return point or nil."
         (skip-chars-forward " \t0-9")
         (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(")
                (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]")
-                       (let (then-test)        ;multi-line if-then
+                       (let (then-test)        ; multi-line if-then
                          (while (and (zerop (forward-line 1))
-                                     ;;search forward for then
+                                     ;; Search forward for then.
                                      (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
                                      (not (setq then-test
                                                 (looking-at
@@ -1368,7 +1387,7 @@ Return point or nil."
                (setq icol (+ icol fortran-structure-indent)))
               ((and (looking-at fortran-end-prog-re1)
                     (fortran-check-end-prog-re))
-               ;; Previous END resets indent to minimum
+               ;; Previous END resets indent to minimum.
                (setq icol fortran-minimum-statement-indent)))))
     (save-excursion
       (beginning-of-line)
@@ -1481,8 +1500,8 @@ notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
                       (insert ?\t (fortran-numerical-continuation-char) 1))
              (forward-char 6))
          (delete-horizontal-space)
-         ;; Put line number in columns 0-4
-         ;; or put continuation character in column 5.
+         ;; Put line number in columns 0-4, or
+          ;; continuation character in column 5.
          (cond ((eobp))
                ((looking-at (regexp-quote fortran-continuation-string))
                 (if indent-tabs-mode
@@ -1532,7 +1551,7 @@ Otherwise return nil."
       (beginning-of-line)
       (when (looking-at "[ \t]*[0-9]+")
         (skip-chars-forward " \t")
-        (skip-chars-forward "0")       ;skip past leading zeros
+        (skip-chars-forward "0")       ; skip past leading zeros
         (setq charnum
               (buffer-substring (point) (progn
                                           (skip-chars-forward "0-9")
@@ -1584,18 +1603,17 @@ If ALL is nil, only match comments that start in column > 0."
      ((save-excursion                  ; comment lines too
        (beginning-of-line)
        (looking-at fortran-comment-line-start-skip)) nil)
-     (t (let (;; ok, serious now. Init some local vars:
-             (parse-state '(0 nil nil nil nil nil 0))
+     (t (let ((parse-state '(0 nil nil nil nil nil 0))
              (quoted-comment-start (if comment-start
                                        (regexp-quote comment-start)))
              (not-done t)
              parse-limit end-of-line)
-         ;; move to start of current statement
+         ;; Move to start of current statement.
          (fortran-next-statement)
          (fortran-previous-statement)
-         ;; now parse up to WHERE
+         ;; Now parse up to WHERE.
          (while not-done
-           (if (or ;; skip to next line if:
+           (if (or ;; Skip to next line if:
                 ;; - comment line?
                 (looking-at fortran-comment-line-start-skip)
                 ;; - at end of line?
@@ -1608,29 +1626,29 @@ If ALL is nil, only match comments that start in column > 0."
                (if (> (forward-line) 0)
                    (setq not-done nil))
              ;; else:
-             ;; if we are at beginning of code line, skip any
+             ;; If we are at beginning of code line, skip any
              ;; whitespace, labels and tab continuation markers.
              (if (bolp) (skip-chars-forward " \t0-9"))
-             ;; if we are in column <= 5 now, check for continuation char
+             ;; If we are in column <= 5 now, check for continuation char.
              (cond ((= 5 (current-column)) (forward-char 1))
                    ((and (< (current-column) 5)
                          (equal fortran-continuation-string
                                 (char-to-string (following-char)))
                          (forward-char 1))))
-             ;; find out parse-limit from here
+             ;; Find out parse-limit from here.
              (setq end-of-line (line-end-position))
              (setq parse-limit (min where end-of-line))
-             ;; parse max up to comment-start, if non-nil and in current line
+             ;; Parse max up to comment-start, if non-nil and in current line.
              (if comment-start
                  (save-excursion
                    (if (re-search-forward quoted-comment-start end-of-line t)
                        (setq parse-limit (min (point) parse-limit)))))
-             ;; now parse if still in limits
+             ;; Now parse if still in limits.
              (if (< (point) where)
                  (setq parse-state (parse-partial-sexp
                                     (point) parse-limit nil nil parse-state))
                (setq not-done nil))))
-         ;; result is
+         ;; Result.
          (nth 3 parse-state))))))
 
 ;; From old version.
@@ -1643,62 +1661,73 @@ If ALL is nil, only match comments that start in column > 0."
         (bol (line-beginning-position))
         (eol (line-end-position))
         (bos (min eol (+ bol (fortran-current-line-indentation))))
+         ;; If in a string at fill-column, break it either before the
+         ;; initial quote, or at fill-col (if string is too long).
         (quote
          (save-excursion
            (goto-char bol)
            ;; OK to break quotes on comment lines.
            (unless (looking-at fortran-comment-line-start-skip)
               (let (fcpoint start)
-             (move-to-column fill-column)
-             (when (fortran-is-in-string-p (setq fcpoint (point)))
-                (save-excursion
-                  (re-search-backward "\\S\"\\s\"\\S\"" bol t)
-                  (setq start
-                        (if fortran-break-before-delimiters
-                            (point)
-                          (1+ (point)))))
-                (if (re-search-forward "\\S\"\\s\"\\S\"" eol t)
-                    (backward-char 2))
-                ;; If the current string is longer than 72 - 6 chars,
-                ;; break it at the fill column (else infinite loop).
-                (if (> (- (point) start)
-                       (- fill-column 6 fortran-continuation-indent))
-                    fcpoint
-                  start))))))
+                (move-to-column fill-column)
+                (when (fortran-is-in-string-p (setq fcpoint (point)))
+                  (save-excursion
+                    (re-search-backward "\\S\"\\s\"\\S\"?" bol t)
+                    (setq start
+                          (if fortran-break-before-delimiters
+                              (point)
+                            (1+ (point)))))
+                  (if (re-search-forward "\\S\"\\s\"\\S\"" eol t)
+                      (backward-char 2))
+                  ;; If the current string is longer than 72 - 6 chars,
+                  ;; break it at the fill column (else infinite loop).
+                  (if (> (- (point) start)
+                         (- fill-column 6 fortran-continuation-indent))
+                      fcpoint
+                    start))))))
         ;; Decide where to split the line. If a position for a quoted
         ;; string was found above then use that, else break the line
-        ;; before the last delimiter.
-        ;; Delimiters are whitespace, commas, and operators.
-        ;; Will break before a pair of *'s.
+        ;; before/after the last delimiter.
         (fill-point
          (or quote
              (save-excursion
-               (move-to-column (1+ fill-column))
-                ;; GM Make this a defcustom as in f90-mode? Add ", (?
-               (skip-chars-backward "^ \t\n,'+-/*=)"
-;;;             (if fortran-break-before-delimiters
-;;;                 "^ \t\n,'+-/*=" "^ \t\n,'+-/*=)")
-                )
-               (when (<= (point) (1+ bos))
+                ;; If f-b-b-d is t, have an extra column to play with,
+                ;; since delimiter gets shifted to new line.
+                (move-to-column (if fortran-break-before-delimiters
+                                    (1+ fill-column)
+                                  fill-column))
+                (let ((repeat t))
+                  (while repeat
+                    (setq repeat nil)
+                    ;; Adapted from f90-find-breakpoint.
+                    (re-search-backward fortran-break-delimiters-re bol)
+                    (if (not fortran-break-before-delimiters)
+                        (if (looking-at fortran-no-break-re)
+                            ;; Deal with cases such as "**" split over
+                            ;; fill-col. Simpler alternative would be
+                            ;; to start from (1- fill-column) above.
+                            (if (> (+ 2 (current-column)) fill-column)
+                                (setq repeat t)
+                              (forward-char 2))
+                          (forward-char 1))
+                      (backward-char)
+                      (or (looking-at fortran-no-break-re)
+                          (forward-char)))))
+                ;; Line indented beyond fill-column?
+               (when (<= (point) bos)
                   (move-to-column (1+ fill-column))
-                  ;;what is this doing???
+                  ;; What is this doing???
                   (or (re-search-forward "[\t\n,'+-/*)=]" eol t)
                       (goto-char bol)))
                (if (bolp)
-                   (re-search-forward "[ \t]" opoint t)
-                 (backward-char)
-                 (if (looking-at "\\s\"")
-                     (forward-char)
-                   (skip-chars-backward " \t\*")))
-               (if fortran-break-before-delimiters
-                   (point)
-                 (1+ (point)))))))
-    ;; if we are in an in-line comment, don't break unless the
+                   (re-search-forward "[ \t]" opoint t))
+                (point)))))
+    ;; If we are in an in-line comment, don't break unless the
     ;; line of code is longer than it should be. Otherwise
     ;; break the line at the column computed above.
     ;;
-    ;; Need to use fortran-find-comment-start-skip to make sure that quoted !'s
-    ;; don't prevent a break.
+    ;; Need to use fortran-find-comment-start-skip to make sure that
+    ;; quoted !'s don't prevent a break.
     (when (and (save-excursion
                 (beginning-of-line)
                 (if (not (fortran-find-comment-start-skip))
@@ -1727,7 +1756,7 @@ If ALL is nil, only match comments that start in column > 0."
           (if (fortran-find-comment-start-skip)
               (delete-and-extract-region
                (match-beginning 0) (line-end-position))))))
-    ;; Forward line 1 really needs to go to next non white line
+    ;; Forward line 1 really needs to go to next non white line.
     (if (save-excursion (forward-line)
                        (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
        (progn
@@ -1761,8 +1790,7 @@ before the end or in the first `fortran-analyze-depth' lines."
       (cond
        ((eq (char-after) ?\t) t)
        ((looking-at " \\{6\\}") nil)
-       (fortran-tab-mode-default t)
-       (t nil)))))
+       (t fortran-tab-mode-default)))))
 
 (defun fortran-fill-paragraph (&optional justify)
   "Fill surrounding comment block as paragraphs, else fill statement.
@@ -1818,7 +1846,7 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace."
     ;; We must be inside function body for this to work.
     (fortran-beginning-of-subprogram)
     (let ((case-fold-search t))                ; case-insensitive
-      ;; search for fortran subprogram start
+      ;; Search for fortran subprogram start.
       (if (re-search-forward
            (concat "^[ \t]*\\(program\\|subroutine\\|function"
                    "\\|[ \ta-z0-9*()]*[ \t]+function\\|"
@@ -1828,7 +1856,7 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace."
            t)
           (or (match-string-no-properties 2)
               (progn
-                ;; move to EOL or before first left paren
+                ;; Move to EOL or before first left paren.
                 (if (re-search-forward "[(\n]" nil t)
                     (progn (backward-char)
                            (skip-chars-backward " \t"))
@@ -1840,4 +1868,5 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace."
 
 (provide 'fortran)
 
+;;; arch-tag: 74935096-21c4-4cab-8ee5-6ef16090dc04
 ;;; fortran.el ends here