Sync to HEAD
[bpt/emacs.git] / lisp / progmodes / fortran.el
CommitLineData
e5167999
ER
1;;; fortran.el --- Fortran mode for GNU Emacs
2
6b61353c 3;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 01, 03, 04
315aa1de 4;; Free Software Foundation, Inc.
9750e079 5
e5167999 6;; Author: Michael D. Prange <prange@erl.mit.edu>
367e10df 7;; Maintainer: Glenn Morris <gmorris@ast.cam.ac.uk>
5b04210c 8;; Keywords: fortran, languages
1a06eabd 9
e5167999
ER
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
e5167999
ER
26
27;;; Commentary:
28
7977773d
DL
29;; This mode is documented in the Emacs manual.
30;;
31;; Note that it is for editing Fortran77 or Fortran90 fixed source
45cf60ae 32;; form. For editing Fortran 90 free format source, use `f90-mode'
b2523604
DL
33;; (f90.el). It is meant to support the GNU Fortran language
34;; implemented by g77 (its extensions to Fortran77 and
35;; interpretations, e.g. of blackslash in strings).
7977773d
DL
36
37;;; History:
38
39;; Fortran mode was upgraded by Stephen A. Wood (saw@cebaf.gov).
23029d77
JB
40
41;; We acknowledge many contributions and valuable suggestions by
b8cbdf43 42;; Lawrence R. Dodd, Ralf Fassel, Ralph Finch, Stephen Gildea,
60db3594 43;; Dr. Anil Gokhale, Ulrich Mueller, Mark Neale, Eric Prestemon,
b8cbdf43
RS
44;; Gary Sabot and Richard Stallman.
45
e5167999
ER
46;;; Code:
47
45cf60ae 48;; Todo:
1eb6bf70 49
315aa1de 50;; * Tidy it all up (more)!
1eb6bf70
DL
51;; * Implement insertion and removal of statement continuations in
52;; mixed f77/f90 style, with the first `&' past column 72 and the
53;; second in column 6.
b2523604 54;; * Support any other extensions to f77 grokked by GNU Fortran I've missed.
1eb6bf70 55
5b04210c 56(eval-when-compile ; silence compiler
be35ca9f 57 (defvar dabbrev-case-fold-search)
5b04210c
GM
58 (defvar imenu-case-fold-search)
59 (defvar imenu-syntax-alist))
60
61
fcad5199 62(defgroup fortran nil
5b04210c
GM
63 "Major mode for editing fixed format Fortran code."
64 :link '(custom-manual "(emacs)Fortran")
fcad5199
RS
65 :group 'languages)
66
67(defgroup fortran-indent nil
5b04210c 68 "Indentation variables in Fortran mode."
fcad5199 69 :prefix "fortran-"
5b04210c 70 :group 'fortran)
fcad5199
RS
71
72(defgroup fortran-comment nil
5b04210c 73 "Comment-handling variables in Fortran mode."
fcad5199 74 :prefix "fortran-"
5b04210c 75 :group 'fortran)
fcad5199
RS
76
77
3dd63760 78;;;###autoload
fcad5199 79(defcustom fortran-tab-mode-default nil
e80f2147 80 "*Default tabbing/carriage control style for empty files in Fortran mode.
5b04210c 81A non-nil value specifies tab-digit style of continuation control.
e80f2147 82A value of nil specifies that continuation lines are marked
fcad5199 83with a character in column 6."
5b04210c 84 :type 'boolean
fcad5199 85 :group 'fortran-indent)
e80f2147 86
a7113309
GM
87(defcustom fortran-tab-mode-string "/t"
88 "*String to appear in mode line in TAB format buffers."
5b04210c 89 :type 'string
fcad5199 90 :group 'fortran-indent)
5b04210c 91
fcad5199
RS
92(defcustom fortran-do-indent 3
93 "*Extra indentation applied to DO blocks."
5b04210c 94 :type 'integer
fcad5199
RS
95 :group 'fortran-indent)
96
97(defcustom fortran-if-indent 3
98 "*Extra indentation applied to IF blocks."
5b04210c 99 :type 'integer
fcad5199
RS
100 :group 'fortran-indent)
101
102(defcustom fortran-structure-indent 3
103 "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
5b04210c 104 :type 'integer
fcad5199
RS
105 :group 'fortran-indent)
106
107(defcustom fortran-continuation-indent 5
5b04210c
GM
108 "*Extra indentation applied to continuation lines."
109 :type 'integer
fcad5199
RS
110 :group 'fortran-indent)
111
112(defcustom fortran-comment-indent-style 'fixed
7977773d 113 "*How to indent comments.
5b04210c
GM
114nil forces comment lines not to be touched;
115`fixed' indents to `fortran-comment-line-extra-indent' columns beyond
116 `fortran-minimum-statement-indent-fixed' (if `indent-tabs-mode' nil), or
117 `fortran-minimum-statement-indent-tab' (if `indent-tabs-mode' non-nil);
ff451e17
SM
118`relative' indents to current Fortran indentation plus
119 `fortran-comment-line-extra-indent'."
5b04210c 120 :type '(radio (const :tag "Untouched" nil) (const fixed) (const relative))
fcad5199
RS
121 :group 'fortran-indent)
122
123(defcustom fortran-comment-line-extra-indent 0
124 "*Amount of extra indentation for text within full-line comments."
5b04210c 125 :type 'integer
fcad5199
RS
126 :group 'fortran-indent
127 :group 'fortran-comment)
128
68ca306c
DL
129(defcustom fortran-comment-line-start "C"
130 "*Delimiter inserted to start new full-line comment.
131You might want to change this to \"*\", for instance."
7dae727d 132 :version "21.1"
5b04210c
GM
133 :type 'string
134 :group 'fortran-comment)
fcad5199 135
68ca306c
DL
136;; This used to match preprocessor lines too, but that messes up
137;; filling and doesn't seem to be necessary.
138(defcustom fortran-comment-line-start-skip
8b31236d 139 "^[CcDd*!]\\(\\([^ \t\n]\\)\\2+\\)?[ \t]*"
fcad5199 140 "*Regexp to match the start of a full-line comment."
7dae727d 141 :version "21.1"
5b04210c
GM
142 :type 'regexp
143 :group 'fortran-comment)
fcad5199 144
5a73972b 145(defcustom fortran-directive-re
8edfcc7d 146 "^[ \t]*#.*"
5a73972b
GM
147 "*Regexp to match a directive line.
148The matching text will be fontified with `font-lock-keyword-face'.
149The matching line will be given zero indentation."
89e7ad59 150 :version "21.4"
5b04210c
GM
151 :type 'regexp
152 :group 'fortran-indent)
8edfcc7d 153
fcad5199
RS
154(defcustom fortran-minimum-statement-indent-fixed 6
155 "*Minimum statement indentation for fixed format continuation style."
5b04210c 156 :type 'integer
fcad5199
RS
157 :group 'fortran-indent)
158
159(defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
160 "*Minimum statement indentation for TAB format continuation style."
5b04210c 161 :type 'integer
fcad5199 162 :group 'fortran-indent)
3dd63760
JB
163
164;; Note that this is documented in the v18 manuals as being a string
165;; of length one rather than a single character.
166;; The code in this file accepts either format for compatibility.
fcad5199 167(defcustom fortran-comment-indent-char " "
3dd63760 168 "*Single-character string inserted for Fortran comment indentation.
fcad5199 169Normally a space."
5b04210c 170 :type 'string
fcad5199 171 :group 'fortran-comment)
3dd63760 172
fcad5199 173(defcustom fortran-line-number-indent 1
3dd63760 174 "*Maximum indentation for Fortran line numbers.
fcad5199 1755 means right-justify them within their five-column field."
5b04210c 176 :type 'integer
fcad5199 177 :group 'fortran-indent)
3dd63760 178
fcad5199
RS
179(defcustom fortran-check-all-num-for-matching-do nil
180 "*Non-nil causes all numbered lines to be treated as possible DO loop ends."
5b04210c 181 :type 'boolean
fcad5199 182 :group 'fortran)
3dd63760 183
fcad5199 184(defcustom fortran-blink-matching-if nil
5b04210c 185 "*Non-nil causes \\[fortran-indent-line] on ENDIF to blink on matching IF.
fcad5199 186Also, from an ENDDO statement blink on matching DO [WHILE] statement."
5b04210c 187 :type 'boolean
fcad5199 188 :group 'fortran)
3dd63760 189
fcad5199 190(defcustom fortran-continuation-string "$"
b8cbdf43 191 "*Single-character string used for Fortran continuation lines.
3dd63760
JB
192In fixed format continuation style, this character is inserted in
193column 6 by \\[fortran-split-line] to begin a continuation line.
5b04210c
GM
194Also, if \\[fortran-indent-line] finds this at the beginning of a
195line, it will convert the line into a continuation line of the
196appropriate style. Normally $."
197 :type 'string
fcad5199 198 :group 'fortran)
3dd63760 199
fcad5199 200(defcustom fortran-comment-region "c$$$"
1eb6bf70
DL
201 "*String inserted by \\[fortran-comment-region] at start of each \
202line in region."
5b04210c 203 :type 'string
fcad5199 204 :group 'fortran-comment)
3dd63760 205
fcad5199 206(defcustom fortran-electric-line-number t
5b04210c
GM
207 "*Non-nil causes line numbers to be moved to the correct column as typed."
208 :type 'boolean
fcad5199 209 :group 'fortran)
3dd63760 210
5b04210c 211(defcustom fortran-column-ruler-fixed
23029d77 212 "0 4 6 10 20 30 40 5\
7977773d 2130 60 70\n\
f022dd89
SM
214\[ ]|{ | | | | | | | | \
215\| | | | |}\n"
dc6579ac 216 "String displayed above current line by \\[fortran-column-ruler].
5b04210c
GM
217This variable is used in fixed format mode.
218See the variable `fortran-column-ruler-tab' for TAB format mode."
219 :type 'string
220 :group 'fortran)
23029d77 221
5b04210c 222(defcustom fortran-column-ruler-tab
23029d77 223 "0 810 20 30 40 5\
7977773d 2240 60 70\n\
f022dd89
SM
225\[ ]| { | | | | | | | | \
226\| | | | |}\n"
dc6579ac 227 "String displayed above current line by \\[fortran-column-ruler].
5b04210c
GM
228This variable is used in TAB format mode.
229See the variable `fortran-column-ruler-fixed' for fixed format mode."
230 :type 'string
231 :group 'fortran)
3dd63760 232
5b04210c
GM
233(defcustom fortran-analyze-depth 100
234 "Number of lines to scan to identify fixed or TAB format style."
235 :type 'integer
236 :group 'fortran)
3dd63760 237
fcad5199 238(defcustom fortran-break-before-delimiters t
5b04210c 239 "*Non-nil causes filling to break lines before delimiters.
6b61353c 240Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
5b04210c 241 :type 'boolean
fcad5199 242 :group 'fortran)
b8cbdf43 243
6b61353c
KH
244(defconst fortran-break-delimiters-re "[-+*/><=, \t]"
245 "Regexp matching delimiter characters at which lines may be broken.
246There are certain tokens comprised entirely of characters
247matching this regexp that should not be split, and these are
248specified by the constant `fortran-no-break-re'.")
249
250;; The ">=", etc F77 extensions are supported by g77.
251(defconst fortran-no-break-re
252 (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=") 'paren)
253 "Regexp specifying where not to break lines when filling.
254This regexp matches certain tokens comprised entirely of
255characters matching the regexp `fortran-break-delimiters-re' that should
256not be split by filling. Each element is assumed to be two
257characters long.")
258
5b04210c
GM
259(defcustom fortran-mode-hook nil
260 "Hook run when entering Fortran mode."
261 :type 'hook
262 :group 'fortran)
3dd63760 263
5b04210c
GM
264\f
265(defvar fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
266 "Regexp matching the start of an IF statement.")
267
268(defvar fortran-end-prog-re1
269 "end\
270\\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
271\\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?"
272 "Regexp possibly matching the end of a subprogram.")
563f09b5 273
5b04210c
GM
274(defvar fortran-end-prog-re
275 (concat "^[ \t0-9]*" fortran-end-prog-re1)
276 "Regexp possibly matching the end of a subprogram, from the line start.
277See also `fortran-end-prog-re1'.")
278
279(defconst fortran-type-types
280 (concat "\\<"
281 (mapconcat 'identity ; " " -> "[ \t]*"
282 (split-string
283 (regexp-opt
284 (let ((simple-types
285 '("character" "byte" "integer" "logical"
286 "none" "real" "complex"
287 "double precision" "double complex"))
288 (structured-types '("structure" "union" "map"))
289 (other-types '("record" "dimension"
290 "parameter" "common" "save"
291 "external" "intrinsic" "data"
292 "equivalence")))
293 (append
294 (mapcar (lambda (x) (concat "implicit " x))
295 simple-types)
296 simple-types
297 (mapcar (lambda (x) (concat "end " x))
298 structured-types)
299 structured-types
300 other-types)) 'paren))
301 "[ \t]*") "\\>")
302 "Regexp matching Fortran types.")
303
304(defvar fortran-font-lock-keywords-1
305 ;; Program, subroutine and function declarations, plus calls.
306 '(("\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|\
307program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
308 (1 font-lock-keyword-face)
309 (2 font-lock-function-name-face nil t)))
f3d4eb7b 310 "Subdued level highlighting for Fortran mode.")
563f09b5 311
5b04210c
GM
312(defvar fortran-font-lock-keywords-2
313 (append fortran-font-lock-keywords-1
314 (list
315 ;; Fontify all type specifiers (must be first - see below).
316 (cons fortran-type-types 'font-lock-type-face)
317 ;; Builtin keywords (except logical, do and goto - see below).
318 (concat "\\<" (regexp-opt
319 '("continue" "format" "end" "enddo"
320 "if" "then" "else" "endif" "elseif"
321 "while" "inquire" "stop" "return"
322 "include" "open" "close" "read"
323 "write" "format" "print" "select" "case"
324 "cycle" "exit" "rewind" "backspace")
325 'paren) "\\>")
326 ;; Builtin operators.
327 (concat "\\." (regexp-opt
328 '("and" "or" "not" "lt" "le" "eq" "ge"
329 "gt" "ne" "true" "false")
330 'paren) "\\.")
331 ;; do/goto keywords and targets, and goto tags.
332 '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
333 (1 font-lock-keyword-face)
334 (2 font-lock-constant-face nil t))
335 '("^ *\\([0-9]+\\)" . font-lock-constant-face)))
f408b027
SM
336 "Medium level highlighting for Fortran mode.")
337
5b04210c
GM
338(defvar fortran-font-lock-keywords-3
339 (append
340 fortran-font-lock-keywords-1
341 ;; All type specifiers plus their declared items.
342 (list
343 (list (concat fortran-type-types "[ \t(/]*\\(*\\)?")
344 ;; Type specifier.
345 '(1 font-lock-type-face)
346 ;; Declaration item (or just /.../ block name).
347 `(font-lock-match-c-style-declaration-item-and-skip-to-next
348 ;; Start after any *(...) expression.
349 (condition-case nil
350 (and (match-beginning ,(1+ (regexp-opt-depth
351 fortran-type-types)))
352 (forward-sexp)
353 (forward-sexp))
354 (error nil))
355 ;; No need to clean up.
356 nil
357 ;; Fontify as a variable name, functions fontified elsewhere.
358 (1 font-lock-variable-name-face nil t))))
359 ;; Things extra to `fortran-font-lock-keywords-3' (must be done first).
360 (list
361 ;; Goto-like `err=label'/`end=label' in read/write statements.
362 '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?"
363 (1 font-lock-keyword-face) (4 font-lock-constant-face nil t))
364 ;; Standard continuation character and in a TAB-formatted line.
365 '("^ \\{5\\}\\([^ 0\n]\\)" 1 font-lock-string-face)
366 '("^\t\\([1-9]\\)" 1 font-lock-string-face))
367 `((,fortran-directive-re (0 font-lock-keyword-face t)))
368 ;; `fortran-font-lock-keywords-2' without types (see above).
369 (cdr (nthcdr (length fortran-font-lock-keywords-1)
370 fortran-font-lock-keywords-2)))
f408b027
SM
371 "Gaudy level highlighting for Fortran mode.")
372
5b04210c
GM
373;; Comments are real pain in Fortran because there is no way to
374;; represent the standard comment syntax in an Emacs syntax table.
375;; (We can do so for F90-style). Therefore an unmatched quote in a
376;; standard comment will throw fontification off on the wrong track.
377;; So we do syntactic fontification with regexps.
378(defvar fortran-font-lock-syntactic-keywords
379 '(("^[cd\\*]" 0 (11))
380 ("^[^cd\\*\t\n].\\{71\\}\\([^\n]+\\)" 1 (11)))
f687a879
DL
381 "`font-lock-syntactic-keywords' for Fortran.
382These get fixed-format comments fontified.")
0f1057e9 383
f3d4eb7b
SM
384(defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
385 "Default expressions to highlight in Fortran mode.")
5b04210c 386
9645c179 387(defvar fortran-imenu-generic-expression
240e9cda
DL
388 ;; These patterns could be confused by sequence nos. in cols 72+ and
389 ;; don't allow continuations everywhere.
7977773d
DL
390 (list
391 (list
392 nil
a8189dfe
DL
393 ;; [This will be fooled by `end function' allowed by G77. Also,
394 ;; it assumes sensible whitespace is employed.]
395 (concat
396 ;; leading whitespace:
397 "^\\s-+\\("
398 ;; function declaration with optional type, e.g. `real',
399 ;; `real*4', character(*), `double precision':
400 "\\(\\sw\\|\\s-\\|[*()+]\\)*"
401 "\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)"
402 ;; Possible statement continuation:
403 "[ \t" fortran-continuation-string "]+"
404 ;; Variable to index:
405 "\\(\\sw+\\)")
7977773d 406 3)
5b04210c
GM
407 ;; Un-named block data.
408 '(nil "^\\s-+\\(block\\s-*data\\)\\s-*$" 1))
409 "Value for `imenu-generic-expression' in Fortran mode.")
410
411\f
412(defvar fortran-mode-syntax-table
413 (let ((table (make-syntax-table)))
414 ;; We might like `;' to be punctuation (g77 multi-statement
415 ;; lines), but that screws abbrevs.
416 (modify-syntax-entry ?\; "w" table)
417 (modify-syntax-entry ?\r " " table)
418 (modify-syntax-entry ?+ "." table)
419 (modify-syntax-entry ?- "." table)
420 (modify-syntax-entry ?= "." table)
421 (modify-syntax-entry ?* "." table)
422 (modify-syntax-entry ?/ "." table)
423 (modify-syntax-entry ?\' "\"" table)
424 (modify-syntax-entry ?\" "\"" table)
425 ;; Consistent with GNU Fortran -- see the manual.
426 (modify-syntax-entry ?\\ "\\" table)
427 ;; This might be better as punctuation, as for C, but this way you
428 ;; can treat floating-point numbers as symbols.
429 (modify-syntax-entry ?. "_" table) ; e.g. `a.ne.b'
430 (modify-syntax-entry ?_ "_" table)
431 (modify-syntax-entry ?$ "_" table) ; esp. VMSisms
432 (modify-syntax-entry ?\! "<" table)
433 (modify-syntax-entry ?\n ">" table)
434 table)
435 "Syntax table used in Fortran mode.")
f408b027 436
f6bf87c5
NR
437(defvar fortran-gud-syntax-table
438 (let ((st (make-syntax-table fortran-mode-syntax-table)))
439 (modify-syntax-entry ?\n "." st)
440 st)
441 "Syntax table used to parse Fortran expressions for printing in GUD.")
442
7a7db8e5 443(defvar fortran-mode-map
315aa1de 444 (let ((map (make-sparse-keymap)))
5b04210c
GM
445 (define-key map ";" 'fortran-abbrev-start)
446 (define-key map "\C-c;" 'fortran-comment-region)
447 (define-key map "\M-;" 'fortran-indent-comment)
448 (define-key map "\M-\n" 'fortran-split-line)
449 (define-key map "\M-\C-q" 'fortran-indent-subprogram)
315aa1de
DL
450 (define-key map "\C-c\C-w" 'fortran-window-create-momentarily)
451 (define-key map "\C-c\C-r" 'fortran-column-ruler)
452 (define-key map "\C-c\C-p" 'fortran-previous-statement)
453 (define-key map "\C-c\C-n" 'fortran-next-statement)
454 (define-key map "\C-c\C-d" 'fortran-join-line) ; like f90
5b04210c 455 (define-key map "\M-^" 'fortran-join-line) ; subvert delete-indentation
315aa1de
DL
456 (define-key map "0" 'fortran-electric-line-number)
457 (define-key map "1" 'fortran-electric-line-number)
458 (define-key map "2" 'fortran-electric-line-number)
459 (define-key map "3" 'fortran-electric-line-number)
460 (define-key map "4" 'fortran-electric-line-number)
461 (define-key map "5" 'fortran-electric-line-number)
462 (define-key map "6" 'fortran-electric-line-number)
463 (define-key map "7" 'fortran-electric-line-number)
464 (define-key map "8" 'fortran-electric-line-number)
465 (define-key map "9" 'fortran-electric-line-number)
7a7db8e5 466
5b04210c
GM
467 (easy-menu-define fortran-menu map "Menu for Fortran mode."
468 `("Fortran"
469 ["Manual" (info "(emacs)Fortran")]
470 ("Customization"
471 ,(custom-menu-create 'fortran)
472 ["Set" Custom-set t]
473 ["Save" Custom-save t]
474 ["Reset to Current" Custom-reset-current t]
475 ["Reset to Saved" Custom-reset-saved t]
476 ["Reset to Standard Settings" Custom-reset-standard t]
477 )
478 "--"
479 ["Comment Region" fortran-comment-region mark-active]
480 ["Uncomment Region"
481 (fortran-comment-region (region-beginning) (region-end) 1)
482 mark-active]
483 ["Indent Region" indent-region mark-active]
484 ["Indent Subprogram" fortran-indent-subprogram t]
485 "--"
486 ["Beginning of Subprogram" fortran-beginning-of-subprogram t]
487 ["End of Subprogram" fortran-end-of-subprogram t]
488 ("Mark"
489 ["Subprogram" mark-defun t]
490 ["IF Block" fortran-mark-if t]
491 ["DO Block" fortran-mark-do t]
492 )
493 ["Narrow to Subprogram" narrow-to-defun t]
494 ["Widen" widen t]
495 "--"
496 ["Temporary column ruler" fortran-column-ruler t]
497 ["72-column window" fortran-window-create t]
498 ["Full Width Window"
499 (enlarge-window-horizontally (- (frame-width) (window-width)))
500 (< (window-width) (frame-width))]
501 ["Momentary 72-column window" fortran-window-create-momentarily t]
502 "--"
503 ["Break Line at Point" fortran-split-line t]
504 ["Join Line" fortran-join-line t]
505 ["Fill Statement/Comment" fill-paragraph t]
506 "--"
507 ["Toggle auto-fill" auto-fill-mode :selected auto-fill-function
508 :style toggle]
509 ["Toggle abbrev-mode" abbrev-mode :selected abbrev-mode
510 :style toggle]
511 ["Add imenu Menu" imenu-add-menubar-index
512 :active (not (lookup-key (current-local-map) [menu-bar index]))
513 :included (fboundp 'imenu-add-to-menubar)]))
315aa1de 514 map)
b8cbdf43 515 "Keymap used in Fortran mode.")
5b04210c 516
3dd63760 517\f
7a7db8e5 518(defvar fortran-mode-abbrev-table
6f9a4ce2
GM
519 (let (abbrevs-changed)
520 (define-abbrev-table 'fortran-mode-abbrev-table nil)
521 ;; Use the 6th arg (SYSTEM-FLAG) of define-abbrev if possible.
522 ;; Only use `apply' to quieten the byte-compiler.
523 (mapcar
524 (function (lambda (element)
525 (condition-case nil
526 (apply 'define-abbrev fortran-mode-abbrev-table
527 (append element '(nil 0 t)))
528 (wrong-number-of-arguments
529 (apply 'define-abbrev fortran-mode-abbrev-table
530 (append element '(nil 0)))))))
531 '((";au" "automatic" )
532 (";b" "byte" )
533 (";bd" "block data" )
534 (";ch" "character" )
535 (";cl" "close" )
536 (";c" "continue" )
537 (";cm" "common" )
538 (";cx" "complex" )
539 (";df" "define" )
540 (";di" "dimension" )
541 (";do" "double" )
542 (";dc" "double complex" )
543 (";dp" "double precision" )
544 (";dw" "do while" )
545 (";e" "else" )
546 (";ed" "enddo" )
547 (";el" "elseif" )
548 (";en" "endif" )
549 (";eq" "equivalence" )
550 (";ew" "endwhere" )
551 (";ex" "external" )
552 (";ey" "entry" )
553 (";f" "format" )
554 (";fa" ".false." )
555 (";fu" "function" )
556 (";g" "goto" )
557 (";im" "implicit" )
558 (";ib" "implicit byte" )
559 (";ic" "implicit complex" )
560 (";ich" "implicit character")
561 (";ii" "implicit integer" )
562 (";il" "implicit logical" )
563 (";ir" "implicit real" )
564 (";inc" "include" )
565 (";in" "integer" )
566 (";intr" "intrinsic" )
567 (";l" "logical" )
568 (";n" "namelist" )
569 (";o" "open" ) ; was ;op
570 (";pa" "parameter" )
571 (";pr" "program" )
572 (";ps" "pause" )
573 (";p" "print" )
574 (";rc" "record" )
575 (";re" "real" )
576 (";r" "read" )
577 (";rt" "return" )
578 (";rw" "rewind" )
579 (";s" "stop" )
580 (";sa" "save" )
581 (";st" "structure" )
582 (";sc" "static" )
583 (";su" "subroutine" )
584 (";tr" ".true." )
585 (";ty" "type" )
586 (";vo" "volatile" )
587 (";w" "write" )
588 (";wh" "where" )))
7a7db8e5 589 fortran-mode-abbrev-table))
7977773d 590
5b04210c 591\f
7dae727d 592
3dd63760
JB
593;;;###autoload
594(defun fortran-mode ()
5b04210c
GM
595 "Major mode for editing Fortran code in fixed format.
596For free format code, use `f90-mode'.
597
60db3594 598\\[fortran-indent-line] indents the current Fortran line correctly.
5b04210c 599Note that DO statements must not share a common CONTINUE.
3dd63760 600
5b04210c
GM
601Type ;? or ;\\[help-command] to display a list of built-in abbrevs for\
602 Fortran keywords.
3dd63760
JB
603
604Key definitions:
605\\{fortran-mode-map}
606
607Variables controlling indentation style and extra features:
608
5b04210c
GM
609`comment-start'
610 To use comments starting with `!', set this to the string \"!\".
611`fortran-do-indent'
612 Extra indentation within DO blocks (default 3).
613`fortran-if-indent'
614 Extra indentation within IF blocks (default 3).
615`fortran-structure-indent'
616 Extra indentation within STRUCTURE, UNION, MAP and INTERFACE blocks.
617 (default 3)
618`fortran-continuation-indent'
619 Extra indentation applied to continuation statements (default 5).
620`fortran-comment-line-extra-indent'
621 Amount of extra indentation for text in full-line comments (default 0).
622`fortran-comment-indent-style'
623 How to indent the text in full-line comments. Allowed values are:
624 nil don't change the indentation
625 fixed indent to `fortran-comment-line-extra-indent' beyond the
626 value of either
627 `fortran-minimum-statement-indent-fixed' (fixed format) or
628 `fortran-minimum-statement-indent-tab' (TAB format),
629 depending on the continuation format in use.
630 relative indent to `fortran-comment-line-extra-indent' beyond the
3dd63760 631 indentation for a line of code.
5b04210c
GM
632 (default 'fixed)
633`fortran-comment-indent-char'
634 Single-character string to be inserted instead of space for
635 full-line comment indentation (default \" \").
636`fortran-minimum-statement-indent-fixed'
637 Minimum indentation for statements in fixed format mode (default 6).
638`fortran-minimum-statement-indent-tab'
639 Minimum indentation for statements in TAB format mode (default 9).
640`fortran-line-number-indent'
641 Maximum indentation for line numbers (default 1). A line number will
642 get less than this much indentation if necessary to avoid reaching
643 column 5.
644`fortran-check-all-num-for-matching-do'
645 Non-nil causes all numbered lines to be treated as possible \"continue\"
646 statements (default nil).
647`fortran-blink-matching-if'
648 Non-nil causes \\[fortran-indent-line] on an ENDIF (or ENDDO) statement
649 to blink on the matching IF (or DO [WHILE]). (default nil)
650`fortran-continuation-string'
651 Single-character string to be inserted in column 5 of a continuation
652 line (default \"$\").
653`fortran-comment-region'
654 String inserted by \\[fortran-comment-region] at start of each line in
655 the region (default \"c$$$\").
656`fortran-electric-line-number'
657 Non-nil causes line number digits to be moved to the correct column
658 as typed (default t).
659`fortran-break-before-delimiters'
660 Non-nil causes lines to be broken before delimiters (default t).
3dd63760 661
b8cbdf43 662Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
3dd63760
JB
663with no args, if that value is non-nil."
664 (interactive)
665 (kill-all-local-variables)
5b04210c
GM
666 (setq major-mode 'fortran-mode
667 mode-name "Fortran"
668 local-abbrev-table fortran-mode-abbrev-table)
3dd63760 669 (set-syntax-table fortran-mode-syntax-table)
5b04210c
GM
670 (use-local-map fortran-mode-map)
671 (set (make-local-variable 'indent-line-function) 'fortran-indent-line)
672 (set (make-local-variable 'indent-region-function)
673 (lambda (start end)
674 (let (fortran-blink-matching-if ; avoid blinking delay
675 indent-region-function)
676 (indent-region start end nil))))
677 (set (make-local-variable 'require-final-newline) t)
678 ;; The syntax tables don't understand the column-0 comment-markers.
679 (set (make-local-variable 'comment-use-syntax) nil)
680 (set (make-local-variable 'comment-padding) "$$$")
681 (set (make-local-variable 'comment-start) fortran-comment-line-start)
ff451e17
SM
682 (set (make-local-variable 'comment-start-skip)
683 ;; We can't reuse `fortran-comment-line-start-skip' directly because
684 ;; it contains backrefs whereas we need submatch-1 to end at the
685 ;; beginning of the comment delimiter.
686 ;; (concat "\\(\\)\\(![ \t]*\\|" fortran-comment-line-start-skip "\\)")
687 "\\(\\)\\(?:^[CcDd*]\\|!\\)\\(?:\\([^ \t\n]\\)\\2+\\)?[ \t]*")
5b04210c
GM
688 (set (make-local-variable 'comment-indent-function) 'fortran-comment-indent)
689 (set (make-local-variable 'abbrev-all-caps) t)
690 (set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill)
5b04210c 691 (set (make-local-variable 'indent-tabs-mode) (fortran-analyze-file-format))
a7113309 692 (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string))
1eb6bf70 693 (set (make-local-variable 'fill-column) 72)
1eb6bf70 694 (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
5b04210c
GM
695 (set (make-local-variable 'font-lock-defaults)
696 '((fortran-font-lock-keywords
697 fortran-font-lock-keywords-1
698 fortran-font-lock-keywords-2
699 fortran-font-lock-keywords-3)
700 nil t ((?/ . "$/") ("_$" . "w"))
701 fortran-beginning-of-subprogram))
702 (set (make-local-variable 'font-lock-syntactic-keywords)
703 fortran-font-lock-syntactic-keywords)
704 (set (make-local-variable 'imenu-case-fold-search) t)
705 (set (make-local-variable 'imenu-generic-expression)
706 fortran-imenu-generic-expression)
707 (set (make-local-variable 'imenu-syntax-alist) '(("_$" . "w")))
26ef1c87
DL
708 (set (make-local-variable 'beginning-of-defun-function)
709 #'fortran-beginning-of-subprogram)
710 (set (make-local-variable 'end-of-defun-function)
711 #'fortran-end-of-subprogram)
68ca306c
DL
712 (set (make-local-variable 'add-log-current-defun-function)
713 #'fortran-current-defun)
315aa1de 714 (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
5727e748 715 (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
3dd63760 716 (run-hooks 'fortran-mode-hook))
5b04210c 717
3dd63760 718\f
5727e748
SM
719(defun fortran-gud-find-expr ()
720 ;; Consider \n as punctuation (end of expression).
721 (with-syntax-table fortran-gud-syntax-table
722 (gud-find-c-expr)))
723
315aa1de 724(defsubst fortran-comment-indent ()
5b04210c
GM
725 "Return the indentation appropriate for the current comment line.
726This is 0 for a line matching `fortran-comment-line-start-skip', else
727the value of `comment-column' (leaving at least one space after code)."
728 (if (looking-at fortran-comment-line-start-skip) 0
729 (save-excursion
ff451e17 730 (skip-chars-backward " \t")
0a39a75c 731 (max (1+ (current-column)) comment-column))))
3dd63760
JB
732
733(defun fortran-indent-comment ()
734 "Align or create comment on current line.
735Existing comments of all types are recognized and aligned.
5b04210c 736If the line has no comment, a side-by-side comment is inserted and aligned,
ff451e17 737if the value of `comment-start' is not nil and allows such comments.
3dd63760
JB
738Otherwise, a separate-line comment is inserted, on this line
739or on a new line inserted before this line if this line is not blank."
5b04210c 740 (interactive "*")
3dd63760
JB
741 (beginning-of-line)
742 ;; Recognize existing comments of either kind.
ff451e17
SM
743 (cond ((fortran-find-comment-start-skip 'all)
744 (goto-char (match-beginning 0))
745 (if (bolp)
746 (fortran-indent-line)
5b04210c
GM
747 (unless (= (current-column) (fortran-comment-indent))
748 (delete-horizontal-space)
749 (indent-to (fortran-comment-indent)))))
3dd63760
JB
750 ;; No existing comment.
751 ;; If side-by-side comments are defined, insert one,
752 ;; unless line is now blank.
ff451e17
SM
753 ((and comment-start (not (looking-at "[ \t]*$"))
754 (string-match comment-start-skip (concat " " comment-start)))
3dd63760
JB
755 (end-of-line)
756 (delete-horizontal-space)
315aa1de 757 (indent-to (fortran-comment-indent))
3dd63760
JB
758 (insert comment-start))
759 ;; Else insert separate-line comment, making a new line if nec.
760 (t
761 (if (looking-at "^[ \t]*$")
762 (delete-horizontal-space)
763 (beginning-of-line)
7dae727d 764 (insert ?\n)
3dd63760 765 (forward-char -1))
7dae727d 766 (insert fortran-comment-line-start)
3dd63760
JB
767 (insert-char (if (stringp fortran-comment-indent-char)
768 (aref fortran-comment-indent-char 0)
b8cbdf43 769 fortran-comment-indent-char)
1eb6bf70 770 (- (fortran-calculate-indent) (current-column))))))
3dd63760
JB
771
772(defun fortran-comment-region (beg-region end-region arg)
5b04210c
GM
773 "Comment every line in the region.
774Inserts the string variable `fortran-comment-region' at the beginning of
775every line in the region.
776BEG-REGION and END-REGION specify the region boundaries.
3dd63760
JB
777With non-nil ARG, uncomments the region."
778 (interactive "*r\nP")
b937fd1e 779 (let ((end-region-mark (copy-marker end-region))
315aa1de 780 (save-point (point-marker)))
3dd63760
JB
781 (goto-char beg-region)
782 (beginning-of-line)
5b04210c 783 (if arg
0a39a75c 784 (let ((com (regexp-quote fortran-comment-region))) ; uncomment
5b04210c
GM
785 (if (looking-at com)
786 (delete-region (point) (match-end 0)))
787 (while (and (zerop (forward-line 1))
788 (< (point) end-region-mark))
789 (if (looking-at com)
790 (delete-region (point) (match-end 0)))))
0a39a75c 791 (insert fortran-comment-region) ; comment
5b04210c
GM
792 (while (and (zerop (forward-line 1))
793 (< (point) end-region-mark))
794 (insert fortran-comment-region)))
3dd63760
JB
795 (goto-char save-point)
796 (set-marker end-region-mark nil)
797 (set-marker save-point nil)))
5b04210c 798
3dd63760
JB
799\f
800(defun fortran-abbrev-start ()
60db3594 801 "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
3dd63760 802Any other key combination is executed normally."
5b04210c 803 (interactive "*")
be35ca9f
GM
804 (insert last-command-char)
805 (let (char event)
806 (if (fboundp 'next-command-event) ; XEmacs
807 (setq event (next-command-event)
808 char (event-to-character event))
809 (setq event (read-event)
810 char event))
811 ;; Insert char if not equal to `?', or if abbrev-mode is off.
812 (if (and abbrev-mode (or (eq char ??) (eq char help-char)))
3dd63760 813 (fortran-abbrev-help)
be35ca9f 814 (setq unread-command-events (list event)))))
3dd63760
JB
815
816(defun fortran-abbrev-help ()
817 "List the currently defined abbrevs in Fortran mode."
818 (interactive)
819 (message "Listing abbrev table...")
e80f2147 820 (display-buffer (fortran-prepare-abbrev-list-buffer))
3dd63760
JB
821 (message "Listing abbrev table...done"))
822
e80f2147 823(defun fortran-prepare-abbrev-list-buffer ()
5b04210c 824 "Create a buffer listing the Fortran mode abbreviations."
e80f2147
RS
825 (save-excursion
826 (set-buffer (get-buffer-create "*Abbrevs*"))
827 (erase-buffer)
4632a893 828 (insert-abbrev-table-description 'fortran-mode-abbrev-table t)
e80f2147
RS
829 (goto-char (point-min))
830 (set-buffer-modified-p nil)
831 (edit-abbrevs-mode))
832 (get-buffer-create "*Abbrevs*"))
833
3dd63760 834(defun fortran-column-ruler ()
7977773d 835 "Insert a column ruler momentarily above current line, till next keystroke.
0a39a75c
GM
836The ruler is defined by the value of `fortran-column-ruler-fixed' in fixed
837format mode, and `fortran-column-ruler-tab' in TAB format mode.
838The next key typed is executed unless it is SPC."
3dd63760 839 (interactive)
60db3594 840 (momentary-string-display
23029d77
JB
841 (if indent-tabs-mode
842 fortran-column-ruler-tab
843 fortran-column-ruler-fixed)
844 (save-excursion
60db3594 845 (beginning-of-line)
23029d77
JB
846 (if (eq (window-start (selected-window))
847 (window-point (selected-window)))
7a7db8e5 848 (line-beginning-position 2)
23029d77 849 (point)))
3dd63760
JB
850 nil "Type SPC or any command to erase ruler."))
851
852(defun fortran-window-create ()
7977773d 853 "Make the window 72 columns wide.
fe668515 854See also `fortran-window-create-momentarily'."
3dd63760 855 (interactive)
b2523604
DL
856 (let ((window-min-width 2))
857 (if (< (window-width) (frame-width))
858 (enlarge-window-horizontally (- (frame-width)
859 (window-width) 1)))
860 (let* ((window-edges (window-edges))
861 (scroll-bar-width (- (nth 2 window-edges)
862 (car window-edges)
863 (window-width))))
864 (split-window-horizontally (+ 72 scroll-bar-width)))
865 (other-window 1)
866 (switch-to-buffer " fortran-window-extra" t)
867 (select-window (previous-window))))
3dd63760
JB
868
869(defun fortran-window-create-momentarily (&optional arg)
7977773d 870 "Momentarily make the window 72 columns wide.
3dd63760 871Optional ARG non-nil and non-unity disables the momentary feature.
fe668515 872See also `fortran-window-create'."
3dd63760
JB
873 (interactive "p")
874 (if (or (not arg)
875 (= arg 1))
876 (save-window-excursion
b2523604
DL
877 (progn
878 (condition-case nil
879 (fortran-window-create)
880 (error (error "No room for Fortran window")))
881 (message "Type SPC to continue editing.")
882 (let ((char (read-event)))
883 (or (equal char (string-to-char " "))
884 (setq unread-command-events (list char))))))
3dd63760
JB
885 (fortran-window-create)))
886
887(defun fortran-split-line ()
888 "Break line at point and insert continuation marker and alignment."
5b04210c 889 (interactive "*")
3dd63760 890 (delete-horizontal-space)
7dae727d 891 (if (save-excursion
894dc7e7
SM
892 (let ((pos (point)))
893 (beginning-of-line)
894 (and (fortran-find-comment-start-skip 'all)
895 (< (match-beginning 0) pos))))
ff451e17 896 (insert ?\n (match-string 0))
23029d77 897 (if indent-tabs-mode
7dae727d 898 (insert ?\n ?\t (fortran-numerical-continuation-char))
0a39a75c
GM
899 (insert "\n " fortran-continuation-string))) ; space after \n important
900 (fortran-indent-line)) ; when cont string is C, c or *
1eb6bf70
DL
901
902(defun fortran-remove-continuation ()
5b04210c
GM
903 "Delete any Fortran continuation characters at point.
904Returns t if anything actually deleted."
905 (when (looking-at "\\( \\{5\\}[^ 0\n]\\|\t[1-9]\\|&\\)")
906 (replace-match "")
907 (delete-indentation)
908 t))
3dd63760 909
46d4d7bf
DL
910(defun fortran-join-line (arg)
911 "Join current line to the previous one and re-indent.
912With a prefix argument, repeat this operation that many times.
913If the prefix argument ARG is negative, join the next -ARG lines.
914Continuation lines are correctly handled."
915 (interactive "*p")
7977773d 916 (save-excursion
46d4d7bf
DL
917 (when (> 0 arg)
918 (setq arg (- arg))
919 (forward-line arg))
920 (while (not (zerop arg))
921 (beginning-of-line)
922 (or (fortran-remove-continuation)
923 (delete-indentation))
924 (setq arg (1- arg)))
7977773d
DL
925 (fortran-indent-line)))
926
3dd63760 927(defun fortran-numerical-continuation-char ()
b56eb7c9 928 "Return a digit for tab-digit style of continuation lines.
5b04210c
GM
929If previous line is a tab-digit continuation line, return that digit
930plus one, otherwise return 1. Zero not allowed."
3dd63760
JB
931 (save-excursion
932 (forward-line -1)
933 (if (looking-at "\t[1-9]")
5b04210c 934 (+ ?1 (% (- (char-after (1+ (point))) ?0) 9))
3dd63760
JB
935 ?1)))
936
556dd629 937(put 'fortran-electric-line-number 'delete-selection t)
3dd63760
JB
938(defun fortran-electric-line-number (arg)
939 "Self insert, but if part of a Fortran line number indent it automatically.
7977773d 940Auto-indent does not happen if a numeric ARG is used."
5b04210c 941 (interactive "*P")
3dd63760 942 (if (or arg (not fortran-electric-line-number))
60db3594 943 (if arg
b8cbdf43 944 (self-insert-command (prefix-numeric-value arg))
3dd63760
JB
945 (self-insert-command 1))
946 (if (or (and (= 5 (current-column))
947 (save-excursion
948 (beginning-of-line)
5b04210c
GM
949 ;; In col 5 with only spaces to the left.
950 (looking-at " \\{5\\}")))
23029d77 951 (and (= (if indent-tabs-mode
1eb6bf70
DL
952 fortran-minimum-statement-indent-tab
953 fortran-minimum-statement-indent-fixed) (current-column))
5b04210c
GM
954 ;; In col 8 with a single tab to the left.
955 (eq ?\t (char-after (line-beginning-position)))
3dd63760
JB
956 (not (or (eq last-command 'fortran-indent-line)
957 (eq last-command
aa4ed68c 958 'fortran-indent-new-line))))
3dd63760
JB
959 (save-excursion
960 (re-search-backward "[^ \t0-9]"
7dae727d 961 (line-beginning-position)
5b04210c
GM
962 t)) ; not a line number
963 (looking-at "[0-9]")) ; within a line number
b8cbdf43 964 (self-insert-command (prefix-numeric-value arg))
3dd63760
JB
965 (skip-chars-backward " \t")
966 (insert last-command-char)
967 (fortran-indent-line))))
5b04210c 968
3dd63760 969\f
823ab5da
DL
970(defun fortran-check-end-prog-re ()
971 "Check a preliminary match against `fortran-end-prog-re'."
972 ;; Having got a possible match for the subprogram end, we need a
973 ;; match of whitespace, avoiding possible column 73+ stuff.
974 (save-match-data
bd6cabcf 975 (string-match "^\\s-*\\(\\'\\|\\s<\\)"
823ab5da
DL
976 (buffer-substring (match-end 0)
977 (min (line-end-position)
978 (+ 72 (line-beginning-position)))))))
979
980;; Note that you can't just check backwards for `subroutine' &c in
981;; case of un-marked main programs not at the start of the file.
7dae727d 982(defun fortran-beginning-of-subprogram ()
b2523604 983 "Move point to the beginning of the current Fortran subprogram."
3dd63760 984 (interactive)
f687a879
DL
985 (save-match-data
986 (let ((case-fold-search t))
987 (beginning-of-line -1)
988 (if (catch 'ok
989 (while (re-search-backward fortran-end-prog-re nil 'move)
990 (if (fortran-check-end-prog-re)
991 (throw 'ok t))))
992 (forward-line)))))
3dd63760 993
7dae727d 994(defun fortran-end-of-subprogram ()
b2523604 995 "Move point to the end of the current Fortran subprogram."
3dd63760 996 (interactive)
f687a879
DL
997 (save-match-data
998 (let ((case-fold-search t))
999 (if (save-excursion ; on END
1000 (beginning-of-line)
1001 (and (looking-at fortran-end-prog-re)
1002 (fortran-check-end-prog-re)))
1003 (forward-line)
1004 (beginning-of-line 2)
1005 (catch 'ok
1006 (while (re-search-forward fortran-end-prog-re nil 'move)
1007 (if (fortran-check-end-prog-re)
1008 (throw 'ok t))))
1009 (goto-char (match-beginning 0))
1010 (forward-line)))))
3dd63760 1011
3dd63760 1012(defun fortran-previous-statement ()
b2523604 1013 "Move point to beginning of the previous Fortran statement.
8edfcc7d
GM
1014Returns 'first-statement if that statement is the first
1015non-comment Fortran statement in the file, and nil otherwise.
5a73972b 1016Directive lines are treated as comments."
3dd63760
JB
1017 (interactive)
1018 (let (not-first-statement continue-test)
1019 (beginning-of-line)
1020 (setq continue-test
b8cbdf43 1021 (and
7dae727d 1022 (not (looking-at fortran-comment-line-start-skip))
5a73972b 1023 (not (looking-at fortran-directive-re))
b8cbdf43 1024 (or (looking-at
315aa1de
DL
1025 (concat "[ \t]*"
1026 (regexp-quote fortran-continuation-string)))
1027 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))))
5b04210c 1028 (while (and (setq not-first-statement (zerop (forward-line -1)))
7dae727d 1029 (or (looking-at fortran-comment-line-start-skip)
5a73972b 1030 (looking-at fortran-directive-re)
98110b1f
GM
1031 (looking-at
1032 (concat "[ \t]*"
1033 (regexp-quote fortran-continuation-string)))
315aa1de
DL
1034 (looking-at "[ \t]*$\\| \\{5\\}[^ 0\n]\\|\t[1-9]")
1035 (looking-at (concat "[ \t]*" comment-start-skip)))))
3dd63760
JB
1036 (cond ((and continue-test
1037 (not not-first-statement))
1038 (message "Incomplete continuation statement."))
60db3594 1039 (continue-test
3dd63760
JB
1040 (fortran-previous-statement))
1041 ((not not-first-statement)
1042 'first-statement))))
1043
1044(defun fortran-next-statement ()
b2523604 1045 "Move point to beginning of the next Fortran statement.
8edfcc7d
GM
1046Returns 'last-statement if that statement is the last
1047non-comment Fortran statement in the file, and nil otherwise.
5a73972b 1048Directive lines are treated as comments."
3dd63760
JB
1049 (interactive)
1050 (let (not-last-statement)
1051 (beginning-of-line)
b8cbdf43 1052 (while (and (setq not-last-statement
5b04210c 1053 (and (zerop (forward-line 1))
b8cbdf43 1054 (not (eobp))))
7dae727d 1055 (or (looking-at fortran-comment-line-start-skip)
5a73972b 1056 (looking-at fortran-directive-re)
7dae727d 1057 (looking-at "[ \t]*$\\| [^ 0\n]\\|\t[1-9]")
315aa1de 1058 (looking-at (concat "[ \t]*" comment-start-skip)))))
3dd63760
JB
1059 (if (not not-last-statement)
1060 'last-statement)))
5b04210c 1061
3dd63760 1062\f
7dae727d
DL
1063(defun fortran-blink-match (regex keyword find-begin)
1064 "From a line matching REGEX, blink matching KEYWORD statement line.
1065Use function FIND-BEGIN to match it."
1eb6bf70 1066 (let ((top-of-window (window-start))
7dae727d 1067 (end-point (point))
1eb6bf70 1068 (case-fold-search t)
7dae727d 1069 matching
1eb6bf70 1070 message)
5b04210c
GM
1071 (when (save-excursion
1072 (beginning-of-line)
1073 (skip-chars-forward " \t0-9")
1074 (looking-at regex))
1075 (if (not (setq matching (funcall find-begin)))
1076 (setq message (concat "No matching " keyword "."))
1077 (if (< matching top-of-window)
1078 (save-excursion
1079 (goto-char matching)
1080 (beginning-of-line)
1081 (setq message
1082 (concat "Matches "
1083 (buffer-substring (point)
1084 (line-end-position)))))))
1085 (if message
1086 (message "%s" message)
1087 (goto-char matching)
1088 (sit-for 1)
1089 (goto-char end-point)))))
7dae727d
DL
1090
1091(defun fortran-blink-matching-if ()
1092 "From an ENDIF or ELSE statement, blink the matching IF statement."
1093 (fortran-blink-match "e\\(nd[ \t]*if\\|lse\\([ \t]*if\\)?\\)\\b"
1094 "if" #'fortran-beginning-if))
947388af
RS
1095
1096(defun fortran-blink-matching-do ()
45cf60ae 1097 "From an ENDDO statement, blink the matching DO or DO WHILE statement."
7dae727d 1098 (fortran-blink-match "end[ \t]*do\\b" "do" #'fortran-beginning-do))
c5af0a18
RS
1099
1100(defun fortran-mark-do ()
60db3594 1101 "Put mark at end of Fortran DO [WHILE]-ENDDO construct, point at beginning.
c5af0a18
RS
1102The marks are pushed."
1103 (interactive)
1104 (let (enddo-point do-point)
1105 (if (setq enddo-point (fortran-end-do))
1106 (if (not (setq do-point (fortran-beginning-do)))
1107 (message "No matching do.")
c5af0a18
RS
1108 (goto-char enddo-point)
1109 (push-mark)
1110 (goto-char do-point)))))
1111
1112(defun fortran-end-do ()
45cf60ae
DL
1113 "Search forward for first unmatched ENDDO.
1114Return point or nil."
1eb6bf70
DL
1115 (let ((case-fold-search t))
1116 (if (save-excursion (beginning-of-line)
1117 (skip-chars-forward " \t0-9")
1118 (looking-at "end[ \t]*do\\b"))
1119 ;; Sitting on one.
1120 (match-beginning 0)
1121 ;; Search for one.
1122 (save-excursion
1123 (let ((count 1))
5b04210c 1124 (while (and (not (zerop count))
1eb6bf70 1125 (not (eq (fortran-next-statement) 'last-statement))
0a39a75c 1126 ;; Keep local to subprogram.
45cf60ae
DL
1127 (not (and (looking-at fortran-end-prog-re)
1128 (fortran-check-end-prog-re))))
1eb6bf70
DL
1129 (skip-chars-forward " \t0-9")
1130 (cond ((looking-at "end[ \t]*do\\b")
1131 (setq count (1- count)))
7dae727d
DL
1132 ((looking-at
1133 "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]")
5b04210c
GM
1134 (setq count (1+ count)))))
1135 (and (zerop count)
1eb6bf70
DL
1136 ;; All pairs accounted for.
1137 (point)))))))
c5af0a18
RS
1138
1139(defun fortran-beginning-do ()
45cf60ae 1140 "Search backwards for first unmatched DO [WHILE].
845d331e
GM
1141Return point or nil. Ignores labelled DO loops (ie DO 10 ... 10 CONTINUE)."
1142 (let ((case-fold-search t)
1143 (dostart-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]"))
7dae727d
DL
1144 (if (save-excursion
1145 (beginning-of-line)
1146 (skip-chars-forward " \t0-9")
845d331e 1147 (looking-at dostart-re))
1eb6bf70
DL
1148 ;; Sitting on one.
1149 (match-beginning 0)
1150 ;; Search for one.
1151 (save-excursion
1152 (let ((count 1))
5b04210c 1153 (while (and (not (zerop count))
1eb6bf70 1154 (not (eq (fortran-previous-statement) 'first-statement))
0a39a75c 1155 ;; Keep local to subprogram.
45cf60ae
DL
1156 (not (and (looking-at fortran-end-prog-re)
1157 (fortran-check-end-prog-re))))
1eb6bf70 1158 (skip-chars-forward " \t0-9")
845d331e 1159 (cond ((looking-at dostart-re)
1eb6bf70 1160 (setq count (1- count)))
845d331e 1161 ;; Note labelled loop ends not considered.
1eb6bf70
DL
1162 ((looking-at "end[ \t]*do\\b")
1163 (setq count (1+ count)))))
5b04210c 1164 (and (zerop count)
1eb6bf70
DL
1165 ;; All pairs accounted for.
1166 (point)))))))
c5af0a18
RS
1167
1168(defun fortran-mark-if ()
1169 "Put mark at end of Fortran IF-ENDIF construct, point at beginning.
1170The marks are pushed."
1171 (interactive)
1172 (let (endif-point if-point)
1173 (if (setq endif-point (fortran-end-if))
1174 (if (not (setq if-point (fortran-beginning-if)))
1175 (message "No matching if.")
1176 ;; Set mark, move point.
1177 (goto-char endif-point)
1178 (push-mark)
1179 (goto-char if-point)))))
1180
1181(defun fortran-end-if ()
45cf60ae
DL
1182 "Search forwards for first unmatched ENDIF.
1183Return point or nil."
1eb6bf70
DL
1184 (let ((case-fold-search t))
1185 (if (save-excursion (beginning-of-line)
1186 (skip-chars-forward " \t0-9")
1187 (looking-at "end[ \t]*if\\b"))
1188 ;; Sitting on one.
1189 (match-beginning 0)
1190 ;; Search for one. The point has been already been moved to first
1191 ;; letter on line but this should not cause troubles.
1192 (save-excursion
1193 (let ((count 1))
5b04210c 1194 (while (and (not (zerop count))
1eb6bf70
DL
1195 (not (eq (fortran-next-statement) 'last-statement))
1196 ;; Keep local to subprogram.
45cf60ae
DL
1197 (not (and (looking-at fortran-end-prog-re)
1198 (fortran-check-end-prog-re))))
1eb6bf70
DL
1199 (skip-chars-forward " \t0-9")
1200 (cond ((looking-at "end[ \t]*if\\b")
5b04210c 1201 (setq count (1- count)))
1eb6bf70
DL
1202 ((looking-at fortran-if-start-re)
1203 (save-excursion
1204 (if (or
1205 (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
0a39a75c 1206 (let (then-test) ; multi-line if-then
1eb6bf70 1207 (while
315aa1de 1208 (and
5b04210c 1209 (zerop (forward-line 1))
315aa1de
DL
1210 ;; Search forward for then.
1211 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
1212 (not
1213 (setq then-test
1214 (looking-at
1215 ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
1eb6bf70 1216 then-test))
5b04210c
GM
1217 (setq count (1+ count)))))))
1218 (and (zerop count)
1eb6bf70
DL
1219 ;; All pairs accounted for.
1220 (point)))))))
c5af0a18
RS
1221
1222(defun fortran-beginning-if ()
45cf60ae
DL
1223 "Search backwards for first unmatched IF-THEN.
1224Return point or nil."
1eb6bf70
DL
1225 (let ((case-fold-search t))
1226 (if (save-excursion
7dae727d
DL
1227 ;; May be sitting on multi-line if-then statement, first
1228 ;; move to beginning of current statement. Note:
1229 ;; `fortran-previous-statement' moves to previous statement
1230 ;; *unless* current statement is first one. Only move
1231 ;; forward if not first-statement.
1eb6bf70
DL
1232 (if (not (eq (fortran-previous-statement) 'first-statement))
1233 (fortran-next-statement))
1234 (skip-chars-forward " \t0-9")
1235 (and
1236 (looking-at fortran-if-start-re)
1237 (save-match-data
1238 (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
1239 ;; Multi-line if-then.
1240 (let (then-test)
1241 (while
5b04210c 1242 (and (zerop (forward-line 1))
1eb6bf70 1243 ;; Search forward for then.
315aa1de 1244 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
1eb6bf70
DL
1245 (not
1246 (setq then-test
1247 (looking-at
1248 ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
1249 then-test)))))
1250 ;; Sitting on one.
1251 (match-beginning 0)
1252 ;; Search for one.
1253 (save-excursion
1254 (let ((count 1))
5b04210c 1255 (while (and (not (zerop count))
1eb6bf70
DL
1256 (not (eq (fortran-previous-statement) 'first-statement))
1257 ;; Keep local to subprogram.
45cf60ae
DL
1258 (not (and (looking-at fortran-end-prog-re)
1259 (fortran-check-end-prog-re))))
1eb6bf70
DL
1260 (skip-chars-forward " \t0-9")
1261 (cond ((looking-at fortran-if-start-re)
1262 (save-excursion
1263 (if (or
1264 (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
0a39a75c 1265 (let (then-test) ; multi-line if-then
1eb6bf70 1266 (while
315aa1de 1267 (and
5b04210c 1268 (zerop (forward-line 1))
315aa1de
DL
1269 ;; Search forward for then.
1270 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
1271 (not
1272 (setq then-test
1273 (looking-at
1274 (concat ".*then\\b[ \t]*"
b2523604 1275 "[^ \t(=a-z0-9]"))))))
1eb6bf70 1276 then-test))
5b04210c 1277 (setq count (1- count)))))
1eb6bf70 1278 ((looking-at "end[ \t]*if\\b")
5b04210c
GM
1279 (setq count (1+ count)))))
1280 (and (zerop count)
1eb6bf70
DL
1281 ;; All pairs accounted for.
1282 (point)))))))
5b04210c 1283
3dd63760
JB
1284\f
1285(defun fortran-indent-line ()
7977773d 1286 "Indent current Fortran line based on its contents and on previous lines."
5b04210c 1287 (interactive "*")
1eb6bf70 1288 (let ((cfi (fortran-calculate-indent)))
3dd63760
JB
1289 (save-excursion
1290 (beginning-of-line)
1291 (if (or (not (= cfi (fortran-current-line-indentation)))
1292 (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
1293 (not (fortran-line-number-indented-correctly-p))))
1294 (fortran-indent-to-column cfi)
1295 (beginning-of-line)
ff451e17 1296 (if (fortran-find-comment-start-skip)
3dd63760
JB
1297 (fortran-indent-comment))))
1298 ;; Never leave point in left margin.
1299 (if (< (current-column) cfi)
1300 (move-to-column cfi))
5b04210c
GM
1301 (and auto-fill-function
1302 (> (save-excursion (end-of-line) (current-column))
1303 fill-column)
1304 (save-excursion
1305 (end-of-line)
1306 (fortran-fill)))
1307 (when fortran-blink-matching-if
1308 (fortran-blink-matching-if)
1309 (fortran-blink-matching-do))))
3dd63760 1310
315aa1de 1311(defun fortran-auto-fill ()
5b04210c 1312 "Function to use for `normal-auto-fill-function' in Fortran mode."
315aa1de
DL
1313 (if (> (current-column) (current-fill-column))
1314 (let ((cfi (fortran-calculate-indent)))
1315 (save-excursion
1316 (beginning-of-line)
1317 (if (or (not (= cfi (fortran-current-line-indentation)))
1318 (and (re-search-forward "^[ \t]*[0-9]+"
1319 (+ (point) 4) t)
1320 (not (fortran-line-number-indented-correctly-p))))
1321 (fortran-indent-to-column cfi)
1322 (beginning-of-line)
ff451e17 1323 (if (fortran-find-comment-start-skip)
315aa1de
DL
1324 (fortran-indent-comment))))
1325 (fortran-fill)
1326 ;; Never leave point in left margin.
1327 (if (< (current-column) cfi)
1328 (move-to-column cfi)))))
1329
5aca2648
DL
1330;; Historically this was a separate function which advertised itself
1331;; as reindenting but only did so where `most likely to be necessary'.
1332(defalias 'fortran-indent-new-line 'reindent-then-newline-and-indent)
b8cbdf43 1333
3dd63760 1334(defun fortran-indent-subprogram ()
5b04210c
GM
1335 "Properly indent the Fortran subprogram containing point."
1336 (interactive "*")
3dd63760 1337 (save-excursion
7a7db8e5 1338 (mark-defun)
c4c42b2e
DL
1339 (message "Indenting subprogram...")
1340 (indent-region (point) (mark) nil))
3dd63760
JB
1341 (message "Indenting subprogram...done."))
1342
1eb6bf70 1343(defun fortran-calculate-indent ()
b8cbdf43 1344 "Calculates the Fortran indent column based on previous lines."
3dd63760
JB
1345 (let (icol first-statement (case-fold-search t)
1346 (fortran-minimum-statement-indent
23029d77
JB
1347 (if indent-tabs-mode
1348 fortran-minimum-statement-indent-tab
1349 fortran-minimum-statement-indent-fixed)))
3dd63760
JB
1350 (save-excursion
1351 (setq first-statement (fortran-previous-statement))
1352 (if first-statement
1353 (setq icol fortran-minimum-statement-indent)
98110b1f
GM
1354 (if (= (point) (point-min))
1355 (setq icol fortran-minimum-statement-indent)
1356 (setq icol (fortran-current-line-indentation)))
1357 (skip-chars-forward " \t0-9")
1358 (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(")
1359 (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]")
0a39a75c 1360 (let (then-test) ; multi-line if-then
5b04210c 1361 (while (and (zerop (forward-line 1))
0a39a75c 1362 ;; Search forward for then.
98110b1f
GM
1363 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")
1364 (not (setq then-test
1365 (looking-at
1366 ".*then\\b[ \t]\
b8cbdf43 1367*[^ \t_$(=a-z0-9]")))))
98110b1f
GM
1368 then-test))
1369 (setq icol (+ icol fortran-if-indent))))
1370 ((looking-at "else\\(if\\)?\\b")
1371 (setq icol (+ icol fortran-if-indent)))
1372 ((looking-at "select[ \t]*case[ \t](.*)")
1373 (setq icol (+ icol fortran-if-indent)))
1374 ((looking-at "case[ \t]*(.*)")
1375 (setq icol (+ icol fortran-if-indent)))
1376 ((looking-at "case[ \t]*default\\b")
1377 (setq icol (+ icol fortran-if-indent)))
1378 ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
1379 (setq icol (+ icol fortran-if-indent)))
1380 ((looking-at "where[ \t]*(.*)[ \t]*\n")
1381 (setq icol (+ icol fortran-if-indent)))
1382 ((looking-at "do\\b")
1383 (setq icol (+ icol fortran-do-indent)))
1384 ((looking-at
1385 "\\(structure\\|union\\|map\\|interface\\)\
7dae727d 1386\\b[ \t]*[^ \t=(a-z]")
98110b1f
GM
1387 (setq icol (+ icol fortran-structure-indent)))
1388 ((and (looking-at fortran-end-prog-re1)
1389 (fortran-check-end-prog-re))
0a39a75c 1390 ;; Previous END resets indent to minimum.
98110b1f 1391 (setq icol fortran-minimum-statement-indent)))))
3dd63760
JB
1392 (save-excursion
1393 (beginning-of-line)
1394 (cond ((looking-at "[ \t]*$"))
5a73972b
GM
1395 ;; Check for directive before comment, so as not to indent.
1396 ((looking-at fortran-directive-re)
1397 (setq fortran-minimum-statement-indent 0 icol 0))
7dae727d 1398 ((looking-at fortran-comment-line-start-skip)
3dd63760 1399 (cond ((eq fortran-comment-indent-style 'relative)
23029d77 1400 (setq icol (+ icol fortran-comment-line-extra-indent)))
3dd63760 1401 ((eq fortran-comment-indent-style 'fixed)
b8cbdf43 1402 (setq icol (+ fortran-minimum-statement-indent
23029d77 1403 fortran-comment-line-extra-indent))))
b8cbdf43 1404 (setq fortran-minimum-statement-indent 0))
98110b1f 1405 ((or (looking-at (concat "[ \t]*"
b8cbdf43
RS
1406 (regexp-quote
1407 fortran-continuation-string)))
315aa1de 1408 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
98110b1f
GM
1409 (skip-chars-forward " \t")
1410 ;; Do not introduce extra whitespace into a broken string.
1411 (setq icol
1412 (if (fortran-is-in-string-p (point))
1413 6
1414 (+ icol fortran-continuation-indent))))
3dd63760
JB
1415 (first-statement)
1416 ((and fortran-check-all-num-for-matching-do
1417 (looking-at "[ \t]*[0-9]+")
1418 (fortran-check-for-matching-do))
1419 (setq icol (- icol fortran-do-indent)))
1420 (t
1421 (skip-chars-forward " \t0-9")
1eb6bf70 1422 (cond ((looking-at "end[ \t]*\\(if\\|select\\|where\\)\\b")
3dd63760 1423 (setq icol (- icol fortran-if-indent)))
1eb6bf70 1424 ((looking-at "else\\(if\\)?\\b")
5a8d870b 1425 (setq icol (- icol fortran-if-indent)))
1eb6bf70 1426 ((looking-at "case[ \t]*\\((.*)\\|default\\>\\)")
5a8d870b 1427 (setq icol (- icol fortran-if-indent)))
b8cbdf43
RS
1428 ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b")
1429 (setq icol (- icol fortran-if-indent)))
3dd63760
JB
1430 ((and (looking-at "continue\\b")
1431 (fortran-check-for-matching-do))
1432 (setq icol (- icol fortran-do-indent)))
1433 ((looking-at "end[ \t]*do\\b")
1434 (setq icol (- icol fortran-do-indent)))
1eb6bf70 1435 ((looking-at "end[ \t]*\
5a8d870b 1436\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]")
b8cbdf43 1437 (setq icol (- icol fortran-structure-indent)))
1eb6bf70 1438 ((and (looking-at fortran-end-prog-re1)
45cf60ae 1439 (fortran-check-end-prog-re)
3dd63760
JB
1440 (not (= icol fortran-minimum-statement-indent)))
1441 (message "Warning: `end' not in column %d. Probably\
1442 an unclosed block." fortran-minimum-statement-indent))))))
1443 (max fortran-minimum-statement-indent icol)))
5b04210c 1444
3dd63760
JB
1445\f
1446(defun fortran-current-line-indentation ()
1447 "Indentation of current line, ignoring Fortran line number or continuation.
1448This is the column position of the first non-whitespace character
1449aside from the line number and/or column 5/8 line-continuation character.
1450For comment lines, returns indentation of the first
1451non-indentation text within the comment."
1452 (save-excursion
1453 (beginning-of-line)
7dae727d 1454 (cond ((looking-at fortran-comment-line-start-skip)
3dd63760
JB
1455 (goto-char (match-end 0))
1456 (skip-chars-forward
b8cbdf43
RS
1457 (if (stringp fortran-comment-indent-char)
1458 fortran-comment-indent-char
1459 (char-to-string fortran-comment-indent-char))))
315aa1de 1460 ((or (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
3dd63760
JB
1461 (goto-char (match-end 0)))
1462 (t
1463 ;; Move past line number.
7dae727d 1464 (skip-chars-forward "[ \t0-9]")))
3dd63760
JB
1465 ;; Move past whitespace.
1466 (skip-chars-forward " \t")
1467 (current-column)))
1468
1469(defun fortran-indent-to-column (col)
5b04210c 1470 "Indent current line to column COL.
3dd63760
JB
1471notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
1472 line, and this continuation character is retained on indentation;
b8cbdf43
RS
1473 2) If `fortran-continuation-string' is the first non-whitespace
1474 character, this is a continuation line;
3dd63760
JB
1475 3) A non-continuation line which has a number as the first
1476 non-whitespace character is a numbered line.
b8cbdf43 1477 4) A TAB followed by a digit indicates a continuation line."
3dd63760
JB
1478 (save-excursion
1479 (beginning-of-line)
7dae727d 1480 (if (looking-at fortran-comment-line-start-skip)
3dd63760 1481 (if fortran-comment-indent-style
7dae727d
DL
1482 (let* ((char (if (stringp fortran-comment-indent-char)
1483 (aref fortran-comment-indent-char 0)
1484 fortran-comment-indent-char))
1485 (chars (string ? ?\t char)))
3dd63760 1486 (goto-char (match-end 0))
7dae727d
DL
1487 (skip-chars-backward chars)
1488 (delete-region (point) (progn (skip-chars-forward chars)
1489 (point)))
3dd63760
JB
1490 (insert-char char (- col (current-column)))))
1491 (if (looking-at "\t[1-9]")
23029d77 1492 (if indent-tabs-mode
3dd63760
JB
1493 (goto-char (match-end 0))
1494 (delete-char 2)
7dae727d 1495 (insert-char ? 5)
3dd63760 1496 (insert fortran-continuation-string))
315aa1de 1497 (if (looking-at " \\{5\\}[^ 0\n]")
23029d77 1498 (if indent-tabs-mode
3dd63760 1499 (progn (delete-char 6)
7dae727d 1500 (insert ?\t (fortran-numerical-continuation-char) 1))
3dd63760
JB
1501 (forward-char 6))
1502 (delete-horizontal-space)
0a39a75c
GM
1503 ;; Put line number in columns 0-4, or
1504 ;; continuation character in column 5.
3dd63760
JB
1505 (cond ((eobp))
1506 ((looking-at (regexp-quote fortran-continuation-string))
23029d77 1507 (if indent-tabs-mode
3dd63760 1508 (progn
60db3594 1509 (indent-to
23029d77
JB
1510 (if indent-tabs-mode
1511 fortran-minimum-statement-indent-tab
1512 fortran-minimum-statement-indent-fixed))
3dd63760
JB
1513 (delete-char 1)
1514 (insert-char (fortran-numerical-continuation-char) 1))
b8cbdf43
RS
1515 (indent-to 5)
1516 (forward-char 1)))
3dd63760
JB
1517 ((looking-at "[0-9]+")
1518 (let ((extra-space (- 5 (- (match-end 0) (point)))))
1519 (if (< extra-space 0)
1520 (message "Warning: line number exceeds 5-digit limit.")
1521 (indent-to (min fortran-line-number-indent extra-space))))
1522 (skip-chars-forward "0-9")))))
1523 ;; Point is now after any continuation character or line number.
1524 ;; Put body of statement where specified.
1525 (delete-horizontal-space)
1526 (indent-to col)
1527 ;; Indent any comment following code on the same line.
5b04210c
GM
1528 (when (fortran-find-comment-start-skip)
1529 (goto-char (match-beginning 0))
1530 (unless (= (current-column) (fortran-comment-indent))
1531 (delete-horizontal-space)
1532 (indent-to (fortran-comment-indent)))))))
3dd63760
JB
1533
1534(defun fortran-line-number-indented-correctly-p ()
1535 "Return t if current line's line number is correctly indented.
1536Do not call if there is no line number."
1537 (save-excursion
1538 (beginning-of-line)
1539 (skip-chars-forward " \t")
1540 (and (<= (current-column) fortran-line-number-indent)
1541 (or (= (current-column) fortran-line-number-indent)
1542 (progn (skip-chars-forward "0-9")
1543 (= (current-column) 5))))))
1544
1545(defun fortran-check-for-matching-do ()
7977773d
DL
1546 "When called from a numbered statement, return t if matching DO is found.
1547Otherwise return nil."
7dae727d
DL
1548 (let ((case-fold-search t)
1549 charnum)
3dd63760
JB
1550 (save-excursion
1551 (beginning-of-line)
5b04210c
GM
1552 (when (looking-at "[ \t]*[0-9]+")
1553 (skip-chars-forward " \t")
0a39a75c 1554 (skip-chars-forward "0") ; skip past leading zeros
5b04210c
GM
1555 (setq charnum
1556 (buffer-substring (point) (progn
1557 (skip-chars-forward "0-9")
1558 (point))))
1559 (beginning-of-line)
1560 (save-restriction
1561 (save-excursion
1562 (narrow-to-defun)
1563 (and (re-search-backward
1564 (concat
1565 "\\(^[ \t0-9]*do[ \t]*0*"
1566 charnum "\\b\\)\\|" "\\(^[ \t]*0*"
1567 charnum "\\b\\)")
1568 nil t)
1569 (looking-at
1570 (concat "^[ \t0-9]*do[ \t]*0*"
1571 charnum)))))))))
3dd63760 1572
ff451e17 1573(defun fortran-find-comment-start-skip (&optional all)
b8cbdf43 1574 "Move to past `comment-start-skip' found on current line.
ff451e17
SM
1575Return non-nil if `comment-start-skip' found, nil if not.
1576If ALL is nil, only match comments that start in column > 0."
ff451e17
SM
1577 ;; Hopefully at some point we can just use the line below! -stef
1578 ;; (comment-search-forward (line-end-position) t))
1579 (when (or all comment-start-skip)
1580 (let ((pos (point))
1581 (css (if comment-start-skip
1582 (concat fortran-comment-line-start-skip
1583 "\\|" comment-start-skip)
1584 fortran-comment-line-start-skip)))
1585 (when (re-search-forward css (line-end-position) t)
1586 (if (and (or all (> (match-beginning 0) (line-beginning-position)))
1587 (or (save-match-data
1588 (not (fortran-is-in-string-p (match-beginning 0))))
1589 ;; Recurse for rest of line.
1590 (fortran-find-comment-start-skip all)))
1591 (point)
1592 (goto-char pos)
1593 nil)))))
f022dd89 1594
5b04210c 1595;; From: ralf@up3aud1.gwdg.de (Ralf Fassel)
1eb6bf70 1596;; Test if TAB format continuation lines work.
b56eb7c9 1597(defun fortran-is-in-string-p (where)
7977773d 1598 "Return non-nil iff WHERE (a buffer position) is inside a Fortran string."
b56eb7c9
RS
1599 (save-excursion
1600 (goto-char where)
1601 (cond
1602 ((bolp) nil) ; bol is never inside a string
1603 ((save-excursion ; comment lines too
1eb6bf70 1604 (beginning-of-line)
7dae727d 1605 (looking-at fortran-comment-line-start-skip)) nil)
0a39a75c 1606 (t (let ((parse-state '(0 nil nil nil nil nil 0))
b56eb7c9
RS
1607 (quoted-comment-start (if comment-start
1608 (regexp-quote comment-start)))
1609 (not-done t)
7dae727d 1610 parse-limit end-of-line)
0a39a75c 1611 ;; Move to start of current statement.
b56eb7c9
RS
1612 (fortran-next-statement)
1613 (fortran-previous-statement)
0a39a75c 1614 ;; Now parse up to WHERE.
b56eb7c9 1615 (while not-done
0a39a75c 1616 (if (or ;; Skip to next line if:
b56eb7c9 1617 ;; - comment line?
7dae727d 1618 (looking-at fortran-comment-line-start-skip)
b56eb7c9
RS
1619 ;; - at end of line?
1620 (eolp)
1621 ;; - not in a string and after comment-start?
1622 (and (not (nth 3 parse-state))
1623 comment-start
1624 (equal comment-start
1625 (char-to-string (preceding-char)))))
1eb6bf70 1626 (if (> (forward-line) 0)
b56eb7c9
RS
1627 (setq not-done nil))
1628 ;; else:
0a39a75c 1629 ;; If we are at beginning of code line, skip any
b56eb7c9
RS
1630 ;; whitespace, labels and tab continuation markers.
1631 (if (bolp) (skip-chars-forward " \t0-9"))
0a39a75c 1632 ;; If we are in column <= 5 now, check for continuation char.
b56eb7c9
RS
1633 (cond ((= 5 (current-column)) (forward-char 1))
1634 ((and (< (current-column) 5)
1635 (equal fortran-continuation-string
1636 (char-to-string (following-char)))
1637 (forward-char 1))))
0a39a75c 1638 ;; Find out parse-limit from here.
7dae727d 1639 (setq end-of-line (line-end-position))
b56eb7c9 1640 (setq parse-limit (min where end-of-line))
0a39a75c 1641 ;; Parse max up to comment-start, if non-nil and in current line.
b56eb7c9
RS
1642 (if comment-start
1643 (save-excursion
1644 (if (re-search-forward quoted-comment-start end-of-line t)
1645 (setq parse-limit (min (point) parse-limit)))))
0a39a75c 1646 ;; Now parse if still in limits.
b56eb7c9
RS
1647 (if (< (point) where)
1648 (setq parse-state (parse-partial-sexp
1649 (point) parse-limit nil nil parse-state))
7dae727d 1650 (setq not-done nil))))
0a39a75c 1651 ;; Result.
b56eb7c9 1652 (nth 3 parse-state))))))
b8cbdf43 1653
7aabd23e
DL
1654;; From old version.
1655(defalias 'fortran-auto-fill-mode 'auto-fill-mode)
b8cbdf43 1656
4254fe58 1657(defun fortran-fill ()
5b04210c 1658 "Fill the current line at an appropriate point(s)."
315aa1de 1659 (let* ((auto-fill-function #'fortran-auto-fill)
e04196d3 1660 (opoint (point))
7dae727d
DL
1661 (bol (line-beginning-position))
1662 (eol (line-end-position))
b8cbdf43 1663 (bos (min eol (+ bol (fortran-current-line-indentation))))
6b61353c
KH
1664 ;; If in a string at fill-column, break it either before the
1665 ;; initial quote, or at fill-col (if string is too long).
b8cbdf43
RS
1666 (quote
1667 (save-excursion
1668 (goto-char bol)
98110b1f
GM
1669 ;; OK to break quotes on comment lines.
1670 (unless (looking-at fortran-comment-line-start-skip)
1671 (let (fcpoint start)
6b61353c
KH
1672 (move-to-column fill-column)
1673 (when (fortran-is-in-string-p (setq fcpoint (point)))
1674 (save-excursion
1675 (re-search-backward "\\S\"\\s\"\\S\"?" bol t)
1676 (setq start
1677 (if fortran-break-before-delimiters
1678 (point)
1679 (1+ (point)))))
1680 (if (re-search-forward "\\S\"\\s\"\\S\"" eol t)
1681 (backward-char 2))
1682 ;; If the current string is longer than 72 - 6 chars,
1683 ;; break it at the fill column (else infinite loop).
1684 (if (> (- (point) start)
1685 (- fill-column 6 fortran-continuation-indent))
1686 fcpoint
1687 start))))))
5b04210c 1688 ;; Decide where to split the line. If a position for a quoted
b8cbdf43 1689 ;; string was found above then use that, else break the line
6b61353c 1690 ;; before/after the last delimiter.
b8cbdf43
RS
1691 (fill-point
1692 (or quote
1693 (save-excursion
6b61353c
KH
1694 ;; If f-b-b-d is t, have an extra column to play with,
1695 ;; since delimiter gets shifted to new line.
1696 (move-to-column (if fortran-break-before-delimiters
1697 (1+ fill-column)
1698 fill-column))
1699 (let ((repeat t))
1700 (while repeat
1701 (setq repeat nil)
1702 ;; Adapted from f90-find-breakpoint.
1703 (re-search-backward fortran-break-delimiters-re
1704 (line-beginning-position))
1705 (if (not fortran-break-before-delimiters)
1706 (if (looking-at fortran-no-break-re)
1707 ;; Deal with cases such as "**" split over
1708 ;; fill-col. Simpler alternative would be
1709 ;; to start from (1- fill-column) above.
1710 (if (> (+ 2 (current-column)) fill-column)
1711 (setq repeat t)
1712 (forward-char 2))
1713 (forward-char 1))
1714 (backward-char)
1715 (or (looking-at fortran-no-break-re)
1716 (forward-char)))))
1717 ;; Line indented beyond fill-column?
1718 (when (<= (point) bos)
98110b1f 1719 (move-to-column (1+ fill-column))
0a39a75c 1720 ;; What is this doing???
98110b1f
GM
1721 (or (re-search-forward "[\t\n,'+-/*)=]" eol t)
1722 (goto-char bol)))
b8cbdf43 1723 (if (bolp)
6b61353c
KH
1724 (re-search-forward "[ \t]" opoint t))
1725 (point)))))
0a39a75c 1726 ;; If we are in an in-line comment, don't break unless the
b8cbdf43
RS
1727 ;; line of code is longer than it should be. Otherwise
1728 ;; break the line at the column computed above.
1729 ;;
0a39a75c
GM
1730 ;; Need to use fortran-find-comment-start-skip to make sure that
1731 ;; quoted !'s don't prevent a break.
ff451e17
SM
1732 (when (and (save-excursion
1733 (beginning-of-line)
0ab47edc
GM
1734 (if (not (fortran-find-comment-start-skip))
1735 t
ff451e17
SM
1736 (goto-char (match-beginning 0))
1737 (>= (point) fill-point)))
1738 (save-excursion
1739 (goto-char fill-point)
1740 (not (bolp)))
1741 (> (save-excursion
1742 (goto-char opoint)
1743 (current-column))
1744 (min (1+ fill-column)
1745 (+ (fortran-calculate-indent)
1746 fortran-continuation-indent))))
1747 (goto-char fill-point)
1748 (fortran-break-line)
1749 (end-of-line))))
7dae727d 1750
b8cbdf43 1751(defun fortran-break-line ()
5b04210c 1752 "Call `fortran-split-line'. Joins continuation lines first, then refills."
b8cbdf43 1753 (let ((opoint (point))
7dae727d 1754 (bol (line-beginning-position))
ff451e17
SM
1755 (comment-string
1756 (save-excursion
1757 (if (fortran-find-comment-start-skip)
1758 (delete-and-extract-region
1759 (match-beginning 0) (line-end-position))))))
0a39a75c 1760 ;; Forward line 1 really needs to go to next non white line.
1eb6bf70 1761 (if (save-excursion (forward-line)
ff451e17 1762 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]"))
b8cbdf43 1763 (progn
b8313955
RS
1764 (end-of-line)
1765 (delete-region (point) (match-end 0))
b8cbdf43 1766 (delete-horizontal-space)
4254fe58 1767 (fortran-fill))
b8cbdf43
RS
1768 (fortran-split-line))
1769 (if comment-string
1770 (save-excursion
1771 (goto-char bol)
1772 (end-of-line)
1773 (delete-horizontal-space)
315aa1de 1774 (indent-to (fortran-comment-indent))
b8cbdf43
RS
1775 (insert comment-string)))))
1776
23029d77 1777(defun fortran-analyze-file-format ()
7977773d 1778 "Return nil if fixed format is used, t if TAB formatting is used.
5b04210c
GM
1779Use `fortran-tab-mode-default' if no non-comment statements are found
1780before the end or in the first `fortran-analyze-depth' lines."
23029d77
JB
1781 (let ((i 0))
1782 (save-excursion
1783 (goto-char (point-min))
23029d77
JB
1784 (while (not (or
1785 (eobp)
7dae727d 1786 (eq (char-after) ?\t)
315aa1de 1787 (looking-at " \\{6\\}")
23029d77
JB
1788 (> i fortran-analyze-depth)))
1789 (forward-line)
1790 (setq i (1+ i)))
1791 (cond
7dae727d 1792 ((eq (char-after) ?\t) t)
315aa1de 1793 ((looking-at " \\{6\\}") nil)
a7113309 1794 (t fortran-tab-mode-default)))))
23029d77 1795
1eb6bf70
DL
1796(defun fortran-fill-paragraph (&optional justify)
1797 "Fill surrounding comment block as paragraphs, else fill statement.
5b04210c
GM
1798Intended as the value of `fill-paragraph-function'.
1799A comment block is filled by calling `fill-comment-paragraph' with
1800argument JUSTIFY, otherwise `fortran-fill-statement' is called.
1801Always returns non-nil (to prevent `fill-paragraph' being called)."
1802 (interactive "*P")
2bcfe15e
SM
1803 (or (fill-comment-paragraph justify)
1804 (fortran-fill-statement)
1805 t))
1eb6bf70
DL
1806
1807(defun fortran-fill-statement ()
5b04210c
GM
1808 "Fill a Fortran statement up to `fill-column'."
1809 (interactive "*")
315aa1de 1810 (let ((auto-fill-function #'fortran-auto-fill))
5b04210c
GM
1811 (unless (save-excursion
1812 (beginning-of-line)
1813 (or (looking-at "[ \t]*$")
1814 (looking-at fortran-comment-line-start-skip)
1815 (and comment-start-skip
1816 (looking-at (concat "[ \t]*" comment-start-skip)))))
1817 (save-excursion
1818 ;; Find beginning of statement.
1819 (fortran-next-statement)
1820 (fortran-previous-statement)
1821 ;; Re-indent initially.
1822 (fortran-indent-line)
1823 ;; Replace newline plus continuation field plus indentation with
1824 ;; single space.
1825 (while (progn
1826 (forward-line)
1827 (fortran-remove-continuation)))
1828 (fortran-previous-statement)))
e04196d3 1829 (fortran-indent-line)))
1eb6bf70 1830
cfe9d0b5 1831(defun fortran-strip-sequence-nos (&optional do-space)
b9fe3dc8
RS
1832 "Delete all text in column 72 and up (assumed to be sequence numbers).
1833Normally also deletes trailing whitespace after stripping such text.
1834Supplying prefix arg DO-SPACE prevents stripping the whitespace."
5b04210c 1835 (interactive "*p")
3b4613a4
DL
1836 (save-excursion
1837 (goto-char (point-min))
562e00da 1838 (while (re-search-forward "^.\\{72\\}\\(.*\\)" nil t)
3b4613a4
DL
1839 (replace-match "" nil nil nil 1)
1840 (unless do-space (delete-horizontal-space)))))
1841
68ca306c
DL
1842;; This code used to live in add-log.el, but this is a better place
1843;; for it.
1844(defun fortran-current-defun ()
1845 "Function to use for `add-log-current-defun-function' in Fortran mode."
a245ece5
GM
1846 (save-excursion
1847 ;; We must be inside function body for this to work.
1848 (fortran-beginning-of-subprogram)
1849 (let ((case-fold-search t)) ; case-insensitive
0a39a75c 1850 ;; Search for fortran subprogram start.
a245ece5
GM
1851 (if (re-search-forward
1852 (concat "^[ \t]*\\(program\\|subroutine\\|function"
1853 "\\|[ \ta-z0-9*()]*[ \t]+function\\|"
1854 "\\(block[ \t]*data\\)\\)")
1855 (save-excursion (fortran-end-of-subprogram)
1856 (point))
1857 t)
1858 (or (match-string-no-properties 2)
1859 (progn
0a39a75c 1860 ;; Move to EOL or before first left paren.
a245ece5
GM
1861 (if (re-search-forward "[(\n]" nil t)
1862 (progn (backward-char)
1863 (skip-chars-backward " \t"))
1864 (end-of-line))
1865 ;; Use the name preceding that.
1866 (buffer-substring-no-properties (point) (progn (backward-sexp)
1867 (point)))))
1868 "main"))))
68ca306c 1869
49116ac0
JB
1870(provide 'fortran)
1871
6b61353c 1872;;; arch-tag: 74935096-21c4-4cab-8ee5-6ef16090dc04
1a06eabd 1873;;; fortran.el ends here