fortran.el 68.6 KB
Newer Older
Eric S. Raymond's avatar
Eric S. Raymond committed
1 2
;;; fortran.el --- Fortran mode for GNU Emacs

3
;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000 Free Software Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
4

Eric S. Raymond's avatar
Eric S. Raymond committed
5
;; Author: Michael D. Prange <prange@erl.mit.edu>
6
;; Maintainer: Dave Love <fx@gnu.org>
Eric S. Raymond's avatar
Eric S. Raymond committed
7
;; Keywords: languages
Eric S. Raymond's avatar
Eric S. Raymond committed
8

Eric S. Raymond's avatar
Eric S. Raymond committed
9 10 11 12 13 14 15 16 17 18 19 20 21
;; This file is part of GNU Emacs.

;; GNU Emacs 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 2, or (at your option)
;; any later version.

;; GNU Emacs 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
Erik Naggum's avatar
Erik Naggum committed
22 23 24
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
Eric S. Raymond's avatar
Eric S. Raymond committed
25 26 27

;;; Commentary:

28 29 30
;; This mode is documented in the Emacs manual.
;;
;; Note that it is for editing Fortran77 or Fortran90 fixed source
Dave Love's avatar
Dave Love committed
31
;; form.  For editing Fortran 90 free format source, use `f90-mode'
32 33 34 35 36
;; (f90.el).

;;; History:

;; Fortran mode was upgraded by Stephen A. Wood (saw@cebaf.gov).
37 38

;; We acknowledge many contributions and valuable suggestions by
Richard M. Stallman's avatar
Richard M. Stallman committed
39
;; Lawrence R. Dodd, Ralf Fassel, Ralph Finch, Stephen Gildea,
40
;; Dr. Anil Gokhale, Ulrich Mueller, Mark Neale, Eric Prestemon,
Richard M. Stallman's avatar
Richard M. Stallman committed
41 42
;; Gary Sabot and Richard Stallman.

Eric S. Raymond's avatar
Eric S. Raymond committed
43 44
;;; Code:

Dave Love's avatar
Dave Love committed
45
;; Todo:
46

47
;; * Tidy it all up!
48 49 50
;; * Implement insertion and removal of statement continuations in
;;   mixed f77/f90 style, with the first `&' past column 72 and the
;;   second in column 6.
Dave Love's avatar
Dave Love committed
51
;; * Support any other extensions to f77 grokked by GNU Fortran.
52

