fortran.el 81.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, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
4 5
;;               2002, 2003, 2004, 2005, 2006, 2007
;;               Free Software Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
6

Eric S. Raymond's avatar
Eric S. Raymond committed
7
;; Author: Michael D. Prange <prange@erl.mit.edu>
8
;; Maintainer: Glenn Morris <rgm@gnu.org>
9
;; Keywords: fortran, languages
Eric S. Raymond's avatar
Eric S. Raymond committed
10

Eric S. Raymond's avatar
Eric S. Raymond committed
11 12 13 14
;; 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
15
;; the Free Software Foundation; either version 3, or (at your option)
Eric S. Raymond's avatar
Eric S. Raymond committed
16 17 18 19 20 21 22 23
;; 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
24
;; along with GNU Emacs; see the file COPYING.  If not, write to the
Lute Kamstra's avatar
Lute Kamstra committed
25 26
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
Eric S. Raymond's avatar
Eric S. Raymond committed
27 28 29

;;; Commentary:

30 31 32
;; 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
33
;; form.  For editing Fortran 90 free format source, use `f90-mode'
34 35 36
;; (f90.el).  It is meant to support the GNU Fortran language
;; implemented by g77 (its extensions to Fortran77 and
;; interpretations, e.g. of blackslash in strings).
37 38 39 40

;;; History:

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

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

Eric S. Raymond's avatar
Eric S. Raymond committed
47 48
;;; Code:

Dave Love's avatar
Dave Love committed
49
;; Todo:
50

51
;; * Tidy it all up (more)!
52 53 54
;; * Implement insertion and removal of statement continuations in
;;   mixed f77/f90 style, with the first `&' past column 72 and the
;;   second in column 6.
55
;; * Support any other extensions to f77 grokked by GNU Fortran I've missed.
56

57 58 59 60 61
;; silence compiler
(defvar dabbrev-case-fold-search)
(defvar gud-find-expr-function)
(defvar imenu-case-fold-search)
(defvar imenu-syntax-alist)
62 63


