aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Blandy1991-07-15 21:21:23 +0000
committerJim Blandy1991-07-15 21:21:23 +0000
commit3dd637609876e12908bfa554b80a1c2145c98ed3 (patch)
treefd75ddf524aea06f2a89affce3f4eb17fbba1684
parent9c74a0dd25800566a4afdecd0d61d073dee47b05 (diff)
downloademacs-3dd637609876e12908bfa554b80a1c2145c98ed3.tar.gz
emacs-3dd637609876e12908bfa554b80a1c2145c98ed3.zip
Initial revision
-rw-r--r--lisp/progmodes/fortran.el997
1 files changed, 997 insertions, 0 deletions
diff --git a/lisp/progmodes/fortran.el b/lisp/progmodes/fortran.el
new file mode 100644
index 00000000000..33a2da4b182
--- /dev/null
+++ b/lisp/progmodes/fortran.el
@@ -0,0 +1,997 @@
1;;; Fortran mode for GNU Emacs (version 1.28.3, July 15, 1991)
2;;; Copyright (c) 1991 Free Software Foundation, Inc.
3;;; Written by Michael D. Prange (prange@erl.mit.edu)
4;;; Maintained (as of version 1.28) by Stephen A. Wood (saw@hallc1.cebaf.gov)
5;;; This version is an update of version 1.21 (Oct 1, 1985).
6;;; Updated by Stephen A. Wood (saw@hallc1.cebaf.gov) to use tab format
7;;; continuation control and indentation. (Digit after TAB to signify
8;;; continuation line. This version also incorporates suggestions from
9;;; Richard Stallman, and the ideas in two previous unpublished versions of
10;;; fortran .el (version 1.21.1 (from gildea@expo.lcs.mit.edu) and 1.27
11;;; (prange@erl.mit.edu).)
12
13;;; Notes to fortran-mode version 1.28
14;;; 1. Fortran mode can support either fixed format or tab format. Fixed
15;;; format is where statements start in column 6 (first column is 0)
16;;; and continuation lines are denoted by a character in column 5.
17;;; In tab mode, statements follow a tab character. Continuation lines
18;;; are where the first character on a line is a tab and the second is
19;;; a digit from 1 to 9.
20;;; 2. When fortran mode is called, the buffer is analyzed to determine what
21;;; kind of formating is used. Starting at the top of the file, lines
22;;; are scanned until a line is found that begins with a tab or 6 spaces.
23;;; The mode for that buffer is then set to either tab or fixed format
24;;; based on that line. If no line starting with a tab or 6 spaces is
25;;; found before the end of the buffer or in the first 100 lines, the
26;;; mode is set from the variable `fortran-tab-mode-default'. t is tab
27;;; mode, nil is fixed format mode. By default, fixed format mode is used.
28;;; To use tabbing mode as the default, put the following line in .emacs
29;;; (setq fortran-tab-mode-default t)
30;;; This line should not be in the hook since the hook is called only
31;;; after the file is analyzed.
32;;; To force a particular mode independent of the analysis, attach
33;;; (fortran-tab-mode t) or (fortran-tab-mode nil)
34;;; to fortran-mode-hook.
35;;; 3. The command `fortran-tab-mode' will toggle between fixed and tab
36;;; formatting modes. The file will not automatically be reformatted,
37;;; but either `indent-region' or `fortran-indent-subprogram' can be
38;;; used to reformat portions of the file.
39;;; 4. Several abbreviations have been added. Abbreviation mode is turned
40;;; on by default.
41;;; 5. The routine fortran-blink-matching if has been incorporated (from
42;;; experimental version 1.27). If the variable of the same name is set
43;;; to t, the the matching if statement is blinked whenever an endif
44;;; line is indented.
45;;; 6. C-c C-w is now bound to fortran-window-create-momentarily (from
46;;; experimental version 1.27.)
47;;; 7. LFD is now bound to fortran-reindent-then-newline-and-indent.
48;;; 8. fortran-continuation-string (was fortran-continuation-char) is now
49;;; a string rather than a character.
50;;; 9. Fixed a bug from 1.21 that gave max-lisp-eval-depth exceeded when
51;;; Comments lines had !'s in them.
52;;; 10. DEC fortran recognizes a & in the first column as a continuation.
53;;; character. This mode does not recognize the & as a continuation
54;;; character.
55;;; 11. fortran-blink-matching-if still is in effect when indenting a region.
56;;; Is this a desirable effect? (It looks kind of neat)
57;;; 12. If you strike a digit and there are exactly 5 characters, all spaces
58;;; to the left of the point, the digit will be inserted in place to
59;;; serve as a continuation line marker. Similarly, if the only thing to
60;;; the left of the point is a single tab, and the last command issued
61;;; was neither fortran-indent-line (TAB) or fortran-reindent-then-newline-
62;;; and-indent (LFD), the digit is inserted as a tab format style
63;;; continuation character.
64;;; 13. Both modes should usually work with tab-width set to other than 8.
65;;; However, in tab-mode, if tab-width is less than 6, the column number
66;;; for the minimum indentation is set to 6 so that all line numbers will
67;;; have have a tab after them. This may be a bit ugly, but why would
68;;; you want to use a tab-width other than 8 anyway?
69;;; 14. When in tab mode, the fortran column ruler will not be correct if
70;;; tab-width is not 8.
71
72;; This file is part of GNU Emacs.
73
74;; GNU Emacs is free software; you can redistribute it and/or modify
75;; it under the terms of the GNU General Public License as published by
76;; the Free Software Foundation; either version 1, or (at your option)
77;; any later version.
78
79;; GNU Emacs is distributed in the hope that it will be useful,
80;; but WITHOUT ANY WARRANTY; without even the implied warranty of
81;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82;; GNU General Public License for more details.
83
84;; You should have received a copy of the GNU General Public License
85;; along with GNU Emacs; see the file COPYING. If not, write to
86;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
87
88;;; Author acknowledges help from Stephen Gildea <gildea@erl.mit.edu>
89
90;;; Bugs to bug-fortran-mode@erl.mit.edu
91
92(provide 'fortran)
93
94;;;###autoload
95(defvar fortran-tab-mode-default nil
96 "*Default tabbing/carriage control style for empty files in fortran mode.
97t indicates that tab-digit style of continuation control will be used.
98nil indicates that continuation lines are marked with a character in
99column 6.")
100
101(defvar fortran-do-indent 3
102 "*Extra indentation applied to `do' blocks.")
103
104(defvar fortran-if-indent 3
105 "*Extra indentation applied to `if' blocks.")
106
107(defvar fortran-continuation-indent 5
108 "*Extra indentation applied to `continuation' lines.")
109
110(defvar fortran-comment-indent-style 'fixed
111 "*nil forces comment lines not to be touched,
112'fixed produces fixed comment indentation to comment-column,
113and 'relative indents to current fortran indentation plus comment-column.")
114
115(defvar fortran-comment-line-column 6
116 "*Indentation for text in comment lines.")
117
118(defvar comment-line-start nil
119 "*Delimiter inserted to start new full-line comment.")
120
121(defvar comment-line-start-skip nil
122 "*Regexp to match the start of a full-line comment.")
123
124(defvar fortran-minimum-statement-indent 6
125 "*Minimum indentation for fortran statements.")
126
127;; Note that this is documented in the v18 manuals as being a string
128;; of length one rather than a single character.
129;; The code in this file accepts either format for compatibility.
130(defvar fortran-comment-indent-char " "
131 "*Single-character string inserted for Fortran comment indentation.
132Normally a space.")
133
134(defvar fortran-line-number-indent 1
135 "*Maximum indentation for Fortran line numbers.
1365 means right-justify them within their five-column field.")
137
138(defvar fortran-check-all-num-for-matching-do nil
139 "*Non-nil causes all numbered lines to be treated as possible do-loop ends.")
140
141(defvar fortran-blink-matching-if nil
142 "*From a fortran `endif' statement, blink the matching `if' statement.")
143
144(defvar fortran-continuation-string "$"
145 "*Single-character string used for fortran continuation lines.
146In fixed format continuation style, this character is inserted in
147column 6 by \\[fortran-split-line] to begin a continuation line.
148Also, if \\[fortran-indent-line] finds this at the beginning of a line, it will
149convert the line into a continuation line of the appropriate style.
150Normally $.")
151
152(defvar fortran-comment-region "c$$$"
153 "*String inserted by \\[fortran-comment-region]\
154 at start of each line in region.")
155
156(defvar fortran-electric-line-number t
157 "*Non-nil causes line number digits to be moved to the correct column as\
158 typed.")
159
160(defvar fortran-startup-message t
161 "*Non-nil displays a startup message when Fortran mode is first called.")
162
163(defvar fortran-column-ruler " "
164 "*String displayed above current line by \\[fortran-column-ruler].")
165
166(defconst bug-fortran-mode "bug-fortran-mode@erl.mit.edu"
167 "Address of mailing list for Fortran mode bugs.")
168
169(defconst fortran-mode-version "1.28.3")
170
171(defvar fortran-mode-syntax-table nil
172 "Syntax table in use in Fortran mode buffers.")
173
174(defvar fortran-analyze-depth 100
175 "Number of lines to scan to determine whether to use fixed or tab format\
176 style.")
177
178(if fortran-mode-syntax-table
179 ()
180 (setq fortran-mode-syntax-table (make-syntax-table))
181 (modify-syntax-entry ?\; "w" fortran-mode-syntax-table)
182 (modify-syntax-entry ?\r " " fortran-mode-syntax-table)
183 (modify-syntax-entry ?+ "." fortran-mode-syntax-table)
184 (modify-syntax-entry ?- "." fortran-mode-syntax-table)
185 (modify-syntax-entry ?= "." fortran-mode-syntax-table)
186 (modify-syntax-entry ?* "." fortran-mode-syntax-table)
187 (modify-syntax-entry ?/ "." fortran-mode-syntax-table)
188 (modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
189 (modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
190 (modify-syntax-entry ?\\ "/" fortran-mode-syntax-table)
191 (modify-syntax-entry ?. "w" fortran-mode-syntax-table)
192 (modify-syntax-entry ?\n ">" fortran-mode-syntax-table))
193
194(defvar fortran-mode-map ()
195 "Keymap used in fortran mode.")
196(if fortran-mode-map
197 ()
198 (setq fortran-mode-map (make-sparse-keymap))
199 (define-key fortran-mode-map ";" 'fortran-abbrev-start)
200 (define-key fortran-mode-map "\C-c;" 'fortran-comment-region)
201 (define-key fortran-mode-map "\e\C-a" 'beginning-of-fortran-subprogram)
202 (define-key fortran-mode-map "\e\C-e" 'end-of-fortran-subprogram)
203 (define-key fortran-mode-map "\e;" 'fortran-indent-comment)
204 (define-key fortran-mode-map "\e\C-h" 'mark-fortran-subprogram)
205 (define-key fortran-mode-map "\e\n" 'fortran-split-line)
206 (define-key fortran-mode-map "\n" 'fortran-reindent-then-newline-and-indent)
207 (define-key fortran-mode-map "\e\C-q" 'fortran-indent-subprogram)
208 (define-key fortran-mode-map "\C-c\C-w" 'fortran-window-create-momentarily)
209 (define-key fortran-mode-map "\C-c\C-r" 'fortran-column-ruler)
210 (define-key fortran-mode-map "\C-c\C-p" 'fortran-previous-statement)
211 (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement)
212 (define-key fortran-mode-map "\t" 'fortran-indent-line)
213 (define-key fortran-mode-map "0" 'fortran-electric-line-number)
214 (define-key fortran-mode-map "1" 'fortran-electric-line-number)
215 (define-key fortran-mode-map "2" 'fortran-electric-line-number)
216 (define-key fortran-mode-map "3" 'fortran-electric-line-number)
217 (define-key fortran-mode-map "4" 'fortran-electric-line-number)
218 (define-key fortran-mode-map "5" 'fortran-electric-line-number)
219 (define-key fortran-mode-map "6" 'fortran-electric-line-number)
220 (define-key fortran-mode-map "7" 'fortran-electric-line-number)
221 (define-key fortran-mode-map "8" 'fortran-electric-line-number)
222 (define-key fortran-mode-map "9" 'fortran-electric-line-number))
223
224(defvar fortran-mode-abbrev-table nil)
225(if fortran-mode-abbrev-table
226 ()
227 (let ((ac abbrevs-changed))
228 (define-abbrev-table 'fortran-mode-abbrev-table ())
229 (define-abbrev fortran-mode-abbrev-table ";au" "automatic" nil)
230 (define-abbrev fortran-mode-abbrev-table ";b" "byte" nil)
231 (define-abbrev fortran-mode-abbrev-table ";bl" "block data" nil)
232 (define-abbrev fortran-mode-abbrev-table ";ch" "character" nil)
233 (define-abbrev fortran-mode-abbrev-table ";cl" "close" nil)
234 (define-abbrev fortran-mode-abbrev-table ";c" "continue" nil)
235 (define-abbrev fortran-mode-abbrev-table ";cm" "common" nil)
236 (define-abbrev fortran-mode-abbrev-table ";cx" "complex" nil)
237 (define-abbrev fortran-mode-abbrev-table ";df" "define" nil)
238 (define-abbrev fortran-mode-abbrev-table ";di" "dimension" nil)
239 (define-abbrev fortran-mode-abbrev-table ";do" "double" nil)
240 (define-abbrev fortran-mode-abbrev-table ";dc" "double complex" nil)
241 (define-abbrev fortran-mode-abbrev-table ";dp" "double precision" nil)
242 (define-abbrev fortran-mode-abbrev-table ";dw" "do while" nil)
243 (define-abbrev fortran-mode-abbrev-table ";e" "else" nil)
244 (define-abbrev fortran-mode-abbrev-table ";ed" "enddo" nil)
245 (define-abbrev fortran-mode-abbrev-table ";el" "elseif" nil)
246 (define-abbrev fortran-mode-abbrev-table ";en" "endif" nil)
247 (define-abbrev fortran-mode-abbrev-table ";eq" "equivalence" nil)
248 (define-abbrev fortran-mode-abbrev-table ";ex" "external" nil)
249 (define-abbrev fortran-mode-abbrev-table ";ey" "entry" nil)
250 (define-abbrev fortran-mode-abbrev-table ";f" "format" nil)
251 (define-abbrev fortran-mode-abbrev-table ";fa" ".false." nil)
252 (define-abbrev fortran-mode-abbrev-table ";fu" "function" nil)
253 (define-abbrev fortran-mode-abbrev-table ";g" "goto" nil)
254 (define-abbrev fortran-mode-abbrev-table ";im" "implicit" nil)
255 (define-abbrev fortran-mode-abbrev-table ";ib" "implicit byte" nil)
256 (define-abbrev fortran-mode-abbrev-table ";ic" "implicit complex" nil)
257 (define-abbrev fortran-mode-abbrev-table ";ich" "implicit character" nil)
258 (define-abbrev fortran-mode-abbrev-table ";ii" "implicit integer" nil)
259 (define-abbrev fortran-mode-abbrev-table ";il" "implicit logical" nil)
260 (define-abbrev fortran-mode-abbrev-table ";ir" "implicit real" nil)
261 (define-abbrev fortran-mode-abbrev-table ";inc" "include" nil)
262 (define-abbrev fortran-mode-abbrev-table ";in" "integer" nil)
263 (define-abbrev fortran-mode-abbrev-table ";intr" "intrinsic" nil)
264 (define-abbrev fortran-mode-abbrev-table ";l" "logical" nil)
265 (define-abbrev fortran-mode-abbrev-table ";n" "namelist" nil)
266 (define-abbrev fortran-mode-abbrev-table ";o" "open" nil) ; was ;op
267 (define-abbrev fortran-mode-abbrev-table ";pa" "parameter" nil)
268 (define-abbrev fortran-mode-abbrev-table ";pr" "program" nil)
269 (define-abbrev fortran-mode-abbrev-table ";ps" "pause" nil)
270 (define-abbrev fortran-mode-abbrev-table ";p" "print" nil)
271 (define-abbrev fortran-mode-abbrev-table ";rc" "record" nil)
272 (define-abbrev fortran-mode-abbrev-table ";re" "real" nil)
273 (define-abbrev fortran-mode-abbrev-table ";r" "read" nil)
274 (define-abbrev fortran-mode-abbrev-table ";rt" "return" nil)
275 (define-abbrev fortran-mode-abbrev-table ";rw" "rewind" nil)
276 (define-abbrev fortran-mode-abbrev-table ";s" "stop" nil)
277 (define-abbrev fortran-mode-abbrev-table ";sa" "save" nil)
278 (define-abbrev fortran-mode-abbrev-table ";st" "structure" nil)
279 (define-abbrev fortran-mode-abbrev-table ";sc" "static" nil)
280 (define-abbrev fortran-mode-abbrev-table ";su" "subroutine" nil)
281 (define-abbrev fortran-mode-abbrev-table ";tr" ".true." nil)
282 (define-abbrev fortran-mode-abbrev-table ";ty" "type" nil)
283 (define-abbrev fortran-mode-abbrev-table ";vo" "volatile" nil)
284 (define-abbrev fortran-mode-abbrev-table ";w" "write" nil)
285 (setq abbrevs-changed ac)))
286
287;;;###autoload
288(defun fortran-mode ()
289 "Major mode for editing fortran code.
290Tab indents the current fortran line correctly.
291`do' statements must not share a common `continue'.
292
293Type `;?' or `;\\[help-command]' to display a list of built-in\
294 abbrevs for Fortran keywords.
295
296Key definitions:
297\\{fortran-mode-map}
298
299Variables controlling indentation style and extra features:
300
301 comment-start
302 Normally nil in Fortran mode. If you want to use comments
303 starting with `!', set this to the string \"!\".
304 fortran-do-indent
305 Extra indentation within do blocks. (default 3)
306 fortran-if-indent
307 Extra indentation within if blocks. (default 3)
308 fortran-continuation-indent
309 Extra indentation appled to continuation statements. (default 5)
310 fortran-comment-line-column
311 Amount of indentation for text within full-line comments. (default 6)
312 fortran-comment-indent-style
313 nil means don't change indentation of text in full-line comments,
314 fixed means indent that text at column fortran-comment-line-column
315 relative means indent at fortran-comment-line-column beyond the
316 indentation for a line of code.
317 (default 'fixed)
318 fortran-comment-indent-char
319 Single-character string be inserted instead of space for
320 full-line comment indentation. (default \" \")
321 fortran-minimum-statement-indent
322 Minimum indentation for fortran statements. (default 6)
323 fortran-line-number-indent
324 Maximum indentation for line numbers. A line number will get
325 less than this much indentation if necessary to avoid reaching
326 column 5. (default 1)
327 fortran-check-all-num-for-matching-do
328 Non-nil causes all numbered lines to be treated as possible 'continue'
329 statements. (default nil)
330 fortran-blink-matching-if
331 From a fortran `endif' statement, blink the matching `if' statement.
332 (default nil)
333 fortran-continuation-string
334 Single-character string to be inserted in column 5 of a continuation
335 line. (default \"$\")
336 fortran-comment-region
337 String inserted by \\[fortran-comment-region] at start of each line in
338 region. (default \"c$$$\")
339 fortran-electric-line-number
340 Non-nil causes line number digits to be moved to the correct column
341 as typed. (default t)
342 fortran-startup-message
343 Set to nil to inhibit message first time Fortran mode is used.
344
345Turning on Fortran mode calls the value of the variable fortran-mode-hook
346with no args, if that value is non-nil."
347 (interactive)
348 (kill-all-local-variables)
349 (if fortran-startup-message
350 (message "Emacs Fortran mode version %s. Bugs to %s"
351 fortran-mode-version bug-fortran-mode))
352 (setq fortran-startup-message nil)
353 (setq local-abbrev-table fortran-mode-abbrev-table)
354 (set-syntax-table fortran-mode-syntax-table)
355 (make-local-variable 'indent-line-function)
356 (setq indent-line-function 'fortran-indent-line)
357 (make-local-variable 'comment-indent-hook)
358 (setq comment-indent-hook 'fortran-comment-hook)
359 (make-local-variable 'comment-line-start-skip)
360 (setq comment-line-start-skip
361 "^[Cc*]\\(\\([^ \t\n]\\)\\1*\\)?[ \t]*") ;[^ \t\n]* handles c$$$
362 (make-local-variable 'comment-line-start)
363 (setq comment-line-start "c")
364 (make-local-variable 'comment-start-skip)
365 (setq comment-start-skip "![ \t]*")
366 (make-local-variable 'comment-start)
367 (setq comment-start nil)
368 (make-local-variable 'require-final-newline)
369 (setq require-final-newline t)
370 (make-local-variable 'abbrev-all-caps)
371 (setq abbrev-all-caps t)
372 (make-local-variable 'indent-tabs-mode)
373 (setq indent-tabs-mode nil)
374 (setq abbrev-mode t) ; ?? (abbrev-mode 1) instead??
375 (use-local-map fortran-mode-map)
376 (setq mode-name "Fortran")
377 (setq major-mode 'fortran-mode)
378 (make-local-variable 'fortran-tab-mode)
379 (make-local-variable 'fortran-comment-line-column)
380 (make-local-variable 'fortran-minimum-statement-indent)
381 (make-local-variable 'fortran-column-ruler)
382 (make-local-variable 'fortran-tab-mode-string)
383 (fortran-tab-mode (fortran-analyze-file-format))
384 (run-hooks 'fortran-mode-hook))
385
386(defun fortran-comment-hook ()
387 (save-excursion
388 (skip-chars-backward " \t")
389 (max (+ 1 (current-column))
390 comment-column)))
391
392(defun fortran-indent-comment ()
393 "Align or create comment on current line.
394Existing comments of all types are recognized and aligned.
395If the line has no comment, a side-by-side comment is inserted and aligned
396if the value of comment-start is not nil.
397Otherwise, a separate-line comment is inserted, on this line
398or on a new line inserted before this line if this line is not blank."
399 (interactive)
400 (beginning-of-line)
401 ;; Recognize existing comments of either kind.
402 (cond ((looking-at comment-line-start-skip)
403 (fortran-indent-line))
404 ((re-search-forward comment-start-skip
405 (save-excursion (end-of-line) (point)) t)
406 (indent-for-comment))
407 ;; No existing comment.
408 ;; If side-by-side comments are defined, insert one,
409 ;; unless line is now blank.
410 ((and comment-start (not (looking-at "^[ \t]*$")))
411 (end-of-line)
412 (delete-horizontal-space)
413 (indent-to (fortran-comment-hook))
414 (insert comment-start))
415 ;; Else insert separate-line comment, making a new line if nec.
416 (t
417 (if (looking-at "^[ \t]*$")
418 (delete-horizontal-space)
419 (beginning-of-line)
420 (insert "\n")
421 (forward-char -1))
422 (insert comment-line-start)
423 (insert-char (if (stringp fortran-comment-indent-char)
424 (aref fortran-comment-indent-char 0)
425 fortran-comment-indent-char)
426 (- (calculate-fortran-indent) (current-column))))))
427
428(defun fortran-comment-region (beg-region end-region arg)
429 "Comments every line in the region.
430Puts fortran-comment-region at the beginning of every line in the region.
431BEG-REGION and END-REGION are args which specify the region boundaries.
432With non-nil ARG, uncomments the region."
433 (interactive "*r\nP")
434 (let ((end-region-mark (make-marker)) (save-point (point-marker)))
435 (set-marker end-region-mark end-region)
436 (goto-char beg-region)
437 (beginning-of-line)
438 (if (not arg) ;comment the region
439 (progn (insert fortran-comment-region)
440 (while (and (= (forward-line 1) 0)
441 (< (point) end-region-mark))
442 (insert fortran-comment-region)))
443 (let ((com (regexp-quote fortran-comment-region))) ;uncomment the region
444 (if (looking-at com)
445 (delete-region (point) (match-end 0)))
446 (while (and (= (forward-line 1) 0)
447 (< (point) end-region-mark))
448 (if (looking-at com)
449 (delete-region (point) (match-end 0))))))
450 (goto-char save-point)
451 (set-marker end-region-mark nil)
452 (set-marker save-point nil)))
453
454(defun fortran-abbrev-start ()
455 "Typing \";\\[help-command]\" or \";?\" lists all the fortran abbrevs.
456Any other key combination is executed normally."
457 (interactive)
458 (let (c)
459 (insert last-command-char)
460 (if (or (= (setq c (read-char)) ??) ;insert char if not equal to `?'
461 (= c help-char))
462 (fortran-abbrev-help)
463 (setq unread-command-char c))))
464
465(defun fortran-abbrev-help ()
466 "List the currently defined abbrevs in Fortran mode."
467 (interactive)
468 (message "Listing abbrev table...")
469 (require 'abbrevlist)
470 (list-one-abbrev-table fortran-mode-abbrev-table "*Help*")
471 (message "Listing abbrev table...done"))
472
473(defun fortran-column-ruler ()
474 "Inserts a column ruler momentarily above current line, till next keystroke.
475The ruler is defined by the value of fortran-column-ruler.
476The key typed is executed unless it is SPC."
477 (interactive)
478 (momentary-string-display
479 fortran-column-ruler (save-excursion (beginning-of-line) (point))
480 nil "Type SPC or any command to erase ruler."))
481
482(defun fortran-window-create ()
483 "Makes the window 72 columns wide.
484See also fortran-window-create-momentarily."
485 (interactive)
486 (condition-case error
487 (progn
488 (let ((window-min-width 2))
489 (if (< (window-width) (screen-width))
490 (enlarge-window-horizontally (- (screen-width)
491 (window-width) 1)))
492 (split-window-horizontally 73)
493 (other-window 1)
494 (switch-to-buffer " fortran-window-extra" t)
495 (select-window (previous-window))))
496 (error (message "No room for fortran window.")
497 'error)))
498
499(defun fortran-window-create-momentarily (&optional arg)
500 "Momentarily makes the window 72 columns wide.
501Optional ARG non-nil and non-unity disables the momentary feature.
502See also fortran-window-create."
503 (interactive "p")
504 (if (or (not arg)
505 (= arg 1))
506 (save-window-excursion
507 (if (not (equal (fortran-window-create) 'error))
508 (progn (message "Type SPC to continue editing.")
509 (let ((char (read-char)))
510 (or (equal char (string-to-char " "))
511 (setq unread-command-char char))))))
512 (fortran-window-create)))
513
514(defun fortran-split-line ()
515 "Break line at point and insert continuation marker and alignment."
516 (interactive)
517 (delete-horizontal-space)
518 (if (save-excursion (beginning-of-line) (looking-at comment-line-start-skip))
519 (insert "\n" comment-line-start " ")
520 (if fortran-tab-mode
521 (progn
522 (insert "\n\t")
523 (insert-char (fortran-numerical-continuation-char) 1))
524 (insert "\n" fortran-continuation-string)))
525 (fortran-indent-line))
526
527(defun fortran-numerical-continuation-char ()
528 "Return a digit for tab-digit style of continution lines.
529If, previous line is a tab-digit continuation line, returns that digit
530plus one. Otherwise return 1. Zero not allowed."
531 (save-excursion
532 (forward-line -1)
533 (if (looking-at "\t[1-9]")
534 (+ ?1 (% (- (char-after (+ (point) 1)) ?0) 9))
535 ?1)))
536
537(defun delete-horizontal-regexp (chars)
538 "Delete all characters in CHARS around point.
539CHARS is like the inside of a [...] in a regular expression
540except that ] is never special and \ quotes ^, - or \."
541 (interactive "*s")
542 (skip-chars-backward chars)
543 (delete-region (point) (progn (skip-chars-forward chars) (point))))
544
545(defun fortran-electric-line-number (arg)
546 "Self insert, but if part of a Fortran line number indent it automatically.
547Auto-indent does not happen if a numeric arg is used."
548;The use of arg may be superfluous here since there apears to be no way to
549;prefix a digit key with an argument.
550 (interactive "P")
551 (if (or arg (not fortran-electric-line-number))
552 (if arg
553 (self-insert-command arg)
554 (self-insert-command 1))
555 (if (or (and (= 5 (current-column))
556 (save-excursion
557 (beginning-of-line)
558 (looking-at " ")));In col 5 with only spaces to left.
559 (and (= fortran-minimum-statement-indent (current-column))
560 (save-excursion
561 (beginning-of-line)
562 (looking-at "\t"));In col 8 with a single tab to the left.
563 (not (or (eq last-command 'fortran-indent-line)
564 (eq last-command
565 'fortran-reindent-then-newline-and-indent))))
566 (save-excursion
567 (re-search-backward "[^ \t0-9]"
568 (save-excursion
569 (beginning-of-line)
570 (point))
571 t)) ;not a line number
572 (looking-at "[0-9]") ;within a line number
573 )
574 (insert last-command-char)
575 (skip-chars-backward " \t")
576 (insert last-command-char)
577 (fortran-indent-line))))
578
579(defun beginning-of-fortran-subprogram ()
580 "Moves point to the beginning of the current fortran subprogram."
581 (interactive)
582 (let ((case-fold-search t))
583 (beginning-of-line -1)
584 (re-search-backward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
585 (if (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")
586 (forward-line 1))))
587
588(defun end-of-fortran-subprogram ()
589 "Moves point to the end of the current fortran subprogram."
590 (interactive)
591 (let ((case-fold-search t))
592 (beginning-of-line 2)
593 (re-search-forward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move)
594 (goto-char (match-beginning 0))
595 (forward-line 1)))
596
597(defun mark-fortran-subprogram ()
598 "Put mark at end of fortran subprogram, point at beginning.
599The marks are pushed."
600 (interactive)
601 (end-of-fortran-subprogram)
602 (push-mark (point))
603 (beginning-of-fortran-subprogram))
604
605(defun fortran-previous-statement ()
606 "Moves point to beginning of the previous fortran statement.
607Returns 'first-statement if that statement is the first
608non-comment Fortran statement in the file, and nil otherwise."
609 (interactive)
610 (let (not-first-statement continue-test)
611 (beginning-of-line)
612 (setq continue-test
613 (or (looking-at
614 (concat "[ \t]*" (regexp-quote fortran-continuation-string)))
615 (or (looking-at " [^ 0\n]")
616 (looking-at "\t[1-9]"))))
617 (while (and (setq not-first-statement (= (forward-line -1) 0))
618 (or (looking-at comment-line-start-skip)
619 (looking-at "[ \t]*$")
620 (looking-at " [^ 0\n]")
621 (looking-at "\t[1-9]")
622 (looking-at (concat "[ \t]*" comment-start-skip)))))
623 (cond ((and continue-test
624 (not not-first-statement))
625 (message "Incomplete continuation statement."))
626 (continue-test
627 (fortran-previous-statement))
628 ((not not-first-statement)
629 'first-statement))))
630
631(defun fortran-next-statement ()
632 "Moves point to beginning of the next fortran statement.
633Returns `last-statement' if that statement is the last
634non-comment Fortran statement in the file, and nil otherwise."
635 (interactive)
636 (let (not-last-statement)
637 (beginning-of-line)
638 (while (and (setq not-last-statement (= (forward-line 1) 0))
639 (or (looking-at comment-line-start-skip)
640 (looking-at "[ \t]*$")
641 (looking-at " [^ 0\n]")
642 (looking-at "\t[1-9]")
643 (looking-at (concat "[ \t]*" comment-start-skip)))))
644 (if (not not-last-statement)
645 'last-statement)))
646
647(defun fortran-blink-matching-if ()
648 "From a fortran `endif' statement, blink the matching `if' statement."
649 (let ((count 1) (top-of-window (window-start)) matching-if
650 (endif-point (point)) message)
651 (if (save-excursion (beginning-of-line)
652 (skip-chars-forward " \t0-9")
653 (looking-at "end[ \t]*if\\b"))
654 (progn
655 (save-excursion
656 (while (and (not (= count 0))
657 (not (eq (fortran-previous-statement)
658 'first-statement))
659 (not (looking-at
660 "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]")))
661 ; Keep local to subprogram
662 (skip-chars-forward " \t0-9")
663 (cond ((looking-at "if[ \t]*(")
664 (save-excursion (if (or (looking-at ".*)[
665\t]*then\\b[ \t]*[^ \t(=a-z0-9]")
666 (let (then-test);multi-line if-then
667 (while (and (= (forward-line 1) 0)
668 ;search forward for then
669 (or
670(looking-at " [^ 0\n]")
671
672(looking-at "\t[1-9]"))
673 (not (setq
674then-test (looking-at
675
676 ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
677 then-test))
678 (setq count (- count 1)))))
679 ((looking-at "end[ \t]*if\\b")
680 (setq count (+ count 1)))))
681 (if (not (= count 0))
682 (setq message "No matching if.")
683 (if (< (point) top-of-window)
684 (setq message (concat "Matches " (buffer-substring
685 (progn (beginning-of-line)
686 (point))
687 (progn (end-of-line)
688 (point)))))
689 (setq matching-if (point)))))
690 (if message
691 (message message)
692 (goto-char matching-if)
693 (sit-for 1)
694 (goto-char endif-point))))))
695
696(defun fortran-indent-line ()
697 "Indents current fortran line based on its contents and on previous lines."
698 (interactive)
699 (let ((cfi (calculate-fortran-indent)))
700 (save-excursion
701 (beginning-of-line)
702 (if (or (not (= cfi (fortran-current-line-indentation)))
703 (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t)
704 (not (fortran-line-number-indented-correctly-p))))
705 (fortran-indent-to-column cfi)
706 (beginning-of-line)
707 (if (and (not (looking-at comment-line-start-skip))
708 (re-search-forward comment-start-skip
709 (save-excursion (end-of-line) (point)) 'move))
710 (fortran-indent-comment))))
711 ;; Never leave point in left margin.
712 (if (< (current-column) cfi)
713 (move-to-column cfi))
714 (if fortran-blink-matching-if
715 (fortran-blink-matching-if))))
716
717(defun fortran-reindent-then-newline-and-indent ()
718 "Reindent the current fortran line, insert a newline and indent the newline.
719An abbrev before point is expanded if abbrev-mode is non-nil."
720 (interactive)
721 (if abbrev-mode (expand-abbrev))
722 (save-excursion
723 (beginning-of-line)
724 (skip-chars-forward " \t")
725 (if (or (looking-at "[0-9]") ;Reindent only where it is most
726 (looking-at "end") ;likely to be necessary
727 (looking-at "else")
728 (looking-at (regexp-quote fortran-continuation-string)))
729 (fortran-indent-line)))
730 (insert "\n")
731 (fortran-indent-line))
732
733(defun fortran-indent-subprogram ()
734 "Properly indents the Fortran subprogram which contains point."
735 (interactive)
736 (save-excursion
737 (mark-fortran-subprogram)
738 (message "Indenting subprogram...")
739 (indent-region (point) (mark) nil))
740 (message "Indenting subprogram...done."))
741
742(defun calculate-fortran-indent ()
743 "Calculates the fortran indent column based on previous lines."
744 (let (icol first-statement (case-fold-search t)
745 (fortran-minimum-statement-indent
746 fortran-minimum-statement-indent))
747 (save-excursion
748 (setq first-statement (fortran-previous-statement))
749 (if first-statement
750 (setq icol fortran-minimum-statement-indent)
751 (progn
752 (if (= (point) (point-min))
753 (setq icol fortran-minimum-statement-indent)
754 (setq icol (fortran-current-line-indentation)))
755 (skip-chars-forward " \t0-9")
756 (cond ((looking-at "if[ \t]*(")
757 (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]")
758 (let (then-test) ;multi-line if-then
759 (while (and (= (forward-line 1) 0)
760 ;search forward for then
761 (or (looking-at " [^ 0\n]")
762 (looking-at "\t[1-9]"))
763 (not (setq then-test (looking-at
764 ".*then\\b[ \t]*[^ \t(=a-z0-9]")))))
765 then-test))
766 (setq icol (+ icol fortran-if-indent))))
767 ((looking-at "\\(else\\|elseif\\)\\b")
768 (setq icol (+ icol fortran-if-indent)))
769 ((looking-at "do\\b")
770 (setq icol (+ icol fortran-do-indent)))
771 ((looking-at "end\\b[ \t]*[^ \t=(a-z]")
772 ; Previous END resets indent to minimum
773 (setq icol fortran-minimum-statement-indent))))))
774 (save-excursion
775 (beginning-of-line)
776 (cond ((looking-at "[ \t]*$"))
777 ((looking-at comment-line-start-skip)
778 (setq fortran-minimum-statement-indent 0)
779 (cond ((eq fortran-comment-indent-style 'relative)
780 (setq icol (+ icol fortran-comment-line-column)))
781 ((eq fortran-comment-indent-style 'fixed)
782 (setq icol fortran-comment-line-column))))
783 ((or (looking-at (concat "[ \t]*"
784 (regexp-quote fortran-continuation-string)))
785 (looking-at " [^ 0\n]")
786 (looking-at "\t[1-9]"))
787 (setq icol (+ icol fortran-continuation-indent)))
788 (first-statement)
789 ((and fortran-check-all-num-for-matching-do
790 (looking-at "[ \t]*[0-9]+")
791 (fortran-check-for-matching-do))
792 (setq icol (- icol fortran-do-indent)))
793 (t
794 (skip-chars-forward " \t0-9")
795 (cond ((looking-at "end[ \t]*if\\b")
796 (setq icol (- icol fortran-if-indent)))
797 ((looking-at "\\(else\\|elseif\\)\\b")
798 (setq icol (- icol fortran-if-indent)))
799 ((and (looking-at "continue\\b")
800 (fortran-check-for-matching-do))
801 (setq icol (- icol fortran-do-indent)))
802 ((looking-at "end[ \t]*do\\b")
803 (setq icol (- icol fortran-do-indent)))
804 ((and (looking-at "end\\b[ \t]*[^ \t=(a-z]")
805 (not (= icol fortran-minimum-statement-indent)))
806 (message "Warning: `end' not in column %d. Probably\
807 an unclosed block." fortran-minimum-statement-indent))))))
808 (max fortran-minimum-statement-indent icol)))
809
810(defun fortran-current-line-indentation ()
811 "Indentation of current line, ignoring Fortran line number or continuation.
812This is the column position of the first non-whitespace character
813aside from the line number and/or column 5/8 line-continuation character.
814For comment lines, returns indentation of the first
815non-indentation text within the comment."
816 (save-excursion
817 (beginning-of-line)
818 (cond ((looking-at comment-line-start-skip)
819 (goto-char (match-end 0))
820 (skip-chars-forward
821 (if (stringp fortran-comment-indent-char)
822 fortran-comment-indent-char
823 (char-to-string fortran-comment-indent-char))))
824 ((or (looking-at " [^ 0\n]")
825 (looking-at "\t[1-9]"))
826 (goto-char (match-end 0)))
827 (t
828 ;; Move past line number.
829 (re-search-forward "^[ \t0-9]*" (+ (point) 4) t)))
830 ;; Move past whitespace.
831 (skip-chars-forward " \t")
832 (current-column)))
833
834(defun fortran-indent-to-column (col)
835 "Indents current line with spaces to column COL.
836notes: 1) A non-zero/non-blank character in column 5 indicates a continuation
837 line, and this continuation character is retained on indentation;
838 2) If fortran-continuation-string is the first non-whitespace character,
839 this is a continuation line;
840 3) A non-continuation line which has a number as the first
841 non-whitespace character is a numbered line.
842 4) A tab followed by a digit indicates a continuation line."
843 (save-excursion
844 (beginning-of-line)
845 (if (looking-at comment-line-start-skip)
846 (if fortran-comment-indent-style
847 (let ((char (if (stringp fortran-comment-indent-char)
848 (aref fortran-comment-indent-char 0)
849 fortran-comment-indent-char)))
850 (goto-char (match-end 0))
851 (delete-horizontal-regexp (concat " \t" (char-to-string char)))
852 (insert-char char (- col (current-column)))))
853 (if (looking-at "\t[1-9]")
854 (if fortran-tab-mode
855 (goto-char (match-end 0))
856 (delete-char 2)
857 (insert " ")
858 (insert fortran-continuation-string))
859 (if (looking-at " [^ 0\n]")
860 (if fortran-tab-mode
861 (progn (delete-char 6)
862 (insert "\t")
863 (insert-char (fortran-numerical-continuation-char) 1))
864 (forward-char 6))
865 (delete-horizontal-space)
866 ;; Put line number in columns 0-4
867 ;; or put continuation character in column 5.
868 (cond ((eobp))
869 ((looking-at (regexp-quote fortran-continuation-string))
870 (if fortran-tab-mode
871 (progn
872 (indent-to fortran-minimum-statement-indent)
873 (delete-char 1)
874 (insert-char (fortran-numerical-continuation-char) 1))
875 (indent-to 5))
876 (forward-char 1))
877 ((looking-at "[0-9]+")
878 (let ((extra-space (- 5 (- (match-end 0) (point)))))
879 (if (< extra-space 0)
880 (message "Warning: line number exceeds 5-digit limit.")
881 (indent-to (min fortran-line-number-indent extra-space))))
882 (skip-chars-forward "0-9")))))
883 ;; Point is now after any continuation character or line number.
884 ;; Put body of statement where specified.
885 (delete-horizontal-space)
886 (indent-to col)
887 ;; Indent any comment following code on the same line.
888 (if (and comment-start-skip
889 (re-search-forward comment-start-skip
890 (save-excursion (end-of-line) (point)) t))
891 (progn (goto-char (match-beginning 0))
892 (if (not (= (current-column) (fortran-comment-hook)))
893 (progn (delete-horizontal-space)
894 (indent-to (fortran-comment-hook)))))))))
895
896(defun fortran-line-number-indented-correctly-p ()
897 "Return t if current line's line number is correctly indented.
898Do not call if there is no line number."
899 (save-excursion
900 (beginning-of-line)
901 (skip-chars-forward " \t")
902 (and (<= (current-column) fortran-line-number-indent)
903 (or (= (current-column) fortran-line-number-indent)
904 (progn (skip-chars-forward "0-9")
905 (= (current-column) 5))))))
906
907(defun fortran-check-for-matching-do ()
908 "When called from a numbered statement, returns t if matching 'do' is found.
909Otherwise return a nil."
910 (let (charnum
911 (case-fold-search t))
912 (save-excursion
913 (beginning-of-line)
914 (if (looking-at "[ \t]*[0-9]+")
915 (progn
916 (skip-chars-forward " \t")
917 (skip-chars-forward "0") ;skip past leading zeros
918 (setq charnum (buffer-substring (point)
919 (progn (skip-chars-forward "0-9")
920 (point))))
921 (beginning-of-line)
922 (and (re-search-backward
923 (concat
924 "\\(^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]\\)\\|\\(^[ \t0-9]*do[ \t]*0*"
925 charnum "\\b\\)\\|\\(^[ \t]*0*" charnum "\\b\\)")
926 nil t)
927 (looking-at (concat "^[ \t0-9]*do[ \t]*0*" charnum))))))))
928
929(defun fortran-analyze-file-format ()
930 "Return 0 if Fixed format is used, 1 if Tab formatting is used.
931Use fortran-tab-mode-default if no non-comment statements are found in the
932file before the end or the first fortran-analyze-depth lines."
933 (save-excursion
934 (goto-char (point-min))
935 (setq i 0)
936 (while (not (or
937 (eobp)
938 (looking-at "\t")
939 (looking-at " ")
940 (> i fortran-analyze-depth)))
941 (forward-line)
942 (setq i (1+ i)))
943 (cond
944 ((looking-at "\t") 1)
945 ((looking-at " ") 0)
946 (fortran-tab-mode-default 1)
947 (t 0))))
948
949(defun fortran-tab-mode (arg)
950 "Toggle fortran-tab-mode which indicates style of continuation lines.
951With no argument, toggle on/off the tabbing mode of continuation lines.
952If argument is a positive number, or non-nil if not a number, fortran-tab-mode
953is turned on. Otherwise
954If `fortran-tab-mode' is false"
955 (interactive "P")
956 (setq fortran-tab-mode
957 (if (null arg) (not fortran-tab-mode)
958 (if (numberp arg)
959 (> (prefix-numeric-value arg) 0)
960 (arg))))
961 (if fortran-tab-mode
962 (fortran-setup-tab-format-style)
963 (fortran-setup-fixed-format-style))
964 (set-buffer-modified-p (buffer-modified-p))) ;No-op, but updates mode line.
965
966(defun fortran-setup-tab-format-style ()
967 "Set up fortran mode to use the TAB-digit mode of continuation lines.
968Use the command fortran-tab-mode to toggle between this and fixed format style."
969 (setq fortran-comment-line-column (max tab-width 6))
970 (setq fortran-minimum-statement-indent (max tab-width 6))
971 (setq indent-tabs-mode t)
972 (setq fortran-column-ruler
973 (concat
974 "0 810 20 30 40 50 60 70\n"
975 "[ ]| { | | | | | | | | | | | | |}\n"))
976 (setq fortran-tab-mode-string " TAB-format")
977 (set-buffer-modified-p (buffer-modified-p)))
978
979(defun fortran-setup-fixed-format-style ()
980 "Set up fortran mode to use the column 6 mode of continuation lines.
981Use the command fortran-tab-mode to toggle between this and tab
982character format style."
983 (setq fortran-comment-line-column 6)
984 (setq fortran-minimum-statement-indent 6)
985 (setq indent-tabs-mode nil)
986 (setq fortran-column-ruler
987 (concat
988 "0 4 6 10 20 30 40 50 60 70\n"
989 "[ ]|{ | | | | | | | | | | | | |}\n"))
990 (setq fortran-tab-mode-string " Fixed-format")
991 (set-buffer-modified-p (buffer-modified-p)))
992
993(or (assq 'fortran-tab-mode minor-mode-alist)
994 (setq minor-mode-alist (cons
995 '(fortran-tab-mode-string fortran-tab-mode-string)
996 minor-mode-alist)))
997