53
(require 'easymenu)
Erik Naggum's avatar
Erik Naggum committed
54

55 56
(defgroup fortran nil
  "Fortran mode for Emacs"
Dave Love's avatar
Dave Love committed
57
  :link '(custom-manual "(emacs)Fortran")
58 59 60 61 62 63 64 65 66 67 68 69 70
  :group 'languages)

(defgroup fortran-indent nil
  "Indentation variables in Fortran mode"
  :prefix "fortran-"
  :group 'fortran)

(defgroup fortran-comment nil
  "Comment-handling variables in Fortran mode"
  :prefix "fortran-"
  :group 'fortran)


Jim Blandy's avatar
Jim Blandy committed
71
;;;###autoload
72
(defcustom fortran-tab-mode-default nil
73 74 75
  "*Default tabbing/carriage control style for empty files in Fortran mode.
A value of t specifies tab-digit style of continuation control.
A value of nil specifies that continuation lines are marked
76 77 78
with a character in column 6."
  :type 'boolean
  :group 'fortran-indent)
79 80

;; Buffer local, used to display mode line.
81 82 83 84
(defcustom fortran-tab-mode-string nil
  "String to appear in mode line when TAB format mode is on."
  :type '(choice (const nil) string)
  :group 'fortran-indent)
85
(make-variable-buffer-local 'fortran-tab-mode-string)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

(defcustom fortran-do-indent 3
  "*Extra indentation applied to DO blocks."
  :type 'integer
  :group 'fortran-indent)

(defcustom fortran-if-indent 3
  "*Extra indentation applied to IF blocks."
  :type 'integer
  :group 'fortran-indent)

(defcustom fortran-structure-indent 3
  "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
  :type 'integer
  :group 'fortran-indent)

(defcustom fortran-continuation-indent 5
  "*Extra indentation applied to Fortran continuation lines."
  :type 'integer
  :group 'fortran-indent)

(defcustom fortran-comment-indent-style 'fixed
108 109
  "*How to indent comments.
nil forces comment lines not to be touched,
110 111 112 113
'fixed makes fixed comment indentation to `fortran-comment-line-extra-indent'
columns beyond `fortran-minimum-statement-indent-fixed' (for
`indent-tabs-mode' of nil) or `fortran-minimum-statement-indent-tab' (for
`indent-tabs-mode' of t), and 'relative indents to current
114
Fortran indentation plus `fortran-comment-line-extra-indent'."
115
  :type '(radio (const :tag "Untouched" nil) (const fixed) (const relative))
116 117 118 119 120 121 122 123
  :group 'fortran-indent)

(defcustom fortran-comment-line-extra-indent 0
  "*Amount of extra indentation for text within full-line comments."
  :type 'integer
  :group 'fortran-indent
  :group 'fortran-comment)

124 125 126
(defcustom fortran-comment-line-start "C"
  "*Delimiter inserted to start new full-line comment.
You might want to change this to \"*\", for instance."
127
  :version "21.1"
128
  :type 'string
129 130
  :group 'fortran-comment)

131 132 133 134
;; This used to match preprocessor lines too, but that messes up
;; filling and doesn't seem to be necessary.
(defcustom fortran-comment-line-start-skip
  "^[CcDd*!]\\(\\([^ \t\n]\\)\\2\\2*\\)?[ \t]*"
135
  "*Regexp to match the start of a full-line comment."
136
  :version "21.1"
137
  :type 'regexp
138 139 140 141 142 143 144 145 146 147 148
  :group 'fortran-comment)

(defcustom fortran-minimum-statement-indent-fixed 6
  "*Minimum statement indentation for fixed format continuation style."
  :type 'integer
  :group 'fortran-indent)

(defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
  "*Minimum statement indentation for TAB format continuation style."
  :type 'integer
  :group 'fortran-indent)
Jim Blandy's avatar
Jim Blandy committed
149 150 151 152

;; Note that this is documented in the v18 manuals as being a string
;; of length one rather than a single character.
;; The code in this file accepts either format for compatibility.
153
(defcustom fortran-comment-indent-char " "
Jim Blandy's avatar
Jim Blandy committed
154
  "*Single-character string inserted for Fortran comment indentation.
155 156 157
Normally a space."
  :type 'string
  :group 'fortran-comment)
Jim Blandy's avatar
Jim Blandy committed
158

159
(defcustom fortran-line-number-indent 1
Jim Blandy's avatar
Jim Blandy committed
160
  "*Maximum indentation for Fortran line numbers.
161 162 163
5 means right-justify them within their five-column field."
  :type 'integer
  :group 'fortran-indent)
Jim Blandy's avatar
Jim Blandy committed
164

165 166 167 168
(defcustom fortran-check-all-num-for-matching-do nil
  "*Non-nil causes all numbered lines to be treated as possible DO loop ends."
  :type 'boolean
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
169

170
(defcustom fortran-blink-matching-if nil
171
  "*Non-nil causes \\[fortran-indent-line] on ENDIF statement to blink on matching IF.
172 173 174
Also, from an ENDDO statement blink on matching DO [WHILE] statement."
  :type 'boolean
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
175

176
(defcustom fortran-continuation-string "$"
Richard M. Stallman's avatar
Richard M. Stallman committed
177
  "*Single-character string used for Fortran continuation lines.
Jim Blandy's avatar
Jim Blandy committed
178 179 180 181
In fixed format continuation style, this character is inserted in
column 6 by \\[fortran-split-line] to begin a continuation line.
Also, if \\[fortran-indent-line] finds this at the beginning of a line, it will
convert the line into a continuation line of the appropriate style.
182 183 184
Normally $."
  :type 'string
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
185

186
(defcustom fortran-comment-region "c$$$"
187 188
  "*String inserted by \\[fortran-comment-region] at start of each \
line in region."
189 190
  :type 'string
  :group 'fortran-comment)
Jim Blandy's avatar
Jim Blandy committed
191

192
(defcustom fortran-electric-line-number t
193 194
  "*Non-nil causes line number digits to be moved to the correct \
column as typed."
195 196
  :type 'boolean
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
197

198 199
(defvar fortran-column-ruler-fixed
  "0   4 6  10        20        30        40        5\
200
0        60        70\n\
201 202
\[   ]|{   |    |    |    |    |    |    |    |    \
\|    |    |    |    |}\n"
Dave Love's avatar
Dave Love committed
203
  "String displayed above current line by \\[fortran-column-ruler].
204
This variable used in fixed format mode.")
205 206 207

(defvar fortran-column-ruler-tab
  "0       810        20        30        40        5\
208
0        60        70\n\
209 210
\[   ]|  { |    |    |    |    |    |    |    |    \
\|    |    |    |    |}\n"
Dave Love's avatar
Dave Love committed
211
  "String displayed above current line by \\[fortran-column-ruler].
212
This variable used in TAB format mode.")
Jim Blandy's avatar
Jim Blandy committed
213 214 215 216 217

(defvar fortran-mode-syntax-table nil
  "Syntax table in use in Fortran mode buffers.")

(defvar fortran-analyze-depth 100
218 219
  "Number of lines to scan to determine whether to use fixed or TAB \
format style.")
Jim Blandy's avatar
Jim Blandy committed
220

221
(defcustom fortran-break-before-delimiters t
222
  "*Non-nil causes filling to break lines before delimiters."
223 224
  :type 'boolean
  :group 'fortran)
Richard M. Stallman's avatar
Richard M. Stallman committed
225

Jim Blandy's avatar
Jim Blandy committed
226 227 228
(if fortran-mode-syntax-table
    ()
  (setq fortran-mode-syntax-table (make-syntax-table))
229 230
  ;; We might like `;' to be punctuation (g77 multi-statement lines),
  ;; but that screws abbrevs.
Jim Blandy's avatar
Jim Blandy committed
231 232 233 234 235 236 237 238 239
  (modify-syntax-entry ?\; "w" fortran-mode-syntax-table)
  (modify-syntax-entry ?\r " " fortran-mode-syntax-table)
  (modify-syntax-entry ?+ "." fortran-mode-syntax-table)
  (modify-syntax-entry ?- "." fortran-mode-syntax-table)
  (modify-syntax-entry ?= "." fortran-mode-syntax-table)
  (modify-syntax-entry ?* "." fortran-mode-syntax-table)
  (modify-syntax-entry ?/ "." fortran-mode-syntax-table)
  (modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
  (modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
240
  (modify-syntax-entry ?\\ "\\" fortran-mode-syntax-table)
241 242 243 244 245
  ;; This might be better as punctuation, as for C, but this way you
  ;; can treat floating-point numbers as symbols.
  (modify-syntax-entry ?. "_" fortran-mode-syntax-table) ; e.g. `a.ne.b'
  (modify-syntax-entry ?_ "_" fortran-mode-syntax-table)
  (modify-syntax-entry ?$ "_" fortran-mode-syntax-table) ; esp. VMSisms
246
  (modify-syntax-entry ?\! "<" fortran-mode-syntax-table)
Jim Blandy's avatar
Jim Blandy committed
247 248
  (modify-syntax-entry ?\n ">" fortran-mode-syntax-table))

249 250 251 252 253
;; Comments are real pain in Fortran because there is no way to
;; represent the standard comment syntax in an Emacs syntax table.
;; (We can do so for F90-style).  Therefore an unmatched quote in a
;; standard comment will throw fontification off on the wrong track.
;; So we do syntactic fontification with regexps.
254

255 256
;; Regexps done by simon@gnu with help from Ulrik Dickow <dickow@nbi.dk> and
;; probably others Si's forgotten about (sorry).
257

258
(defconst fortran-font-lock-keywords-1 nil
259
  "Subdued level highlighting for Fortran mode.")
260

261 262 263 264 265 266
(defconst fortran-font-lock-keywords-2 nil
  "Medium level highlighting for Fortran mode.")

(defconst fortran-font-lock-keywords-3 nil
  "Gaudy level highlighting for Fortran mode.")

267 268 269
(defconst fortran-font-lock-syntactic-keywords nil
  "`font-lock-syntactic-keywords' for Fortran.
These get fixed-format comments fontified.")
270

271
(let ((comment-chars "cd\\*")		; `d' for `debugging' comments
272
      (fortran-type-types
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
       (eval-when-compile
	 (let ((re (regexp-opt
		    (let ((simple-types
			   '("character" "byte" "integer" "logical"
			     "none" "real" "complex"
			     "double precision" "double complex"))
			  (structured-types '("structure" "union" "map"))
			  (other-types '("record" "dimension"
					 "parameter" "common" "save"
					 "external" "intrinsic" "data"
					 "equivalence")))
		      (append
		       (mapcar (lambda (x) (concat "implicit " x))
			       simple-types)
		       simple-types
		       (mapcar (lambda (x) (concat "end " x))
			       structured-types)
		       structured-types
		       other-types)))))
	   ;; In the optimized regexp above, replace spaces by regexp
	   ;; for optional whitespace, which regexp-opt would have
	   ;; escaped.
	   (mapconcat #'identity (split-string re) "[ \t]*"))))
296 297
      (fortran-keywords
       (eval-when-compile
298 299 300
         (regexp-opt '("continue" "format" "end" "enddo" "if" "then"
                       "else" "endif" "elseif" "while" "inquire" "stop"
                       "return" "include" "open" "close" "read" "write"
Dave Love's avatar
Dave Love committed
301
                       "format" "print" "select" "case" "cycle" "exit"))))
302 303
      (fortran-logicals
       (eval-when-compile
304
         (regexp-opt '("and" "or" "not" "lt" "le" "eq" "ge" "gt" "ne"
305
                       "true" "false")))))
306 307 308 309 310 311 312
  (setq fortran-font-lock-syntactic-keywords
	;; Fixed format comments.  (!-style handled normally.)
	(list
	 (list (concat "^[" comment-chars "]") 0 '(11))
	 (list (concat "^[^" comment-chars "\t\n]" (make-string 71 ?.)
		       "\\([^\n]+\\)")
	       1 '(11))))
313 314 315 316 317 318 319 320 321 322 323
  (setq fortran-font-lock-keywords-1
        (list
         ;; Program, subroutine and function declarations, plus calls.
         (list (concat "\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|"
                       "program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?")
               '(1 font-lock-keyword-face)
               '(2 font-lock-function-name-face nil t))))
  (setq fortran-font-lock-keywords-2
        (append fortran-font-lock-keywords-1
                (list
                 ;; Fontify all type specifiers (must be first; see below).
Dave Love's avatar
Dave Love committed
324
                 (cons (concat "\\<\\(" fortran-type-types "\\)\\>")
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
                       'font-lock-type-face)
                 ;; Fontify all builtin keywords (except logical, do
                 ;; and goto; see below).
                 (concat "\\<\\(" fortran-keywords "\\)\\>")
                 ;; Fontify all builtin operators.
                 (concat "\\.\\(" fortran-logicals "\\)\\.")
                 ;; Fontify do/goto keywords and targets, and goto tags.
                 (list "\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
                       '(1 font-lock-keyword-face)
                       '(2 font-lock-constant-face nil t))
                 (cons "^ *\\([0-9]+\\)" 'font-lock-constant-face))))
  (setq fortran-font-lock-keywords-3
        (append
         ;; The list `fortran-font-lock-keywords-1'.
         fortran-font-lock-keywords-1
         ;; Fontify all type specifiers plus their declared items.
         (list
          (list (concat "\\<\\(" fortran-type-types "\\)\\>[ \t(/]*\\(*\\)?")
                ;; Fontify the type specifier.
                '(1 font-lock-type-face)
                ;; Fontify each declaration item (or just the /.../ block name).
346
                `(font-lock-match-c-style-declaration-item-and-skip-to-next
347
                  ;; Start after any *(...) expression.
348 349 350 351 352 353
                  (condition-case nil
		      (and (and (match-beginning ,(+ 2 (regexp-opt-depth
							fortran-type-types)))
				(forward-sexp))
			   (forward-sexp))
		    (error nil))
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
                  ;; No need to clean up.
                  nil
                  ;; Fontify as a variable name, functions are
                  ;; fontified elsewhere.
                  (1 font-lock-variable-name-face nil t))))
         ;; Things extra to `fortran-font-lock-keywords-3'
         ;; (must be done first).
         (list
          ;; Fontify goto-like `err=label'/`end=label' in read/write
          ;; statements.
          '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?"
            (1 font-lock-keyword-face) (4 font-lock-constant-face nil t))
          ;; Highlight standard continuation character and in a
          ;; TAB-formatted line.
          '("^     \\([^ 0]\\)" 1 font-lock-string-face)
          '("^\t\\([1-9]\\)" 1 font-lock-string-face))
370 371 372
	 (list 
	  ;; cpp stuff (ugh)
	  '("^# *[a-z]+" . font-lock-keyword-face))
373 374 375 376
         ;; The list `fortran-font-lock-keywords-2' less that for types
         ;; (see above).
         (cdr (nthcdr (length fortran-font-lock-keywords-1)
                      fortran-font-lock-keywords-2)))))
377

378 379
(defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
  "Default expressions to highlight in Fortran mode.")
380

381
(defvar fortran-imenu-generic-expression
382 383
  ;; These patterns could be confused by sequence nos. in cols 72+ and
  ;; don't allow continuations everywhere.
384 385 386 387 388 389 390 391 392 393
  (list
   (list
    nil
    ;; Lines below are: 1. leading whitespace; 2. function
    ;; declaration with optional type, e.g. `real', `real*4',
    ;; character(*), `double precision' and possible statement
    ;; continuation; 3. untyped declarations; 4. the variable to
    ;; index.  [This will be fooled by `end function' allowed by G77.
    ;; Also, it assumes sensible whitespace is employed.]
    (concat "^\\s-+\\(\
394 395 396
\\(\\sw\\|\\s-\\|[*()+]\\)*\
\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)\
[ \t" fortran-continuation-string "]+\
397 398 399 400
\\(\\sw+\\)")
    3)
   ;; Un-named block data
   (list nil "^\\s-+\\(block\\s-*data\\)\\s-*$" 1))
Dave Love's avatar
Dave Love committed
401
  "Imenu generic expression for `imenu-default-create-index-function'.")
402

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
(defvar fortran-mode-map
  (let ((fortran-mode-map (make-sparse-keymap)))
    (define-key fortran-mode-map ";" 'fortran-abbrev-start)
    (define-key fortran-mode-map "\C-c;" 'fortran-comment-region)
    (define-key fortran-mode-map "\M-;" 'fortran-indent-comment)
    (define-key fortran-mode-map "\M-\n" 'fortran-split-line)
    (define-key fortran-mode-map "\M-\C-q" 'fortran-indent-subprogram)
    (define-key fortran-mode-map "\C-c\C-w" 'fortran-window-create-momentarily)
    (define-key fortran-mode-map "\C-c\C-r" 'fortran-column-ruler)
    (define-key fortran-mode-map "\C-c\C-p" 'fortran-previous-statement)
    (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement)
    (define-key fortran-mode-map "\C-c\C-d" 'fortran-join-line) ; like f90
    (define-key fortran-mode-map "\M-^" 'fortran-join-line) ; subvert delete-indentation
    (define-key fortran-mode-map "0" 'fortran-electric-line-number)
    (define-key fortran-mode-map "1" 'fortran-electric-line-number)
    (define-key fortran-mode-map "2" 'fortran-electric-line-number)
    (define-key fortran-mode-map "3" 'fortran-electric-line-number)
    (define-key fortran-mode-map "4" 'fortran-electric-line-number)
    (define-key fortran-mode-map "5" 'fortran-electric-line-number)
    (define-key fortran-mode-map "6" 'fortran-electric-line-number)
    (define-key fortran-mode-map "7" 'fortran-electric-line-number)
    (define-key fortran-mode-map "8" 'fortran-electric-line-number)
    (define-key fortran-mode-map "9" 'fortran-electric-line-number)

    ;; Menu
    (unless (boundp 'fortran-mode-menu)
      (easy-menu-define
       fortran-mode-menu fortran-mode-map ""
       `("Fortran"
	 ["Manual" (info "(emacs)Fortran")]
433 434 435 436 437 438 439
;;; This loads cus-edit as things stand -- needs to be done lazily.
;;; 	 ,(customize-menu-create 'fortran)
;;; 	 ["Set" Custom-set t]
;;; 	 ["Save" Custom-save t]
;;; 	 ["Reset to Current" Custom-reset-current t]
;;; 	 ["Reset to Saved" Custom-reset-saved t]
;;; 	 ["Reset to Standard Settings" Custom-reset-standard t]
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
	 "----"
	 ["Toggle Auto-fill" fortran-auto-fill-mode :style toggle
	  :selected (eq auto-fill-function 'fortran-do-auto-fill)]
	 ["Toggle abbrev-mode" abbrev-mode :style toggle :selected abbrev-mode]
	 "----"
	 ["Comment-out Region" fortran-comment-region mark-active]
	 ["Uncomment-out region"
	  (fortran-comment-region (region-beginning) (region-end) 1)
	  mark-active]
	 ["Indent Region" indent-region mark-active]
	 ["Indent Subprogram" fortran-indent-subprogram t]
	 "----"
	 ["Beginning of Subprogram" fortran-beginning-of-subprogram t]
	 ["End of Subprogram" fortran-end-of-subprogram t]
	 ("Mark"
	  ["Subprogram" mark-defun t]
	  ["IF Block" fortran-mark-if t]
	  ["DO Block" fortran-mark-do t])
	 ["Narrow to Subprogram" narrow-to-defun t]
	 ["Widen" widen t]
	 "----"
	 ["Temporary column ruler" fortran-column-ruler t]
	 ["72-column window" fortran-window-create t]
	 ["Full Width Window"
	  (enlarge-window-horizontally (- (frame-width) (window-width)))
	  (< (window-width) (frame-width))]
	 ["Momentary 72-column window" fortran-window-create-momentarily t]
	 "----"
	 ["Break Line at Point" fortran-split-line t]
	 ["Join Line" fortran-join-line t]
	 ["Fill Statement/Comment" fill-paragraph  t]
	 "----"
	 ["Add imenu menu"
	  imenu-add-menubar-index (not (and (boundp 'imenu--index-alist)
					    imenu--index-alist))])))
    fortran-mode-map)
Richard M. Stallman's avatar
Richard M. Stallman committed
476
  "Keymap used in Fortran mode.")
Jim Blandy's avatar
Jim Blandy committed
477

478
(defvar fortran-mode-abbrev-table
Jim Blandy's avatar
Jim Blandy committed
479 480 481 482
  (let ((ac abbrevs-changed))
    (define-abbrev-table 'fortran-mode-abbrev-table ())
    (define-abbrev fortran-mode-abbrev-table  ";au"  "automatic" nil)
    (define-abbrev fortran-mode-abbrev-table  ";b"   "byte" nil)
Richard M. Stallman's avatar
Richard M. Stallman committed
483
    (define-abbrev fortran-mode-abbrev-table  ";bd"  "block data" nil)
Jim Blandy's avatar
Jim Blandy committed
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
    (define-abbrev fortran-mode-abbrev-table  ";ch"  "character" nil)
    (define-abbrev fortran-mode-abbrev-table  ";cl"  "close" nil)
    (define-abbrev fortran-mode-abbrev-table  ";c"   "continue" nil)
    (define-abbrev fortran-mode-abbrev-table  ";cm"  "common" nil)
    (define-abbrev fortran-mode-abbrev-table  ";cx"  "complex" nil)
    (define-abbrev fortran-mode-abbrev-table  ";df"  "define" nil)
    (define-abbrev fortran-mode-abbrev-table  ";di"  "dimension" nil)
    (define-abbrev fortran-mode-abbrev-table  ";do"  "double" nil)
    (define-abbrev fortran-mode-abbrev-table  ";dc"  "double complex" nil)
    (define-abbrev fortran-mode-abbrev-table  ";dp"  "double precision" nil)
    (define-abbrev fortran-mode-abbrev-table  ";dw"  "do while" nil)
    (define-abbrev fortran-mode-abbrev-table  ";e"   "else" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ed"  "enddo" nil)
    (define-abbrev fortran-mode-abbrev-table  ";el"  "elseif" nil)
    (define-abbrev fortran-mode-abbrev-table  ";en"  "endif" nil)
    (define-abbrev fortran-mode-abbrev-table  ";eq"  "equivalence" nil)
Richard M. Stallman's avatar
Richard M. Stallman committed
500
    (define-abbrev fortran-mode-abbrev-table  ";ew"  "endwhere" nil)
Jim Blandy's avatar
Jim Blandy committed
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
    (define-abbrev fortran-mode-abbrev-table  ";ex"  "external" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ey"  "entry" nil)
    (define-abbrev fortran-mode-abbrev-table  ";f"   "format" nil)
    (define-abbrev fortran-mode-abbrev-table  ";fa"  ".false." nil)
    (define-abbrev fortran-mode-abbrev-table  ";fu"  "function" nil)
    (define-abbrev fortran-mode-abbrev-table  ";g"   "goto" nil)
    (define-abbrev fortran-mode-abbrev-table  ";im"  "implicit" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ib"  "implicit byte" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ic"  "implicit complex" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ich" "implicit character" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ii"  "implicit integer" nil)
    (define-abbrev fortran-mode-abbrev-table  ";il"  "implicit logical" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ir"  "implicit real" nil)
    (define-abbrev fortran-mode-abbrev-table  ";inc" "include" nil)
    (define-abbrev fortran-mode-abbrev-table  ";in"  "integer" nil)
    (define-abbrev fortran-mode-abbrev-table  ";intr" "intrinsic" nil)
    (define-abbrev fortran-mode-abbrev-table  ";l"   "logical" nil)
    (define-abbrev fortran-mode-abbrev-table  ";n"   "namelist" nil)
    (define-abbrev fortran-mode-abbrev-table  ";o"   "open" nil) ; was ;op
    (define-abbrev fortran-mode-abbrev-table  ";pa"  "parameter" nil)
    (define-abbrev fortran-mode-abbrev-table  ";pr"  "program" nil)
    (define-abbrev fortran-mode-abbrev-table  ";ps"  "pause" nil)
    (define-abbrev fortran-mode-abbrev-table  ";p"   "print" nil)
    (define-abbrev fortran-mode-abbrev-table  ";rc"  "record" nil)
    (define-abbrev fortran-mode-abbrev-table  ";re"  "real" nil)
    (define-abbrev fortran-mode-abbrev-table  ";r"   "read" nil)
    (define-abbrev fortran-mode-abbrev-table  ";rt"  "return" nil)
    (define-abbrev fortran-mode-abbrev-table  ";rw"  "rewind" nil)
    (define-abbrev fortran-mode-abbrev-table  ";s"   "stop" nil)
    (define-abbrev fortran-mode-abbrev-table  ";sa"  "save" nil)
    (define-abbrev fortran-mode-abbrev-table  ";st"  "structure" nil)
    (define-abbrev fortran-mode-abbrev-table  ";sc"  "static" nil)
    (define-abbrev fortran-mode-abbrev-table  ";su"  "subroutine" nil)
    (define-abbrev fortran-mode-abbrev-table  ";tr"  ".true." nil)
    (define-abbrev fortran-mode-abbrev-table  ";ty"  "type" nil)
    (define-abbrev fortran-mode-abbrev-table  ";vo"  "volatile" nil)
    (define-abbrev fortran-mode-abbrev-table  ";w"   "write" nil)
Richard M. Stallman's avatar
Richard M. Stallman committed
538
    (define-abbrev fortran-mode-abbrev-table  ";wh"  "where" nil)
539 540
    (setq abbrevs-changed ac)
    fortran-mode-abbrev-table))
Jim Blandy's avatar
Jim Blandy committed
541

542 543 544
(eval-when-compile			; silence compiler
  (defvar imenu-case-fold-search)
  (defvar imenu-syntax-alist))
545

546 547 548 549 550
(defcustom fortran-mode-hook nil
  "Hook run by Fortran mode."
  :type 'hook
  :group 'fortran)

Jim Blandy's avatar
Jim Blandy committed
551 552
;;;###autoload
(defun fortran-mode ()
Richard M. Stallman's avatar
Richard M. Stallman committed
553
  "Major mode for editing Fortran code.
554
\\[fortran-indent-line] indents the current Fortran line correctly.
Richard M. Stallman's avatar
Richard M. Stallman committed
555
DO statements must not share a common CONTINUE.
Jim Blandy's avatar
Jim Blandy committed
556

557 558
Type ;? or ;\\[help-command] to display a list of built-in abbrevs for
Fortran keywords.
Jim Blandy's avatar
Jim Blandy committed
559 560 561 562 563 564

Key definitions:
\\{fortran-mode-map}

Variables controlling indentation style and extra features:

Dave Love's avatar
Dave Love committed
565
 `comment-start'
Jim Blandy's avatar
Jim Blandy committed
566 567
    Normally nil in Fortran mode.  If you want to use comments
    starting with `!', set this to the string \"!\".
Dave Love's avatar
Dave Love committed
568
 `fortran-do-indent'
Jim Blandy's avatar
Jim Blandy committed
569
    Extra indentation within do blocks.  (default 3)
Dave Love's avatar
Dave Love committed
570
 `fortran-if-indent'
Jim Blandy's avatar
Jim Blandy committed
571
    Extra indentation within if blocks.  (default 3)
Dave Love's avatar
Dave Love committed
572
 `fortran-structure-indent'
573 574
    Extra indentation within structure, union, map and interface blocks.
    (default 3)
Dave Love's avatar
Dave Love committed
575
 `fortran-continuation-indent'
Richard M. Stallman's avatar
Richard M. Stallman committed
576
    Extra indentation applied to continuation statements.  (default 5)
Dave Love's avatar
Dave Love committed
577 578 579
 `fortran-comment-line-extra-indent'
    Amount of extra indentation for text within full-line comments.  (default 0)
 `fortran-comment-indent-style'
Jim Blandy's avatar
Jim Blandy committed
580
    nil    means don't change indentation of text in full-line comments,
581 582 583 584 585
    fixed  means indent that text at `fortran-comment-line-extra-indent' beyond
           the value of `fortran-minimum-statement-indent-fixed' (for fixed
           format continuation style) or `fortran-minimum-statement-indent-tab'
           (for TAB format continuation style).
    relative  means indent at `fortran-comment-line-extra-indent' beyond the
Jim Blandy's avatar
Jim Blandy committed
586 587
 	      indentation for a line of code.
    (default 'fixed)
Dave Love's avatar
Dave Love committed
588
 `fortran-comment-indent-char'
Richard M. Stallman's avatar
Richard M. Stallman committed
589
    Single-character string to be inserted instead of space for
Jim Blandy's avatar
Jim Blandy committed
590
    full-line comment indentation.  (default \" \")
Dave Love's avatar
Dave Love committed
591 592 593 594 595
 `fortran-minimum-statement-indent-fixed'
    Minimum indentation for Fortran statements in fixed format mode.  (def.6)
 `fortran-minimum-statement-indent-tab'
    Minimum indentation for Fortran statements in TAB format mode.  (default 9)
 `fortran-line-number-indent'
Jim Blandy's avatar
Jim Blandy committed
596 597 598
    Maximum indentation for line numbers.  A line number will get
    less than this much indentation if necessary to avoid reaching
    column 5.  (default 1)
Dave Love's avatar
Dave Love committed
599
 `fortran-check-all-num-for-matching-do'
Richard M. Stallman's avatar
Richard M. Stallman committed
600
    Non-nil causes all numbered lines to be treated as possible \"continue\"
Jim Blandy's avatar
Jim Blandy committed
601
    statements.  (default nil)
Dave Love's avatar
Dave Love committed
602
 `fortran-blink-matching-if'
603 604 605
    Non-nil causes \\[fortran-indent-line] on an ENDIF statement to blink on
    matching IF.  Also, from an ENDDO statement, blink on matching DO [WHILE]
    statement.  (default nil)
Dave Love's avatar
Dave Love committed
606
 `fortran-continuation-string'
Jim Blandy's avatar
Jim Blandy committed
607 608
    Single-character string to be inserted in column 5 of a continuation
    line.  (default \"$\")
Dave Love's avatar
Dave Love committed
609
 `fortran-comment-region'
610
    String inserted by \\[fortran-comment-region] at start of each line in
Jim Blandy's avatar
Jim Blandy committed
611
    region.  (default \"c$$$\")
Dave Love's avatar
Dave Love committed
612
 `fortran-electric-line-number'
613
    Non-nil causes line number digits to be moved to the correct column
Jim Blandy's avatar
Jim Blandy committed
614
    as typed.  (default t)
Dave Love's avatar
Dave Love committed
615
 `fortran-break-before-delimiters'
616
    Non-nil causes lines to be broken before delimiters.
Richard M. Stallman's avatar
Richard M. Stallman committed
617
    (default t)
Jim Blandy's avatar
Jim Blandy committed
618

Richard M. Stallman's avatar
Richard M. Stallman committed
619
Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
Jim Blandy's avatar
Jim Blandy committed
620 621 622 623 624
with no args, if that value is non-nil."
  (interactive)
  (kill-all-local-variables)
  (setq local-abbrev-table fortran-mode-abbrev-table)
  (set-syntax-table fortran-mode-syntax-table)
625
  ;; Font Lock mode support.
626 627 628 629 630
  (make-local-variable 'font-lock-defaults)
  (setq font-lock-defaults '((fortran-font-lock-keywords
			      fortran-font-lock-keywords-1
			      fortran-font-lock-keywords-2
			      fortran-font-lock-keywords-3)
631
			     nil t ((?/ . "$/") ("_$" . "w"))
632
			     fortran-beginning-of-subprogram))
633 634
  (set (make-local-variable 'font-lock-syntactic-keywords)
       fortran-font-lock-syntactic-keywords)
Richard M. Stallman's avatar
Richard M. Stallman committed
635 636
  (make-local-variable 'fortran-break-before-delimiters)
  (setq fortran-break-before-delimiters t)
Jim Blandy's avatar
Jim Blandy committed
637 638
  (make-local-variable 'indent-line-function)
  (setq indent-line-function 'fortran-indent-line)
639
  (make-local-variable 'comment-indent-function)
640
  (setq comment-indent-function 'fortran-comment-indent-function)
Jim Blandy's avatar
Jim Blandy committed
641 642 643
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "![ \t]*")
  (make-local-variable 'comment-start)
644
  (setq comment-start "C")
Jim Blandy's avatar
Jim Blandy committed
645 646 647 648 649 650
  (make-local-variable 'require-final-newline)
  (setq require-final-newline t)
  (make-local-variable 'abbrev-all-caps)
  (setq abbrev-all-caps t)
  (make-local-variable 'indent-tabs-mode)
  (setq indent-tabs-mode nil)
651
;;;(setq abbrev-mode t) ; ?? (abbrev-mode 1) instead??
652
  (set (make-local-variable 'fill-column) 72)
Jim Blandy's avatar
Jim Blandy committed
653 654 655
  (use-local-map fortran-mode-map)
  (setq mode-name "Fortran")
  (setq major-mode 'fortran-mode)
656 657 658 659
  (make-local-variable 'fortran-comment-line-extra-indent)
  (make-local-variable 'fortran-minimum-statement-indent-fixed)
  (make-local-variable 'fortran-minimum-statement-indent-tab)
  (make-local-variable 'fortran-column-ruler-fixed)
Dave Love's avatar
Dave Love committed
660
  (make-local-variable 'fortran-column-ruler-tab)
661 662
  (setq fortran-tab-mode-string " TAB-format")
  (setq indent-tabs-mode (fortran-analyze-file-format))
663
  (setq imenu-case-fold-search t)
664
  (setq imenu-generic-expression fortran-imenu-generic-expression)
665
  (setq imenu-syntax-alist '(("_$" . "w")))
666 667 668 669 670 671 672
  (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
  (set (make-local-variable 'indent-line-function) 'fortran-indent-line)
  (set (make-local-variable 'indent-region-function)
       (lambda (start end)
         (let (fortran-blink-matching-if ; avoid blinking delay
               indent-region-function)
           (indent-region start end nil))))
673 674 675 676
  (set (make-local-variable 'beginning-of-defun-function)
       #'fortran-beginning-of-subprogram)
  (set (make-local-variable 'end-of-defun-function)
       #'fortran-end-of-subprogram)
677 678
  (set (make-local-variable 'add-log-current-defun-function)
       #'fortran-current-defun)
Jim Blandy's avatar
Jim Blandy committed
679 680
  (run-hooks 'fortran-mode-hook))

681
(defun fortran-comment-indent-function ()
Jim Blandy's avatar
Jim Blandy committed
682 683 684 685 686 687 688 689 690
  (save-excursion
    (skip-chars-backward " \t")
    (max (+ 1 (current-column))
	 comment-column)))

(defun fortran-indent-comment ()
  "Align or create comment on current line.
Existing comments of all types are recognized and aligned.
If the line has no comment, a side-by-side comment is inserted and aligned
691
if the value of  `comment-start'  is not nil.
Jim Blandy's avatar
Jim Blandy committed
692 693 694 695 696
Otherwise, a separate-line comment is inserted, on this line
or on a new line inserted before this line if this line is not blank."
  (interactive)
  (beginning-of-line)
  ;; Recognize existing comments of either kind.
697
  (cond ((looking-at fortran-comment-line-start-skip)
Jim Blandy's avatar
Jim Blandy committed
698
	 (fortran-indent-line))
699
	((fortran-find-comment-start-skip) ; catches any inline comment and
Richard M. Stallman's avatar
Richard M. Stallman committed
700 701 702
					; leaves point after comment-start-skip
	 (if comment-start-skip
	     (progn (goto-char (match-beginning 0))
703
		    (if (not (= (current-column) (fortran-comment-indent-function)))
Richard M. Stallman's avatar
Richard M. Stallman committed
704
			(progn (delete-horizontal-space)
705
			       (indent-to (fortran-comment-indent-function)))))
Richard M. Stallman's avatar
Richard M. Stallman committed
706
	   (end-of-line)))        ; otherwise goto end of line or sth else?
Jim Blandy's avatar
Jim Blandy committed
707 708 709 710 711 712
	;; No existing comment.
	;; If side-by-side comments are defined, insert one,
	;; unless line is now blank.
	((and comment-start (not (looking-at "^[ \t]*$")))
	 (end-of-line)
	 (delete-horizontal-space)
713
	 (indent-to (fortran-comment-indent-function))
Jim Blandy's avatar
Jim Blandy committed
714 715 716 717 718 719
	 (insert comment-start))
	;; Else insert separate-line comment, making a new line if nec.
	(t
	 (if (looking-at "^[ \t]*$")
	     (delete-horizontal-space)
	   (beginning-of-line)
720
	   (insert ?\n)
Jim Blandy's avatar
Jim Blandy committed
721
	   (forward-char -1))
722
	 (insert fortran-comment-line-start)
Jim Blandy's avatar
Jim Blandy committed
723 724
	 (insert-char (if (stringp fortran-comment-indent-char)
			  (aref fortran-comment-indent-char 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
725
			fortran-comment-indent-char)
726
		      (- (fortran-calculate-indent) (current-column))))))
Jim Blandy's avatar
Jim Blandy committed
727 728 729

(defun fortran-comment-region (beg-region end-region arg)
  "Comments every line in the region.
730
Puts `fortran-comment-region' at the beginning of every line in the region.
731
BEG-REGION and END-REGION are args which specify the region boundaries.
Jim Blandy's avatar
Jim Blandy committed
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
With non-nil ARG, uncomments the region."
  (interactive "*r\nP")
  (let ((end-region-mark (make-marker)) (save-point (point-marker)))
    (set-marker end-region-mark end-region)
    (goto-char beg-region)
    (beginning-of-line)
    (if (not arg)			;comment the region
	(progn (insert fortran-comment-region)
	       (while (and  (= (forward-line 1) 0)
			    (< (point) end-region-mark))
		 (insert fortran-comment-region)))
      (let ((com (regexp-quote fortran-comment-region))) ;uncomment the region
	(if (looking-at com)
	    (delete-region (point) (match-end 0)))
	(while (and  (= (forward-line 1) 0)
		     (< (point) end-region-mark))
	  (if (looking-at com)
	      (delete-region (point) (match-end 0))))))
    (goto-char save-point)
    (set-marker end-region-mark nil)
    (set-marker save-point nil)))

(defun fortran-abbrev-start ()
755
  "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
Jim Blandy's avatar
Jim Blandy committed
756 757 758 759
Any other key combination is executed normally."
  (interactive)
  (let (c)
    (insert last-command-char)
760 761
    (if (or (eq (setq c (read-event)) ??)    ;insert char if not equal to `?'
	    (eq c help-char))
Jim Blandy's avatar
Jim Blandy committed
762
	(fortran-abbrev-help)
Jim Blandy's avatar
Jim Blandy committed
763
      (setq unread-command-events (list c)))))
Jim Blandy's avatar
Jim Blandy committed
764 765 766 767 768

(defun fortran-abbrev-help ()
  "List the currently defined abbrevs in Fortran mode."
  (interactive)
  (message "Listing abbrev table...")
769
  (display-buffer (fortran-prepare-abbrev-list-buffer))
Jim Blandy's avatar
Jim Blandy committed
770 771
  (message "Listing abbrev table...done"))

772 773 774 775
(defun fortran-prepare-abbrev-list-buffer ()
  (save-excursion
    (set-buffer (get-buffer-create "*Abbrevs*"))
    (erase-buffer)
776
    (insert-abbrev-table-description 'fortran-mode-abbrev-table t)
777 778 779 780 781
    (goto-char (point-min))
    (set-buffer-modified-p nil)
    (edit-abbrevs-mode))
  (get-buffer-create "*Abbrevs*"))

Jim Blandy's avatar
Jim Blandy committed
782
(defun fortran-column-ruler ()
783
  "Insert a column ruler momentarily above current line, till next keystroke.
784 785
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.
Jim Blandy's avatar
Jim Blandy committed
786 787
The key typed is executed unless it is SPC."
  (interactive)
788
  (momentary-string-display
789 790 791 792
   (if indent-tabs-mode
       fortran-column-ruler-tab
     fortran-column-ruler-fixed)
   (save-excursion
793
     (beginning-of-line)
794 795
     (if (eq (window-start (selected-window))
	     (window-point (selected-window)))
796
	 (line-beginning-position 2)
797
       (point)))
Jim Blandy's avatar
Jim Blandy committed
798 799 800
   nil "Type SPC or any command to erase ruler."))

(defun fortran-window-create ()
801
  "Make the window 72 columns wide.
Christopher Zaborsky's avatar
Christopher Zaborsky committed
802
See also `fortran-window-create-momentarily'."
Jim Blandy's avatar
Jim Blandy committed
803 804 805 806
  (interactive)
  (condition-case error
      (progn
	(let ((window-min-width 2))
807 808
	  (if (< (window-width) (frame-width))
	      (enlarge-window-horizontally (- (frame-width)
Jim Blandy's avatar
Jim Blandy committed
809
					      (window-width) 1)))
810 811 812 813 814
	  (let* ((window-edges (window-edges))
		 (scroll-bar-width (- (nth 2 window-edges)
				      (car window-edges)
				      (window-width))))
	    (split-window-horizontally (+ 72 scroll-bar-width)))
Jim Blandy's avatar
Jim Blandy committed
815 816 817
	  (other-window 1)
	  (switch-to-buffer " fortran-window-extra" t)
	  (select-window (previous-window))))
Richard M. Stallman's avatar
Richard M. Stallman committed
818
    (error (message "No room for Fortran window.")
Jim Blandy's avatar
Jim Blandy committed
819 820 821
	   'error)))

(defun fortran-window-create-momentarily (&optional arg)
822
  "Momentarily make the window 72 columns wide.
Jim Blandy's avatar
Jim Blandy committed
823
Optional ARG non-nil and non-unity disables the momentary feature.
Christopher Zaborsky's avatar
Christopher Zaborsky committed
824
See also `fortran-window-create'."
Jim Blandy's avatar
Jim Blandy committed
825 826 827 828 829 830
  (interactive "p")
  (if (or (not arg)
	  (= arg 1))
      (save-window-excursion
	(if (not (equal (fortran-window-create) 'error))
	    (progn (message "Type SPC to continue editing.")
831
		   (let ((char (read-event)))
Jim Blandy's avatar
Jim Blandy committed
832
		     (or (equal char (string-to-char " "))
Jim Blandy's avatar
Jim Blandy committed
833
			 (setq unread-command-events (list char)))))))
Jim Blandy's avatar
Jim Blandy committed
834 835 836 837 838 839
    (fortran-window-create)))

(defun fortran-split-line ()
  "Break line at point and insert continuation marker and alignment."
  (interactive)
  (delete-horizontal-space)
840 841 842 843
  (if (save-excursion
	(beginning-of-line)
	(looking-at fortran-comment-line-start-skip))
      (insert ?\n fortran-comment-line-start ? )
844
    (if indent-tabs-mode
845
	(insert ?\n ?\t (fortran-numerical-continuation-char))
846 847 848 849 850 851 852 853
      (insert "\n " fortran-continuation-string))) ; Space after \n important
  (fortran-indent-line))		; when the cont string is C, c or *.

(defun fortran-remove-continuation ()
  (if (looking-at "\\(     [^ 0\n]\\|\t[1-9]\\|&\\)")
      (progn (replace-match "")
	     (delete-indentation)
	     t)))
Jim Blandy's avatar
Jim Blandy committed
854

Dave Love's avatar
Dave Love committed
855 856 857 858 859 860
(defun fortran-join-line (arg)
  "Join current line to the previous one and re-indent.
With a prefix argument, repeat this operation that many times.
If the prefix argument ARG is negative, join the next -ARG lines.
Continuation lines are correctly handled."
  (interactive "*p")
861
  (save-excursion
Dave Love's avatar
Dave Love committed
862 863 864 865 866 867 868 869
    (when (> 0 arg)
      (setq arg (- arg))
      (forward-line arg))
    (while (not (zerop arg))
      (beginning-of-line)
      (or (fortran-remove-continuation)
          (delete-indentation))
      (setq arg (1- arg)))
870 871
    (fortran-indent-line)))

Jim Blandy's avatar
Jim Blandy committed
872
(defun fortran-numerical-continuation-char ()
873
  "Return a digit for tab-digit style of continuation lines.
Jim Blandy's avatar
Jim Blandy committed
874 875 876 877 878 879 880 881
If, previous line is a tab-digit continuation line, returns that digit
plus one.  Otherwise return 1.  Zero not allowed."
  (save-excursion
    (forward-line -1)
    (if (looking-at "\t[1-9]")
	(+ ?1 (% (- (char-after (+ (point) 1)) ?0) 9))
      ?1)))

882
(put 'fortran-electric-line-number 'delete-selection t)
Jim Blandy's avatar
Jim Blandy committed
883 884
(defun fortran-electric-line-number (arg)
  "Self insert, but if part of a Fortran line number indent it automatically.
885
Auto-indent does not happen if a numeric ARG is used."
Jim Blandy's avatar
Jim Blandy committed
886 887
  (interactive "P")
  (if (or arg (not fortran-electric-line-number))
888
      (if arg
Richard M. Stallman's avatar
Richard M. Stallman committed
889
	  (self-insert-command (prefix-numeric-value arg))
Jim Blandy's avatar
Jim Blandy committed
890 891 892 893
	(self-insert-command 1))
    (if (or (and (= 5 (current-column))
		 (save-excursion
		   (beginning-of-line)
894
		   (looking-at "     "))) ;In col 5 with only spaces to left.
895
	    (and (= (if indent-tabs-mode
896 897
			fortran-minimum-statement-indent-tab
		      fortran-minimum-statement-indent-fixed) (current-column))
898 899
		 (eq ?\t (char-after (line-beginning-position))) ;In col 8
					; with a single tab to the left.
Jim Blandy's avatar
Jim Blandy committed
900 901
		 (not (or (eq last-command 'fortran-indent-line)
			  (eq last-command
902
			      'fortran-indent-new-line))))
Jim Blandy's avatar
Jim Blandy committed
903 904
	    (save-excursion
	      (re-search-backward "[^ \t0-9]"
905
				  (line-beginning-position)
906 907
				  t))	;not a line number
	    (looking-at "[0-9]"))	;within a line number
Richard M. Stallman's avatar
Richard M. Stallman committed
908
	(self-insert-command (prefix-numeric-value arg))
Jim Blandy's avatar
Jim Blandy committed
909 910 911 912
      (skip-chars-backward " \t")
      (insert last-command-char)
      (fortran-indent-line))))

913
(defvar fortran-end-prog-re1
914
  "end\
Dave Love's avatar
Dave Love committed
915 916
\\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
\\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?")
917
(defvar fortran-end-prog-re
Dave Love's avatar
Dave Love committed
918 919
  (concat "^[ \t0-9]*" fortran-end-prog-re1)
  "Regexp possibly marking subprogram end.")
920

Dave Love's avatar
Dave Love committed
921 922 923 924 925
(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
  ;; match of whitespace, avoiding possible column 73+ stuff.
  (save-match-data
926
    (string-match "^\\s-*\\(\\'\\|\\s<\\)"
Dave Love's avatar
Dave Love committed
927 928 929 930 931 932
		  (buffer-substring (match-end 0)
				    (min (line-end-position)
					 (+ 72 (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.
933
(defun fortran-beginning-of-subprogram ()
Richard M. Stallman's avatar
Richard M. Stallman committed
934
  "Moves point to the beginning of the current Fortran subprogram."
Jim Blandy's avatar
Jim Blandy committed
935
  (interactive)
936 937 938 939 940 941 942 943
  (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)))))
Jim Blandy's avatar
Jim Blandy committed
944

945
(defun fortran-end-of-subprogram ()
Richard M. Stallman's avatar
Richard M. Stallman committed
946
  "Moves point to the end of the current Fortran subprogram."
Jim Blandy's avatar
Jim Blandy committed
947
  (interactive)
948 949 950 951 952 953 954 955 956 957 958 959 960 961
  (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)
	(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)))))
Jim Blandy's avatar
Jim Blandy committed
962 963

(defun fortran-previous-statement ()
Richard M. Stallman's avatar
Richard M. Stallman committed
964 965
  "Moves point to beginning of the previous Fortran statement.
Returns `first-statement' if that statement is the first
Jim Blandy's avatar
Jim Blandy committed
966 967 968 969 970
non-comment Fortran statement in the file, and nil otherwise."
  (interactive)
  (let (not-first-statement continue-test)
    (beginning-of-line)
    (setq continue-test
Richard M. Stallman's avatar
Richard M. Stallman committed
971
	  (and
972
	   (not (looking-at fortran-comment-line-start-skip))
Richard M. Stallman's avatar
Richard M. Stallman committed
973
	   (or (looking-at
Jim Blandy's avatar
Jim Blandy committed
974
	        (concat "[ \t]*" (regexp-quote fortran-continuation-string)))
975
	       (looking-at "     [^ 0\n]\\|\t[1-9]"))))
Jim Blandy's avatar
Jim Blandy committed
976
    (while (and (setq not-first-statement (= (forward-line -1) 0))
977 978
		(or (looking-at fortran-comment-line-start-skip)
		    (looking-at "[ \t]*$\\|     [^ 0\n]\\|\t[1-9]")
Jim Blandy's avatar
Jim Blandy committed
979 980 981 982
		    (looking-at (concat "[ \t]*"  comment-start-skip)))))
    (cond ((and continue-test
		(not not-first-statement))
	   (message "Incomplete continuation statement."))
983
	  (continue-test
Jim Blandy's avatar
Jim Blandy committed
984 985 986 987 988
	   (fortran-previous-statement))
	  ((not not-first-statement)
	   'first-statement))))

(defun fortran-next-statement ()
Richard M. Stallman's avatar
Richard M. Stallman committed
989
  "Moves point to beginning of the next Fortran statement.
Jim Blandy's avatar
Jim Blandy committed
990 991 992 993 994
Returns `last-statement' if that statement is the last
non-comment Fortran statement in the file, and nil otherwise."
  (interactive)
  (let (not-last-statement)
    (beginning-of-line)
Richard M. Stallman's avatar
Richard M. Stallman committed
995 996 997
    (while (and (setq not-last-statement
		      (and (= (forward-line 1) 0)
			   (not (eobp))))
998 999
 		(or (looking-at fortran-comment-line-start-skip)
 		    (looking-at "[ \t]*$\\|     [^ 0\n]\\|\t[1-9]")
Jim Blandy's avatar
Jim Blandy committed
1000 1001 1002 1003
 		    (looking-at (concat "[ \t]*"  comment-start-skip)))))
    (if (not not-last-statement)
 	'last-statement)))

1004 1005 1006
(defun fortran-blink-match (regex keyword find-begin)
  "From a line matching REGEX, blink matching KEYWORD statement line.
Use function FIND-BEGIN to match it."
1007
  (let ((top-of-window (window-start))
1008
	(end-point (point))
1009
	(case-fold-search t)
1010
	matching
1011
	message)
1012 1013 1014 1015
    (if (save-excursion
	  (beginning-of-line)
	  (skip-chars-forward " \t0-9")
	  (looking-at regex))
Jim Blandy's avatar
Jim Blandy committed
1016
	(progn
1017 1018 1019
          (if (not (setq matching (funcall find-begin)))
              (setq message (concat "No matching " keyword "."))
            (if (< matching top-of-window)
1020
                (save-excursion
1021
                  (goto-char matching)
1022 1023 1024
                  (beginning-of-line)
                  (setq message
                        (concat "Matches "
1025 1026
                                (buffer-substring (point)
						  (line-end-position)))))))
Jim Blandy's avatar
Jim Blandy committed
1027
	  (if message
Richard M. Stallman's avatar
Richard M. Stallman committed
1028
	      (message "%s" message)
1029
	    (goto-char matching)
Jim Blandy's avatar
Jim Blandy committed
1030
	    (sit-for 1)
1031 1032 1033 1034 1035 1036
	    (goto-char end-point))))))

(defun fortran-blink-matching-if ()
  "From an ENDIF or ELSE statement, blink the matching IF statement."
  (fortran-blink-match "e\\(nd[ \t]*if\\|lse\\([ \t]*if\\)?\\)\\b"
		       "if" #'fortran-beginning-i