64
(defgroup fortran nil
65
  "Major mode for editing fixed format Fortran code."
66 67
  :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
  :link '(custom-manual "(emacs)Fortran")
68 69 70
  :group 'languages)

(defgroup fortran-indent nil
71
  "Indentation variables in Fortran mode."
72
  :prefix "fortran-"
73
  :group  'fortran)
74 75

(defgroup fortran-comment nil
76
  "Comment-handling variables in Fortran mode."
77
  :prefix "fortran-"
78
  :group  'fortran)
79 80 81


(defcustom fortran-tab-mode-default nil
82
  "Default tabbing/carriage control style for empty files in Fortran mode.
83
A non-nil value specifies tab-digit style of continuation control.
84
A value of nil specifies that continuation lines are marked
85
with a character in column 6."
86
  :type  'boolean
87
  :group 'fortran-indent)
88

89 90 91 92 93 94 95 96 97 98 99
;; TODO add more detail of what tab mode is to doc string.
(defcustom fortran-tab-mode-string
  (propertize "/t" 'help-echo "This buffer is in Fortran TAB mode"
              'mouse-face 'mode-line-highlight
              'local-map
              (make-mode-line-mouse-map 'mouse-1
                                        (lambda ()
                                          (interactive)
                                          (describe-variable
                                           'fortran-tab-mode-string))))
  "String to appear in mode line in TAB format buffers."
100
  :type  'string
101
  :group 'fortran-indent)
102

103 104
(put 'fortran-tab-mode-string 'risky-local-variable t)

105
(defcustom fortran-do-indent 3
106
  "Extra indentation applied to DO blocks."
107
  :type  'integer
108 109 110
  :group 'fortran-indent)

(defcustom fortran-if-indent 3
111
  "Extra indentation applied to IF, SELECT CASE and WHERE blocks."
112
  :type  'integer
113 114 115
  :group 'fortran-indent)

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

(defcustom fortran-continuation-indent 5
121
  "Extra indentation applied to continuation lines."
122
  :type  'integer
123 124 125
  :group 'fortran-indent)

(defcustom fortran-comment-indent-style 'fixed
126
  "How to indent comments.
127 128 129 130
nil forces comment lines not to be touched;
`fixed' indents to `fortran-comment-line-extra-indent' columns beyond
  `fortran-minimum-statement-indent-fixed' (if `indent-tabs-mode' nil), or
  `fortran-minimum-statement-indent-tab' (if `indent-tabs-mode' non-nil);
131 132
`relative' indents to current Fortran indentation plus
  `fortran-comment-line-extra-indent'."
133
  :type  '(radio (const :tag "Untouched" nil) (const fixed) (const relative))
134 135 136
  :group 'fortran-indent)

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

142
(defcustom fortran-comment-line-start "C"
143
  "Delimiter inserted to start new full-line comment.
144
You might want to change this to \"*\", for instance."
145
  :version "21.1"
146 147
  :type    'string
  :group   'fortran-comment)
148

149 150 151
;; 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
Dave Love's avatar
Dave Love committed
152
  "^[CcDd*!]\\(\\([^ \t\n]\\)\\2+\\)?[ \t]*"
153
  "Regexp to match the start of a full-line comment."
154
  :version "21.1"
155 156
  :type    'regexp
  :group   'fortran-comment)
157

158
(defcustom fortran-directive-re
159
  "^[ \t]*#.*"
160
  "Regexp to match a directive line.
161 162
The matching text will be fontified with `font-lock-keyword-face'.
The matching line will be given zero indentation."
163
  :version "22.1"
164 165
  :type    'regexp
  :group   'fortran-indent)
166

167
(defcustom fortran-minimum-statement-indent-fixed 6
168
  "Minimum statement indentation for fixed format continuation style."
169
  :type  'integer
170 171 172
  :group 'fortran-indent)

(defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
173
  "Minimum statement indentation for TAB format continuation style."
174
  :type  'integer
175
  :group 'fortran-indent)
Jim Blandy's avatar
Jim Blandy committed
176 177 178 179

;; 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.
180
(defcustom fortran-comment-indent-char " "
181
  "Single-character string inserted for Fortran comment indentation.
182
Normally a space."
183
  :type  'string
184
  :group 'fortran-comment)
Jim Blandy's avatar
Jim Blandy committed
185

186
(defcustom fortran-line-number-indent 1
187
  "Maximum indentation for Fortran line numbers.
188
5 means right-justify them within their five-column field."
189
  :type  'integer
190
  :group 'fortran-indent)
Jim Blandy's avatar
Jim Blandy committed
191

192
(defcustom fortran-check-all-num-for-matching-do nil
193
  "Non-nil causes all numbered lines to be treated as possible DO loop ends."
194
  :type  'boolean
195
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
196

197
(defcustom fortran-blink-matching-if nil
198
  "Non-nil causes \\[fortran-indent-line] on ENDIF to blink on matching IF.
199
Also, from an ENDDO statement blink on matching DO [WHILE] statement."
200
  :type  'boolean
201
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
202

203
(defcustom fortran-continuation-string "$"
204
  "Single-character string used for Fortran continuation lines.
Jim Blandy's avatar
Jim Blandy committed
205 206
In fixed format continuation style, this character is inserted in
column 6 by \\[fortran-split-line] to begin a continuation line.
207 208 209 210
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. Normally $."
  :type  'string
211
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
212

213
(defcustom fortran-comment-region "c$$$"
214
  "String inserted by \\[fortran-comment-region] at start of each \
215
line in region."
216
  :type  'string
217
  :group 'fortran-comment)
Jim Blandy's avatar
Jim Blandy committed
218

219
(defcustom fortran-electric-line-number t
220
  "Non-nil causes line numbers to be moved to the correct column as typed."
221
  :type  'boolean
222
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
223

224
;; TODO use fortran-line-length, somehow.
225
(defcustom fortran-column-ruler-fixed
226
  "0   4 6  10        20        30        40        5\
227
0        60        70\n\
228 229
\[   ]|{   |    |    |    |    |    |    |    |    \
\|    |    |    |    |}\n"
Dave Love's avatar
Dave Love committed
230
  "String displayed above current line by \\[fortran-column-ruler].
231 232 233 234
This variable is used in fixed format mode.
See the variable `fortran-column-ruler-tab' for TAB format mode."
  :type  'string
  :group 'fortran)
235

236
;; TODO use fortran-line-length, somehow.
237
(defcustom fortran-column-ruler-tab
238
  "0       810        20        30        40        5\
239
0        60        70\n\
240 241
\[   ]|  { |    |    |    |    |    |    |    |    \
\|    |    |    |    |}\n"
Dave Love's avatar
Dave Love committed
242
  "String displayed above current line by \\[fortran-column-ruler].
243 244 245 246
This variable is used in TAB format mode.
See the variable `fortran-column-ruler-fixed' for fixed format mode."
  :type  'string
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
247

248 249 250 251
(defcustom fortran-analyze-depth 100
  "Number of lines to scan to identify fixed or TAB format style."
  :type  'integer
  :group 'fortran)
Jim Blandy's avatar
Jim Blandy committed
252

253
(defcustom fortran-break-before-delimiters t
254
  "Non-nil causes filling to break lines before delimiters.
255
Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
256
  :type  'boolean
257
  :group 'fortran)
Richard M. Stallman's avatar
Richard M. Stallman committed
258

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
;; TODO 0 as no-limit, as per g77.
(defcustom fortran-line-length 72
  "Maximum number of characters in a line of fixed-form Fortran code.
Characters beyond this point are treated as comments.  Setting
this variable directly (after fortran mode is loaded) does not
take effect.  Use either \\[customize] (which affects all Fortran
buffers and the default) or the function
`fortran-line-length' (which can also operate on just the current
buffer).  This corresponds to the g77 compiler option
`-ffixed-line-length-N'."
  :type 'integer
  :initialize 'custom-initialize-default
  :set (lambda (symbol value)
         ;; Do all fortran buffers, and the default.
         (fortran-line-length value t))
  :version "23.1"
  :group 'fortran)

(put 'fortran-line-length 'safe-local-variable 'integerp)
(make-variable-buffer-local 'fortran-line-length)

(defcustom fortran-mode-hook nil
  "Hook run when entering Fortran mode."
  :type  'hook
  :group 'fortran)


286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
(defconst fortran-break-delimiters-re "[-+*/><=, \t]"
  "Regexp matching delimiter characters at which lines may be broken.
There are certain tokens comprised entirely of characters
matching this regexp that should not be split, and these are
specified by the constant `fortran-no-break-re'.")

;; The ">=", etc F77 extensions are supported by g77.
(defconst fortran-no-break-re
  (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=") 'paren)
  "Regexp specifying where not to break lines when filling.
This regexp matches certain tokens comprised entirely of
characters matching the regexp `fortran-break-delimiters-re' that should
not be split by filling.  Each element is assumed to be two
characters long.")

301
(defconst fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*("
302 303
  "Regexp matching the start of an IF statement.")

304
(defconst fortran-end-prog-re1
305 306 307 308
  "end\
\\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\
\\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?"
  "Regexp possibly matching the end of a subprogram.")
309

310
(defconst fortran-end-prog-re
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
  (concat "^[ \t0-9]*" fortran-end-prog-re1)
  "Regexp possibly matching the end of a subprogram, from the line start.
See also `fortran-end-prog-re1'.")

(defconst fortran-type-types
  (concat "\\<"
          (mapconcat 'identity          ; " " -> "[ \t]*"
                     (split-string
                      (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)) 'paren))
                     "[ \t]*") "\\>")
  "Regexp matching Fortran types.")

(defvar fortran-font-lock-keywords-1
  ;; Program, subroutine and function declarations, plus calls.
  '(("\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|\
program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?"
     (1 font-lock-keyword-face)
     (2 font-lock-function-name-face nil t)))
346
  "Subdued level highlighting for Fortran mode.")
347

348 349 350 351 352 353 354 355 356 357 358 359
(defvar fortran-font-lock-keywords-2
  (append fortran-font-lock-keywords-1
          (list
           ;; Fontify all type specifiers (must be first - see below).
           (cons fortran-type-types 'font-lock-type-face)
           ;; Builtin keywords (except logical, do and goto - see below).
           (concat "\\<" (regexp-opt
                          '("continue" "format" "end" "enddo"
                            "if" "then" "else" "endif" "elseif"
                            "while" "inquire" "stop" "return"
                            "include" "open" "close" "read"
                            "write" "format" "print" "select" "case"
360 361
                            "cycle" "exit" "rewind" "backspace"
                            "where" "elsewhere")
362 363 364 365 366 367 368 369 370 371 372
                          'paren) "\\>")
           ;; Builtin operators.
           (concat "\\." (regexp-opt
                          '("and" "or" "not" "lt" "le" "eq" "ge"
                            "gt" "ne" "true" "false")
                          'paren) "\\.")
           ;; do/goto keywords and targets, and goto tags.
           '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?"
             (1 font-lock-keyword-face)
             (2 font-lock-constant-face nil t))
           '("^ *\\([0-9]+\\)" . font-lock-constant-face)))
373 374
  "Medium level highlighting for Fortran mode.")

375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
(defvar fortran-font-lock-keywords-3
  (append
   fortran-font-lock-keywords-1
   ;; All type specifiers plus their declared items.
   (list
    (list (concat fortran-type-types "[ \t(/]*\\(*\\)?")
          ;; Type specifier.
          '(1 font-lock-type-face)
          ;; Declaration item (or just /.../ block name).
          `(font-lock-match-c-style-declaration-item-and-skip-to-next
            ;; Start after any *(...) expression.
            (condition-case nil
                (and (match-beginning ,(1+ (regexp-opt-depth
                                            fortran-type-types)))
                     (forward-sexp)
                     (forward-sexp))
              (error nil))
            ;; No need to clean up.
            nil
            ;; Fontify as a variable name, functions fontified elsewhere.
            (1 font-lock-variable-name-face nil t))))
   ;; Things extra to `fortran-font-lock-keywords-3' (must be done first).
   (list
    ;; 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))
    ;; Standard continuation character and in a TAB-formatted line.
    '("^ \\{5\\}\\([^ 0\n]\\)" 1 font-lock-string-face)
    '("^\t\\([1-9]\\)"         1 font-lock-string-face))
   `((,fortran-directive-re (0 font-lock-keyword-face t)))
   ;; `fortran-font-lock-keywords-2' without types (see above).
   (cdr (nthcdr (length fortran-font-lock-keywords-1)
                fortran-font-lock-keywords-2)))
408 409
  "Gaudy level highlighting for Fortran mode.")

410 411 412 413 414 415 416 417 418 419 420
(defvar fortran-font-lock-keywords-4
  (append fortran-font-lock-keywords-3
          (list (list
                 (concat "\\<"
                         (regexp-opt
                          '("int" "ifix" "idint" "real" "float" "sngl"
                            "dble" "cmplx" "ichar" "char" "aint" "dint"
                            "anint" "dnint" "nint" "idnint" "iabs" "abs"
                            "dabs" "cabs" "mod" "amod" "dmod" "isign"
                            "sign" "dsign" "idim" "dim" "ddim" "dprod"
                            "max" "max0" "amax1" "dmax1" "amax0" "max1"
421 422
                            "min" "min0" "amin1" "dmin1" "amin0" "min1"
                            "len" "index" "lge" "lgt" "lle" "llt" "aimag"
423 424 425 426 427 428 429 430 431 432
                            "conjg" "sqrt" "dsqrt" "csqrt" "exp" "dexp"
                            "cexp" "log" "alog" "dlog" "clog" "log10"
                            "alog10" "dlog10" "sin" "dsin" "csin" "cos"
                            "dcos" "ccos" "tan" "dtan" "asin" "dasin"
                            "acos" "dacos" "atan" "datan" "atan2" "datan2"
                            "sinh" "dsinh" "cosh" "dcosh" "tanh" "dtanh")
                          'paren) "[ \t]*(") '(1 font-lock-builtin-face))))
  "Maximum highlighting for Fortran mode.
Consists of level 3 plus all other intrinsics not already highlighted.")

433 434 435 436 437
;; 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.
438 439 440 441 442
(defun fortran-font-lock-syntactic-keywords ()
  "Return a value for `font-lock-syntactic-keywords' in Fortran mode.
This varies according to the value of `fortran-line-length'.
This is used to fontify fixed-format Fortran comments."
  `(("^[cd\\*]" 0 (11))
443
    (,(format "^[^cd\\*\t\n].\\{%d\\}\\([^\n]+\\)" (1- fortran-line-length))
444
     1 (11))))
445

446 447
(defvar fortran-font-lock-keywords fortran-font-lock-keywords-1
  "Default expressions to highlight in Fortran mode.")
448

449
(defvar fortran-imenu-generic-expression
450 451
  ;; These patterns could be confused by sequence nos. in cols 72+ and
  ;; don't allow continuations everywhere.
452 453 454
  (list
   (list
    nil
455 456 457 458 459 460 461 462 463 464 465 466 467
    ;; [This will be fooled by `end function' allowed by G77.  Also,
    ;; it assumes sensible whitespace is employed.]
    (concat
     ;; leading whitespace:
     "^\\s-+\\("
     ;; function declaration with optional type, e.g. `real',
     ;; `real*4', character(*), `double precision':
     "\\(\\sw\\|\\s-\\|[*()+]\\)*"
     "\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)"
     ;; Possible statement continuation:
     "[ \t" fortran-continuation-string "]+"
     ;; Variable to index:
     "\\(\\sw+\\)")
468
    3)
469 470 471 472
   ;; Un-named block data.
   '(nil "^\\s-+\\(block\\s-*data\\)\\s-*$" 1))
  "Value for `imenu-generic-expression' in Fortran mode.")

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 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

;; Hideshow support.
(defconst fortran-blocks-re
  (concat "block[ \t]*data\\|select[ \t]*case\\|"
          (regexp-opt '("do" "if" "interface" "function" "map" "program"
                        "structure" "subroutine" "union" "where")))
  "Regexp potentially indicating the start or end of a Fortran \"block\".
Omits naked END statements, and DO-loops closed by anything other
than ENDDO.")

(defconst fortran-end-block-re
  ;; Do-loops terminated by things other than ENDDO cannot be handled
  ;; with a regexp. This omission does not seem to matter to hideshow...
  (concat "^[ \t0-9]*\\<end[ \t]*\\("
          fortran-blocks-re
          ;; Naked END statement.
          "\\|!\\|$\\)")
  "Regexp matching the end of a Fortran \"block\", from the line start.
Note that only ENDDO is handled for the end of a DO-loop.  Used
in the Fortran entry in `hs-special-modes-alist'.")

(defconst fortran-start-block-re
  (concat
   "^[ \t0-9]*\\("                      ; statement number
   ;; Structure label for DO, IF, SELECT, WHERE.
   "\\(\\(\\sw+[ \t]*:[ \t]*\\)?"
   ;; IF blocks are a nuisance:
   ;; IF ( ... ) foo   is not a block, but a single statement.
   ;; IF ( ... ) THEN  can be split over multiple lines.
   ;; [So can, eg, a DO WHILE (... ), but that is less common, I hope.]
   ;; The regexp below allows for it to be split over at most 2 lines.
   ;; That leads to the problem of not matching two consecutive IF
   ;; statements as one, eg:
   ;; IF ( ... ) foo
   ;; IF ( ... ) THEN
   ;; It simply is not possible to do this in a 100% correct fashion
   ;; using a regexp - see the functions fortran-end-if,
   ;; fortran-beginning-if for the hoops we have to go through.
   ;; An alternative is to match on THEN at a line end, eg:
   ;;   ".*)[ \t]*then[ \t]*\\($\\|!\\)"
   ;; This would also match ELSE branches, though. This does not seem
   ;; right to me, because then one has neighbouring blocks that are
   ;; not nested in each other.
   "\\(if[ \t]*(\\(.*\\|"
   ".*\n\\([^if]*\\([^i].\\|.[^f]\\|.\\>\\)\\)\\)\\<then\\|"
   "do\\|select[ \t]*case\\|where\\)\\)\\|"
   (regexp-opt '("interface" "function" "map" "program"
                 "structure" "subroutine" "union"))
   "\\|block[ \t]*data\\)[ \t]*")
  "Regexp matching the start of a Fortran \"block\", from the line start.
A simple regexp cannot do this in fully correct fashion, so this
tries to strike a compromise between complexity and flexibility.
Used in the Fortran entry in `hs-special-modes-alist'.")

(add-to-list 'hs-special-modes-alist
	     `(fortran-mode ,fortran-start-block-re ,fortran-end-block-re
                            "^[cC*!]" fortran-end-of-block nil))

531 532 533 534 535 536 537 538 539 540 541 542 543 544

(defvar fortran-mode-syntax-table
  (let ((table (make-syntax-table)))
    ;; We might like `;' to be punctuation (g77 multi-statement
    ;; lines), but that screws abbrevs.
    (modify-syntax-entry ?\; "w"  table)
    (modify-syntax-entry ?\r " "  table)
    (modify-syntax-entry ?+  "."  table)
    (modify-syntax-entry ?-  "."  table)
    (modify-syntax-entry ?=  "."  table)
    (modify-syntax-entry ?*  "."  table)
    (modify-syntax-entry ?/  "."  table)
    (modify-syntax-entry ?\' "\"" table)
    (modify-syntax-entry ?\" "\"" table)
545 546
    ;; Consistent with GNU Fortran's default -- see the manual.
    ;; The F77 standard imposes no rule on this issue.
547 548 549 550 551 552 553 554 555 556
    (modify-syntax-entry ?\\ "\\" table)
    ;; This might be better as punctuation, as for C, but this way you
    ;; can treat floating-point numbers as symbols.
    (modify-syntax-entry ?.  "_"  table) ; e.g. `a.ne.b'
    (modify-syntax-entry ?_  "_"  table)
    (modify-syntax-entry ?$  "_"  table) ; esp. VMSisms
    (modify-syntax-entry ?\! "<"  table)
    (modify-syntax-entry ?\n ">"  table)
    table)
  "Syntax table used in Fortran mode.")
557

558 559 560 561 562 563
(defvar fortran-gud-syntax-table
  (let ((st (make-syntax-table fortran-mode-syntax-table)))
    (modify-syntax-entry ?\n "." st)
    st)
  "Syntax table used to parse Fortran expressions for printing in GUD.")

564
(defvar fortran-mode-map
565
  (let ((map (make-sparse-keymap)))
566 567 568 569
    (define-key map ";"        'fortran-abbrev-start)
    (define-key map "\C-c;"    'fortran-comment-region)
    (define-key map "\M-;"     'fortran-indent-comment)
    (define-key map "\M-\n"    'fortran-split-line)
570 571
    (define-key map "\M-\C-n"  'fortran-end-of-block)
    (define-key map "\M-\C-p"  'fortran-beginning-of-block)
572
    (define-key map "\M-\C-q"  'fortran-indent-subprogram)
573 574 575 576 577
    (define-key map "\C-c\C-w" 'fortran-window-create-momentarily)
    (define-key map "\C-c\C-r" 'fortran-column-ruler)
    (define-key map "\C-c\C-p" 'fortran-previous-statement)
    (define-key map "\C-c\C-n" 'fortran-next-statement)
    (define-key map "\C-c\C-d" 'fortran-join-line) ; like f90
578
    (define-key map "\M-^"     'fortran-join-line) ; subvert delete-indentation
579 580 581 582 583 584 585 586 587 588
    (define-key map "0" 'fortran-electric-line-number)
    (define-key map "1" 'fortran-electric-line-number)
    (define-key map "2" 'fortran-electric-line-number)
    (define-key map "3" 'fortran-electric-line-number)
    (define-key map "4" 'fortran-electric-line-number)
    (define-key map "5" 'fortran-electric-line-number)
    (define-key map "6" 'fortran-electric-line-number)
    (define-key map "7" 'fortran-electric-line-number)
    (define-key map "8" 'fortran-electric-line-number)
    (define-key map "9" 'fortran-electric-line-number)
589

590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
    (easy-menu-define fortran-menu map "Menu for Fortran mode."
      `("Fortran"
        ["Manual" (info "(emacs)Fortran")]
        ("Customization"
         ,(custom-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]
         )
        "--"
        ["Comment Region" fortran-comment-region mark-active]
        ["Uncomment 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]
620 621
        ;; May not be '72', depending on fortran-line-length, but this
        ;; seems ok for a menu item.
622 623 624
        ["72-column window"       fortran-window-create t]
        ["Full Width Window"
         (enlarge-window-horizontally (- (frame-width) (window-width)))
625
         (not (window-full-width-p))]
626 627 628 629 630 631 632 633 634 635 636 637 638
        ["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]
        "--"
        ["Toggle auto-fill"   auto-fill-mode :selected auto-fill-function
         :style toggle]
        ["Toggle abbrev-mode" abbrev-mode    :selected abbrev-mode
         :style toggle]
        ["Add imenu Menu" imenu-add-menubar-index
         :active   (not (lookup-key (current-local-map) [menu-bar index]))
         :included (fboundp 'imenu-add-to-menubar)]))
639
    map)
Richard M. Stallman's avatar
Richard M. Stallman committed
640
  "Keymap used in Fortran mode.")
641

Jim Blandy's avatar
Jim Blandy committed
642

643
(defvar fortran-mode-abbrev-table
644
  (progn
645
    (define-abbrev-table 'fortran-mode-abbrev-table nil)
646 647 648 649 650 651
    fortran-mode-abbrev-table)
  "Abbrev table for Fortran mode.")

(let (abbrevs-changed)
  ;; Use the 6th arg (SYSTEM-FLAG) of define-abbrev if possible.
  ;; Only use `apply' to quieten the byte-compiler.
652
  (mapc
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
   (function (lambda (element)
               (condition-case nil
                   (apply 'define-abbrev fortran-mode-abbrev-table
                          (append element '(nil 0 t)))
                 (wrong-number-of-arguments
                  (apply 'define-abbrev fortran-mode-abbrev-table
                         (append element '(nil 0)))))))
   '((";au"   "automatic"         )
     (";b"    "byte"              )
     (";bd"   "block data"        )
     (";ch"   "character"         )
     (";cl"   "close"             )
     (";c"    "continue"          )
     (";cm"   "common"            )
     (";cx"   "complex"           )
     (";df"   "define"            )
     (";di"   "dimension"         )
     (";do"   "double"            )
     (";dc"   "double complex"    )
     (";dp"   "double precision"  )
     (";dw"   "do while"          )
     (";e"    "else"              )
     (";ed"   "enddo"             )
     (";el"   "elseif"            )
     (";en"   "endif"             )
     (";eq"   "equivalence"       )
     (";ew"   "endwhere"          )
     (";ex"   "external"          )
     (";ey"   "entry"             )
     (";f"    "format"            )
     (";fa"   ".false."           )
     (";fu"   "function"          )
     (";g"    "goto"              )
     (";im"   "implicit"          )
     (";ib"   "implicit byte"     )
     (";ic"   "implicit complex"  )
     (";ich"  "implicit character")
     (";ii"   "implicit integer"  )
     (";il"   "implicit logical"  )
     (";ir"   "implicit real"     )
     (";inc"  "include"           )
     (";in"   "integer"           )
     (";intr" "intrinsic"         )
     (";l"    "logical"           )
     (";n"    "namelist"          )
     (";o"    "open"              )     ; was ;op
     (";pa"   "parameter"         )
     (";pr"   "program"           )
     (";ps"   "pause"             )
     (";p"    "print"             )
     (";rc"   "record"            )
     (";re"   "real"              )
     (";r"    "read"              )
     (";rt"   "return"            )
     (";rw"   "rewind"            )
     (";s"    "stop"              )
     (";sa"   "save"              )
     (";st"   "structure"         )
     (";sc"   "static"            )
     (";su"   "subroutine"        )
     (";tr"   ".true."            )
     (";ty"   "type"              )
     (";vo"   "volatile"          )
     (";w"    "write"             )
     (";wh"   "where"             ))))
718

719

Jim Blandy's avatar
Jim Blandy committed
720 721
;;;###autoload
(defun fortran-mode ()
722 723 724
  "Major mode for editing Fortran code in fixed format.
For free format code, use `f90-mode'.

725
\\[fortran-indent-line] indents the current Fortran line correctly.
726
Note that DO statements must not share a common CONTINUE.
Jim Blandy's avatar
Jim Blandy committed
727

728 729
Type ;? or ;\\[help-command] to display a list of built-in abbrevs for\
 Fortran keywords.
Jim Blandy's avatar
Jim Blandy committed
730 731 732 733 734 735

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

Variables controlling indentation style and extra features:

736
`fortran-comment-line-start'
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
  To use comments starting with `!', set this to the string \"!\".
`fortran-do-indent'
  Extra indentation within DO blocks (default 3).
`fortran-if-indent'
  Extra indentation within IF blocks (default 3).
`fortran-structure-indent'
  Extra indentation within STRUCTURE, UNION, MAP and INTERFACE blocks.
  (default 3)
`fortran-continuation-indent'
  Extra indentation applied to continuation statements (default 5).
`fortran-comment-line-extra-indent'
  Amount of extra indentation for text in full-line comments (default 0).
`fortran-comment-indent-style'
  How to indent the text in full-line comments. Allowed values are:
  nil       don't change the indentation
  fixed     indent to `fortran-comment-line-extra-indent' beyond the
              value of either
                `fortran-minimum-statement-indent-fixed' (fixed format) or
                `fortran-minimum-statement-indent-tab' (TAB format),
              depending on the continuation format in use.
  relative  indent to `fortran-comment-line-extra-indent' beyond the
Jim Blandy's avatar
Jim Blandy committed
758
 	      indentation for a line of code.
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
  (default 'fixed)
`fortran-comment-indent-char'
  Single-character string to be inserted instead of space for
  full-line comment indentation (default \" \").
`fortran-minimum-statement-indent-fixed'
  Minimum indentation for statements in fixed format mode (default 6).
`fortran-minimum-statement-indent-tab'
  Minimum indentation for statements in TAB format mode (default 9).
`fortran-line-number-indent'
  Maximum indentation for line numbers (default 1).  A line number will
  get less than this much indentation if necessary to avoid reaching
  column 5.
`fortran-check-all-num-for-matching-do'
  Non-nil causes all numbered lines to be treated as possible \"continue\"
  statements (default nil).
`fortran-blink-matching-if'
  Non-nil causes \\[fortran-indent-line] on an ENDIF (or ENDDO) statement
  to blink on the matching IF (or DO [WHILE]).  (default nil)
`fortran-continuation-string'
  Single-character string to be inserted in column 5 of a continuation
  line (default \"$\").
`fortran-comment-region'
  String inserted by \\[fortran-comment-region] at start of each line in
  the region (default \"c$$$\").
`fortran-electric-line-number'
  Non-nil causes line number digits to be moved to the correct column
  as typed (default t).
`fortran-break-before-delimiters'
  Non-nil causes lines to be broken before delimiters (default t).
Jim Blandy's avatar
Jim Blandy committed
788

Richard M. Stallman's avatar
Richard M. Stallman committed
789
Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
Jim Blandy's avatar
Jim Blandy committed
790 791 792
with no args, if that value is non-nil."
  (interactive)
  (kill-all-local-variables)
793 794 795
  (setq major-mode 'fortran-mode
        mode-name "Fortran"
        local-abbrev-table fortran-mode-abbrev-table)
Jim Blandy's avatar
Jim Blandy committed
796
  (set-syntax-table fortran-mode-syntax-table)
797 798 799 800 801 802 803
  (use-local-map fortran-mode-map)
  (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))))
804
  (set (make-local-variable 'require-final-newline) mode-require-final-newline)
805 806 807 808
  ;; The syntax tables don't understand the column-0 comment-markers.
  (set (make-local-variable 'comment-use-syntax) nil)
  (set (make-local-variable 'comment-padding) "$$$")
  (set (make-local-variable 'comment-start) fortran-comment-line-start)
809 810 811 812 813 814
  (set (make-local-variable 'comment-start-skip)
       ;; We can't reuse `fortran-comment-line-start-skip' directly because
       ;; it contains backrefs whereas we need submatch-1 to end at the
       ;; beginning of the comment delimiter.
       ;; (concat "\\(\\)\\(![ \t]*\\|" fortran-comment-line-start-skip "\\)")
       "\\(\\)\\(?:^[CcDd*]\\|!\\)\\(?:\\([^ \t\n]\\)\\2+\\)?[ \t]*")
815 816 817 818
  (set (make-local-variable 'comment-indent-function) 'fortran-comment-indent)
  (set (make-local-variable 'abbrev-all-caps) t)
  (set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill)
  (set (make-local-variable 'indent-tabs-mode) (fortran-analyze-file-format))
819
  (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string))
820
  (set (make-local-variable 'fill-column) fortran-line-length)
821
  (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph)
822 823 824 825
  (set (make-local-variable 'font-lock-defaults)
       '((fortran-font-lock-keywords
          fortran-font-lock-keywords-1
          fortran-font-lock-keywords-2
826 827
          fortran-font-lock-keywords-3
          fortran-font-lock-keywords-4)
828
         nil t ((?/ . "$/") ("_$" . "w"))
829 830 831
         fortran-beginning-of-subprogram
         (font-lock-syntactic-keywords
          . (fortran-font-lock-syntactic-keywords))))
832 833 834 835
  (set (make-local-variable 'imenu-case-fold-search) t)
  (set (make-local-variable 'imenu-generic-expression)
       fortran-imenu-generic-expression)
  (set (make-local-variable 'imenu-syntax-alist) '(("_$" . "w")))
836 837 838 839
  (set (make-local-variable 'beginning-of-defun-function)
       #'fortran-beginning-of-subprogram)
  (set (make-local-variable 'end-of-defun-function)
       #'fortran-end-of-subprogram)
840 841
  (set (make-local-variable 'add-log-current-defun-function)
       #'fortran-current-defun)
842
  (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
843
  (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
844
  (add-hook 'hack-local-variables-hook 'fortran-hack-local-variables nil t)
845
  (run-mode-hooks 'fortran-mode-hook))
846

Jim Blandy's avatar
Jim Blandy committed
847

848 849 850 851 852 853 854
(defun fortran-line-length (nchars &optional global)
  "Set the length of fixed-form Fortran lines to NCHARS.
This normally only affects the current buffer, which must be in
Fortran mode.  If the optional argument GLOBAL is non-nil, it
affects all Fortran buffers, and also the default."
  (interactive "p")
  (let (new)
855 856 857 858 859 860 861 862 863 864 865 866 867 868
    (mapc (lambda (buff)
            (with-current-buffer buff
              (when (eq major-mode 'fortran-mode)
                (setq fortran-line-length nchars
                      fill-column fortran-line-length
                      new (fortran-font-lock-syntactic-keywords))
                ;; Refontify only if necessary.
                (unless (equal new font-lock-syntactic-keywords)
                  (setq font-lock-syntactic-keywords
                        (fortran-font-lock-syntactic-keywords))
                  (if font-lock-mode (font-lock-mode 1))))))
          (if global
              (buffer-list)
            (list (current-buffer))))
869 870 871 872 873 874 875
    (if global
        (setq-default fortran-line-length nchars))))

(defun fortran-hack-local-variables ()
  "Fortran mode adds this to `hack-local-variables-hook'."
  (fortran-line-length fortran-line-length))

876 877 878 879 880
(defun fortran-gud-find-expr ()
  ;; Consider \n as punctuation (end of expression).
  (with-syntax-table fortran-gud-syntax-table
    (gud-find-c-expr)))

881
(defsubst fortran-comment-indent ()
882 883 884 885 886
  "Return the indentation appropriate for the current comment line.
This is 0 for a line matching `fortran-comment-line-start-skip', else
the value of `comment-column' (leaving at least one space after code)."
  (if (looking-at fortran-comment-line-start-skip) 0
    (save-excursion
887
      (skip-chars-backward " \t")
Glenn Morris's avatar
Glenn Morris committed
888
      (max (1+ (current-column)) comment-column))))
Jim Blandy's avatar
Jim Blandy committed
889 890 891 892

(defun fortran-indent-comment ()
  "Align or create comment on current line.
Existing comments of all types are recognized and aligned.
893
If the line has no comment, a side-by-side comment is inserted and aligned,
894
if the value of `comment-start' is not nil and allows such comments.
Jim Blandy's avatar
Jim Blandy committed
895 896
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."
897
  (interactive "*")
Jim Blandy's avatar
Jim Blandy committed
898 899
  (beginning-of-line)
  ;; Recognize existing comments of either kind.
900 901 902 903
  (cond ((fortran-find-comment-start-skip 'all)
	 (goto-char (match-beginning 0))
	 (if (bolp)
	     (fortran-indent-line)
904 905 906
	   (unless (= (current-column) (fortran-comment-indent))
             (delete-horizontal-space)
             (indent-to (fortran-comment-indent)))))
Jim Blandy's avatar
Jim Blandy committed
907 908 909
	;; No existing comment.
	;; If side-by-side comments are defined, insert one,
	;; unless line is now blank.
910 911
	((and comment-start (not (looking-at "[ \t]*$"))
	      (string-match comment-start-skip (concat " " comment-start)))
Jim Blandy's avatar
Jim Blandy committed
912 913
	 (end-of-line)
	 (delete-horizontal-space)
914
	 (indent-to (fortran-comment-indent))
Jim Blandy's avatar
Jim Blandy committed
915 916 917 918 919 920
	 (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)
921
	   (insert ?\n)
Jim Blandy's avatar
Jim Blandy committed
922
	   (forward-char -1))
923
	 (insert fortran-comment-line-start)
Jim Blandy's avatar
Jim Blandy committed
924 925
	 (insert-char (if (stringp fortran-comment-indent-char)
			  (aref fortran-comment-indent-char 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
926
			fortran-comment-indent-char)
927
		      (- (fortran-calculate-indent) (current-column))))))
Jim Blandy's avatar
Jim Blandy committed
928 929

(defun fortran-comment-region (beg-region end-region arg)
930 931 932 933
  "Comment every line in the region.
Inserts the string variable `fortran-comment-region' at the beginning of
every line in the region.
BEG-REGION and END-REGION specify the region boundaries.
Jim Blandy's avatar
Jim Blandy committed
934 935
With non-nil ARG, uncomments the region."
  (interactive "*r\nP")
936
  (let ((end-region-mark (copy-marker end-region))
937
	(save-point (point-marker)))
Jim Blandy's avatar
Jim Blandy committed
938 939
    (goto-char beg-region)
    (beginning-of-line)
940
    (if arg
Glenn Morris's avatar
Glenn Morris committed
941
        (let ((com (regexp-quote fortran-comment-region))) ; uncomment
942 943 944 945 946 947
          (if (looking-at com)
              (delete-region (point) (match-end 0)))
          (while (and (zerop (forward-line 1))
                      (< (point) end-region-mark))
            (if (looking-at com)
                (delete-region (point) (match-end 0)))))
Glenn Morris's avatar
Glenn Morris committed
948
      (insert fortran-comment-region)   ; comment
949 950 951
      (while (and (zerop (forward-line 1))
                  (< (point) end-region-mark))
        (insert fortran-comment-region)))
Jim Blandy's avatar
Jim Blandy committed
952 953 954
    (goto-char save-point)
    (set-marker end-region-mark nil)
    (set-marker save-point nil)))
955

Jim Blandy's avatar
Jim Blandy committed
956 957

(defun fortran-abbrev-start ()
958
  "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs.
Jim Blandy's avatar
Jim Blandy committed
959
Any other key combination is executed normally."
960
  (interactive "*")
961
  (insert last-command-char)
962 963 964 965 966
  (let* ((event (if (fboundp 'next-command-event) ; XEmacs
                    (next-command-event)
                  (read-event)))
         (char (if (fboundp 'event-to-character)
                   (event-to-character event) event)))
967
    ;; Insert char if not equal to `?', or if abbrev-mode is off.
968 969
    (if (and abbrev-mode (or (eq char ??) (eq char help-char)
                             (memq event help-event-list)))
Jim Blandy's avatar
Jim Blandy committed
970
	(fortran-abbrev-help)
971
      (push event unread-command-events))))
Jim Blandy's avatar
Jim Blandy committed
972 973 974 975 976

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

980
(defun fortran-prepare-abbrev-list-buffer ()
981
  "Create a buffer listing the Fortran mode abbreviations."
982
  (with-current-buffer (get-buffer-create "*Abbrevs*")
983
    (erase-buffer)
984
    (insert-abbrev-table-description 'fortran-mode-abbrev-table t)
985 986 987 988 989
    (goto-char (point-min))
    (set-buffer-modified-p nil)
    (edit-abbrevs-mode))
  (get-buffer-create "*Abbrevs*"))

Jim Blandy's avatar
Jim Blandy committed
990
(defun fortran-column-ruler ()
991
  "Insert a column ruler momentarily above current line, till next keystroke.
Glenn Morris's avatar
Glenn Morris committed
992 993 994
The ruler is defined by the value of `fortran-column-ruler-fixed' in fixed
format mode, and `fortran-column-ruler-tab' in TAB format mode.
The next key typed is executed unless it is SPC."
Jim Blandy's avatar
Jim Blandy committed
995
  (interactive)
996
  (momentary-string-display
997 998 999 1000
   (if indent-tabs-mode
       fortran-column-ruler-tab
     fortran-column-ruler-fixed)
   (save-excursion
1001
     (beginning-of-line)
1002 1003
     (if (eq (window-start (selected-window))
	     (window-point (selected-window)))
1004
	 (line-beginning-position 2)
1005
       (point)))
Jim Blandy's avatar
Jim Blandy committed
1006 1007 1008
   nil "Type SPC or any command to erase ruler."))

(defun fortran-window-create ()
1009
  "Make the window `fortran-line-length' (default 72) columns wide.
Christopher Zaborsky's avatar
Christopher Zaborsky committed
1010
See also `fortran-window-create-momentarily'."
Jim Blandy's avatar
Jim Blandy committed
1011
  (interactive)
1012
  (let ((window-min-width 2))
1013
    (unless (window-full-width-p)
1014 1015 1016 1017 1018 1019
	(enlarge-window-horizontally (- (frame-width)
					(window-width) 1)))
    (let* ((window-edges (window-edges))
	   (scroll-bar-width (- (nth 2 window-edges)
				(car window-edges)
				(window-width))))
1020
      (split-window-horizontally (+ fortran-line-length scroll-bar-width)))
1021 1022 1023
    (other-window 1)
    (switch-to-buffer " fortran-window-extra" t)
    (select-window (previous-window))))
Jim Blandy's avatar
Jim Blandy committed
1024 1025

(defun fortran-window-create-momentarily (&optional arg)
1026
  "Momentarily make the window `fortran-line-length' (default 72) columns wide.
Jim Blandy's avatar
Jim Blandy committed
1027
Optional ARG non-nil and non-unity disables the momentary feature.
Christopher Zaborsky's avatar
Christopher Zaborsky committed
1028
See also `fortran-window-create'."
Jim Blandy's avatar
Jim Blandy committed
1029 1030 1031 1032
  (interactive "p")
  (if (or (not arg)
	  (= arg 1))
      (save-window-excursion
1033 1034 1035 1036 1037 1038
	(progn
	  (condition-case nil
	      (fortran-window-create)
	    (error (error "No room for Fortran window")))
	  (message "Type SPC to continue editing.")
	  (let ((char (read-event)))
1039
	    (or (equal char ?\s)
1040
		(setq unread-command-events (list char))))))
Jim Blandy's avatar
Jim Blandy committed
1041 1042 1043 1044
    (fortran-window-create)))

(defun fortran-split-line ()
  "Break line at point and insert continuation marker and alignment."
1045
  (interactive "*")
Jim Blandy's avatar
Jim Blandy committed
1046
  (delete-horizontal-space)
1047
  (if (save-excursion