comparison lisp/modes/f90.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; f90.el --- Fortran-90 mode (free format)
2 ;; Copyright (C) 1995 Free Software Foundation, Inc.
3
4 ;; Author: Torbj\"orn Einarsson <T.Einarsson@clab.ericsson.se>
5 ;; Created: Apr. 18, 1996
6 ;; Keywords: fortran, f90, languages
7
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2 of the License, or
11 ;; (at your option) any later version.
12
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program; if not, write to the Free Software
20 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 ;;; Synched up with: FSF 19.30.
23
24 ;;; Commentary:
25 ;; Smart mode for editing F90 programs in FREE FORMAT.
26 ;; Knows about continuation lines, named structured statements, and other
27 ;; new features in F90 including HPF (High Performance Fortran) structures.
28 ;; The basic feature is to provide an accurate indentation of F90 programs.
29 ;; In addition, there are many more features like automatic matching of all
30 ;; end statements, an auto-fill function to break long lines, a join-lines
31 ;; function which joins continued lines etc etc.
32 ;; To facilitate typing, a fairly complete list of abbreviations is provided.
33 ;; For example, `i is short-hand for integer (if abbrev-mode is on).
34
35 ;; There are two separate features for highlighting the code.
36 ;; 1) Upcasing or capitalizing of all keywords.
37 ;; 2) Colors/fonts using font-lock-mode. (only when using X-windows)
38 ;; Automatic upcase of downcase of keywords is controlled by the parameter
39 ;; f90-auto-keyword-case.
40
41 ;; The indentations of lines starting with ! is determined by the first of the
42 ;; following matches (the values in the left column are the default values):
43
44 ;; start-string/regexp indent variable holding start-string/regexp
45 ;; !!! 0
46 ;; !hpf\\$ (re) 0 f90-directive-comment-re
47 ;; !!$ 0 f90-comment-region
48 ;; ! (re) as code f90-indented-comment-re
49 ;; default comment-column
50
51 ;; Ex: Here is the result of 3 different settings of f90-indented-comment-re
52 ;; f90-indented-comment-re !-indentation !!-indentation
53 ;; ! as code as code
54 ;; !! comment-column as code
55 ;; ![^!] as code comment-column
56 ;; Trailing comments are indented to comment-column with indent-for-comment M-;
57 ;; f90-comment-region (C-c;) toggles insertion of f90-comment-region in region.
58
59 ;; One common convention for free vs. fixed format is that free-format files
60 ;; have the ending .f90 while the fixed format files have the ending .f.
61 ;; To make f90-mode work, put this file in, for example, your directory
62 ;; ~/lisp, and be sure that you have the following in your .emacs-file
63 ;; (setq load-path (append load-path '("~/lisp")))
64 ;; (autoload 'f90-mode "f90"
65 ;; "Major mode for editing Fortran 90 code in free format." t)
66 ;; (setq auto-mode-alist (append auto-mode-alist
67 ;; (list '("\\.f90$" . f90-mode))))
68 ;; Once you have entered f90-mode, you may get more info by using
69 ;; the command describe-mode (C-h m). For online help describing various
70 ;; functions use C-h f <Name of function you want described>
71
72 ;; To customize the f90-mode for your taste, use, for example:
73 ;; (you don't have to specify values for all the parameters below)
74 ;;(setq f90-mode-hook
75 ;; '(lambda () (setq f90-do-indent 3
76 ;; f90-if-indent 3
77 ;; f90-type-indent 3
78 ;; f90-program-indent 2
79 ;; f90-continuation-indent 5
80 ;; f90-comment-region "!!$"
81 ;; f90-directive-comment-re "!hpf\\$"
82 ;; f90-indented-comment-re "!"
83 ;; f90-break-delimiters "[-+\\*/,><=% \t]"
84 ;; f90-break-before-delimiters t
85 ;; f90-beginning-ampersand t
86 ;; f90-smart-end 'blink
87 ;; f90-auto-keyword-case nil
88 ;; f90-leave-line-no nil
89 ;; f90-startup-message t
90 ;; indent-tabs-mode nil
91 ;; )
92 ;; ;;The rest is not default.
93 ;; (abbrev-mode 1) ; turn on abbreviation mode
94 ;; (f90-auto-fill-mode 1) ; turn on auto-filling
95 ;; (turn-on-font-lock) ; for highlighting
96 ;; (if f90-auto-keyword-case ; change case of all keywords on startup
97 ;; (f90-change-keywords f90-auto-keyword-case))
98 ;; ))
99 ;; in your .emacs file (the shown values are the defaults). You can also
100 ;; change the values of the lists f90-keywords etc.
101 ;; The auto-fill and abbreviation minor modes are accessible from the menu,
102 ;; or by using M-x f90-auto-fill-mode and M-x abbrev-mode, respectively.
103
104 ;; Remarks
105 ;; 1) Line numbers are by default left-justified. If f90-leave-line-no is
106 ;; non-nil, the line numbers are never touched.
107 ;; 2) Multi-; statements like > do i=1,20 ; j=j+i ; end do < are not handled
108 ;; correctly, but I imagine them to be rare.
109 ;; 3) Regexps for hilit19 are no longer supported.
110 ;; 4) For FIXED FORMAT code, use the ordinary fortran mode.
111 ;; 5) This mode does not work under emacs-18.x.
112 ;; 6) Preprocessor directives, i.e., lines starting with # are left-justified
113 ;; and are untouched by all case-changing commands. There is, at present, no
114 ;; mechanism for treating multi-line directives (continued by \ ).
115 ;; 7) f77 do-loops do 10 i=.. ; ; 10 continue are not correctly indented.
116 ;; You are urged to use f90-do loops (with labels if you wish).
117
118 ;; List of user commands
119 ;; f90-previous-statement f90-next-statement
120 ;; f90-beginning-of-subprogram f90-end-of-subprogram f90-mark-subprogram
121 ;; f90-comment-region
122 ;; f90-indent-line f90-indent-new-line
123 ;; f90-indent-region (can be called by calling indent-region)
124 ;; f90-indent-subprogram
125 ;; f90-break-line f90-join-lines
126 ;; f90-auto-fill-mode
127 ;; f90-fill-region
128 ;; f90-insert-end
129 ;; f90-upcase-keywords f90-upcase-region-keywords
130 ;; f90-downcase-keywords f90-downcase-region-keywords
131 ;; f90-capitalize-keywords f90-capitalize-region-keywords
132
133 ;; Thanks to all the people who have tested the mode. Special thanks to Jens
134 ;; Bloch Helmers for encouraging me to write this code, for creative
135 ;; suggestions as well as for the lists of hpf-commands.
136 ;; Also thanks to the authors of the fortran and pascal modes, on which some
137 ;; of this code is built.
138
139
140 ;;; Code:
141 (defconst bug-f90-mode "T.Einarsson@clab.ericsson.se"
142 "Address of mailing list for F90 mode bugs.")
143
144 ;; User options
145 (defvar f90-do-indent 3
146 "*Extra indentation applied to DO blocks.")
147
148 (defvar f90-if-indent 3
149 "*Extra indentation applied to IF, SELECT CASE, WHERE and FORALL blocks.")
150
151 (defvar f90-type-indent 3
152 "*Extra indentation applied to TYPE, INTERFACE and BLOCK DATA blocks.")
153
154 (defvar f90-program-indent 2
155 "*Extra indentation applied to PROGRAM/MODULE/SUBROUTINE/FUNCTION blocks.")
156
157 (defvar f90-continuation-indent 5
158 "*Extra indentation applied to F90 continuation lines.")
159
160 (defvar f90-comment-region "!!$"
161 "*String inserted by \\[f90-comment-region]\
162 at start of each line in region.")
163
164 (defvar f90-indented-comment-re "!"
165 "*Regexp saying which comments to be indented like code.")
166
167 (defvar f90-directive-comment-re "!hpf\\$"
168 "*Regexp of comment-like directive like \"!HPF\\\\$\", not to be indented.")
169
170 (defvar f90-beginning-ampersand t
171 "*t makes automatic insertion of \& at beginning of continuation line.")
172
173 (defvar f90-smart-end 'blink
174 "*From an END statement, check and fill the end using matching block start.
175 Allowed values are 'blink, 'no-blink, and nil, which determine
176 whether to blink the matching beginning.")
177
178 (defvar f90-break-delimiters "[-+\\*/><=,% \t]"
179 "*Regexp holding list of delimiters at which lines may be broken.")
180
181 (defvar f90-break-before-delimiters t
182 "*Non-nil causes `f90-do-auto-fill' to break lines before delimiters.")
183
184 (defvar f90-auto-keyword-case nil
185 "*Automatic case conversion of keywords.
186 The options are 'downcase-word, 'upcase-word, 'capitalize-word and nil")
187
188 (defvar f90-leave-line-no nil
189 "*If nil, left-justify linenumbers.")
190
191 (defvar f90-startup-message t
192 "*Non-nil displays a startup message when F90 mode is first called.")
193
194 (defconst f90-keywords-re
195 ;;("allocate" "allocatable" "assign" "assignment" "backspace" "block"
196 ;;"call" "case" "character" "close" "common" "complex" "contains"
197 ;;"continue" "cycle" "data" "deallocate" "dimension" "do" "double" "else"
198 ;;"elseif" "elsewhere" "end" "enddo" "endfile" "endif" "entry" "equivalence"
199 ;;"exit" "external" "forall" "format" "function" "goto" "if" "implicit"
200 ;;"include" "inquire" "integer" "intent" "interface" "intrinsic" "logical"
201 ;;"module" "namelist" "none" "nullify" "only" "open" "operator" "optional" "parameter"
202 ;;"pause" "pointer" "precision" "print" "private" "procedure" "program"
203 ;;"public" "read" "real" "recursive" "result" "return" "rewind" "save" "select"
204 ;;"sequence" "stop" "subroutine" "target" "then" "type" "use" "where"
205 ;;"while" "write")
206 (concat
207 "\\<\\(a\\(llocat\\(able\\|e\\)\\|ssign\\(\\|ment\\)\\)\\|b\\(ackspace\\|"
208 "lock\\)\\|c\\(a\\(ll\\|se\\)\\|haracter\\|lose\\|o\\(m\\(mon\\|plex\\)\\|"
209 "nt\\(ains\\|inue\\)\\)\\|ycle\\)\\|d\\(ata\\|eallocate\\|imension\\|"
210 "o\\(\\|uble\\)\\)\\|e\\(lse\\(\\|if\\|where\\)\\|n\\(d\\(\\|do\\|file\\|"
211 "if\\)\\|try\\)\\|quivalence\\|x\\(it\\|ternal\\)\\)\\|f\\(or\\(all\\|"
212 "mat\\)\\|unction\\)\\|goto\\|i\\(f\\|mplicit\\|n\\(clude\\|quire\\|t\\("
213 "e\\(ger\\|nt\\|rface\\)\\|rinsic\\)\\)\\)\\|logical\\|module\\|n\\("
214 "amelist\\|one\\|ullify\\)\\|o\\(nly\\|p\\(en\\|erator\\|tional\\)\\)\\|p\\(a\\("
215 "rameter\\|use\\)\\|ointer\\|r\\(ecision\\|i\\(nt\\|vate\\)\\|o\\("
216 "cedure\\|gram\\)\\)\\|ublic\\)\\|re\\(a[dl]\\|cursive\\|sult\\|turn\\|wind\\)\\|"
217 "s\\(ave\\|e\\(lect\\|quence\\)\\|top\\|ubroutine\\)\\|t\\(arget\\|hen\\|"
218 "ype\\)\\|use\\|w\\(h\\(ere\\|ile\\)\\|rite\\)\\)\\>")
219 "Regexp for F90 keywords.")
220
221 (defconst f90-keywords-level-3-re
222 ;; ("allocate" "allocatable" "assign" "assignment" "backspace" "close"
223 ;; "deallocate" "dimension" "endfile" "entry" "equivalence" "external"
224 ;; "inquire" "intent" "intrinsic" "nullify" "only" "open" "operator"
225 ;; "optional" "parameter" "pause" "pointer" "print" "private" "public"
226 ;; "read" "recursive" "result" "rewind" "save" "select" "sequence"
227 ;; "target" "write")
228 (concat
229 "\\<\\(a\\(llocat\\(able\\|e\\)\\|ssign\\(\\|ment\\)\\)\\|backspace\\|"
230 "close\\|d\\(eallocate\\|imension\\)\\|e\\(n\\(dfile\\|try\\)\\|"
231 "quivalence\\|xternal\\)\\|"
232 "in\\(quire\\|t\\(ent\\|rinsic\\)\\)\\|nullify\\|"
233 "o\\(nly\\|p\\(en\\|erator\\|tional\\)\\)\\|"
234 "p\\(a\\(rameter\\|use\\)\\|ointer\\|ri\\(nt\\|vate\\)\\|ublic\\)\\|re\\("
235 "ad\\|cursive\\|sult\\|wind\\)\\|s\\(ave\\|e\\(lect\\|quence\\)\\)\\|target\\|"
236 "write\\)\\>")
237 "Keyword-regexp for font-lock level >= 3.")
238
239
240 (defconst f90-procedures-re
241 ;; ("abs" "achar" "acos" "adjustl" "adjustr" "aimag" "aint" "all" "allocated"
242 ;; "anint" "any" "asin" "associated" "atan" "atan2" "bit_size" "btest"
243 ;; "ceiling" "char" "cmplx" "conjg" "cos" "cosh" "count" "cshift"
244 ;; "date_and_time" "dble" "digits" "dim" "dot_product" "dprod" "eoshift"
245 ;; "epsilon" "exp" "exponent" "floor" "fraction" "huge" "iachar" "iand"
246 ;; "ibclr" "ibits" "ibset" "ichar" "ieor" "index" "int" "ior" "ishft"
247 ;; "ishftc" "kind" "lbound" "len" "len_trim" "lge" "lgt" "lle" "llt" "log"
248 ;; "logical" "log10" "matmul" "max" "maxexponent" "maxloc" "maxval" "merge"
249 ;; "min" "minexponent" "minloc" "minval" "mod" "modulo" "mvbits" "nearest"
250 ;; "nint" "not" "pack" "precision" "present" "product" "radix"
251 ;; "random_number" "random_seed" "range" "real" "repeat" "reshape"
252 ;; "rrspacing" "scale" "scan" "selected_int_kind" "selected_real_kind"
253 ;; "set_exponent" "shape" "sign" "sin" "sinh" "size" "spacing" "spread"
254 ;; "sqrt" "sum" "system_clock" "tan" "tanh" "tiny" "transfer" "transpose"
255 ;; "trim" "ubound" "unpack" "verify")
256 ;; A left paranthesis to avoid highlighting non-procedures.
257 ;; Real is taken out here to avoid highlighting declarations.
258 (concat
259 "\\<\\(a\\(bs\\|c\\(har\\|os\\)\\|djust[lr]\\|i\\(mag\\|nt\\)\\|ll\\(\\|"
260 "ocated\\)\\|n\\(int\\|y\\)\\|s\\(in\\|sociated\\)\\|tan2?\\)\\|b\\("
261 "it_size\\|test\\)\\|c\\(eiling\\|har\\|mplx\\|o\\(njg\\|sh?\\|unt\\)\\|"
262 "shift\\)\\|d\\(ate_and_time\\|ble\\|i\\(gits\\|m\\)\\|ot_product\\|prod"
263 "\\)\\|e\\(oshift\\|psilon\\|xp\\(\\|onent\\)\\)\\|f\\(loor\\|"
264 "raction\\)\\|huge\\|i\\(a\\(char\\|nd\\)\\|b\\(clr\\|its\\|set\\)\\|"
265 "char\\|eor\\|n\\(dex\\|t\\)\\|or\\|shftc?\\)\\|kind\\|l\\(bound\\|"
266 "en\\(\\|_trim\\)\\|g[et]\\|l[et]\\|og\\(\\|10\\|ical\\)\\)\\|m\\(a\\("
267 "tmul\\|x\\(\\|exponent\\|loc\\|val\\)\\)\\|erge\\|in\\(\\|exponent\\|"
268 "loc\\|val\\)\\|od\\(\\|ulo\\)\\|vbits\\)\\|n\\(earest\\|int\\|ot\\)\\|"
269 "p\\(ack\\|r\\(e\\(cision\\|sent\\)\\|oduct\\)\\)\\|r\\(a\\(dix\\|n\\("
270 "dom_\\(number\\|seed\\)\\|ge\\)\\)\\|e\\(peat\\|shape\\)\\|rspacing\\)\\|"
271 "s\\(ca\\(le\\|n\\)\\|e\\(lected_\\(int_kind\\|real_kind\\)\\|"
272 "t_exponent\\)\\|hape\\|i\\(gn\\|nh?\\|ze\\)\\|p\\(acing\\|read\\)\\|"
273 "qrt\\|um\\|ystem_clock\\)\\|t\\(anh?\\|iny\\|r\\(ans\\(fer\\|pose\\)\\|"
274 "im\\)\\)\\|u\\(bound\\|npack\\)\\|verify\\)[ \t]*(")
275 "Regexp whose first part matches F90 intrinsic procedures.")
276
277 (defconst f90-operators-re
278 ;; "and" "or" "not" "eqv" "neqv" "eq" "ne" "lt" "le" "gt" "ge" "true" "false"
279 (concat
280 "\\.\\(and\\|eqv?\\|false\\|g[et]\\|l[et]\\|n\\(e\\(\\|qv\\)\\|"
281 "ot\\)\\|or\\|true\\)\\.")
282 "Regexp matching intrinsic operators.")
283
284 (defconst f90-hpf-keywords-re
285 ;; Intrinsic procedures
286 ;; ("all_prefix" "all_scatter" "all_suffix" "any_prefix" "any_scatter"
287 ;; "any_suffix" "copy_prefix" "copy_scatter" "copy_suffix" "count_prefix"
288 ;; "count_scatter" "count_suffix" "grade_down" "grade_up" "hpf_alignment"
289 ;; "hpf_template" "hpf_distribution" "iall" "iall_prefix" "iall_scatter"
290 ;; "iall_suffix" "iany" "iany_prefix" "iany_scatter" "iany_suffix" "iparity"
291 ;; "iparity_prefix" "iparity_scatter" "iparity_suffix" "leadz"
292 ;; "maxval_prefix" "maxval_scatter" "maxval_suffix" "minval_prefix"
293 ;; "minval_scatter" "minval_suffix" "parity" "parity_prefix"
294 ;; "parity_scatter" "parity_suffix" "popcnt" "poppar" "product_prefix"
295 ;; "product_scatter" "product_suffix" "sum_prefix" "sum_scatter"
296 ;; "sum_suffix" "ilen" "number_of_processors" "processors_shape")
297 ;; Directives
298 ;; ("align" "distribute" "dynamic" "inherit" "template" "processors"
299 ;; "realign" "redistribute" "independent")
300 ;; Keywords
301 ;; ("pure" "extrinsic" "new" "with" "onto" "block" "cyclic")
302 (concat
303 "\\<\\(a\\(l\\(ign\\|l_\\(prefix\\|s\\(catter\\|uffix\\)\\)\\)\\|ny_\\("
304 "prefix\\|s\\(catter\\|uffix\\)\\)\\)\\|block\\|c\\(o\\(py_\\(prefix\\|"
305 "s\\(catter\\|uffix\\)\\)\\|unt_\\(prefix\\|s\\(catter\\|uffix\\)\\)\\)\\|"
306 "yclic\\)\\|d\\(istribute\\|ynamic\\)\\|extrinsic\\|grade_\\(down\\|"
307 "up\\)\\|hpf_\\(alignment\\|distribution\\|template\\)\\|i\\(a\\(ll\\(\\|"
308 "_\\(prefix\\|s\\(catter\\|uffix\\)\\)\\)\\|ny\\(\\|_\\(prefix\\|s\\("
309 "catter\\|uffix\\)\\)\\)\\)\\|len\\|n\\(dependent\\|herit\\)\\|parity\\(\\|"
310 "_\\(prefix\\|s\\(catter\\|uffix\\)\\)\\)\\)\\|leadz\\|m\\(axval_\\("
311 "prefix\\|s\\(catter\\|uffix\\)\\)\\|inval_\\(prefix\\|s\\(catter\\|"
312 "uffix\\)\\)\\)\\|n\\(ew\\|umber_of_processors\\)\\|onto\\|p\\(arity\\(\\|"
313 "_\\(prefix\\|s\\(catter\\|uffix\\)\\)\\)\\|op\\(cnt\\|par\\)\\|ro\\("
314 "cessors\\(\\|_shape\\)\\|duct_\\(prefix\\|s\\(catter\\|uffix\\)\\)\\)\\|"
315 "ure\\)\\|re\\(align\\|distribute\\)\\|sum_\\(prefix\\|s\\(catter\\|"
316 "uffix\\)\\)\\|template\\|with\\)\\>")
317 "Regexp for all HPF keywords, procedures and directives.")
318
319 ;; Highlighting patterns
320
321 (defvar f90-font-lock-keywords-1
322 (if (string-match "XEmacs" emacs-version)
323 (list ; XEmacs
324 '("\\<\\(end[ \t]*\\(program\\|module\\|function\\|subroutine\\|type\\)\\)\\>"
325 1 font-lock-keyword-face)
326 '("\\<\\(end[ \t]*\\(program\\|module\\|function\\|subroutine\\|type\\)\\)\\>[ \t]*\\(\\sw+\\)"
327 3 font-lock-function-name-face)
328 '("\\<\\(program\\|call\\|module\\|subroutine\\|function\\|use\\)\\>"
329 1 font-lock-keyword-face)
330 '("\\<\\(program\\|call\\|module\\|subroutine\\|function\\|use\\)\\>[ \t]*\\(\\sw+\\)"
331 2 font-lock-function-name-face nil t)
332 ;; Special highlighting of "module procedure foo-list"
333 '("\\<\\(module[ \t]*procedure\\)\\>" 1 font-lock-keyword-face t)
334 ;; Highlight definition of new type
335 '("\\<\\(type\\)[ \t]*\\(,.*::[ \t]*\\|[ \t]+\\)\\(\\sw+\\)"
336 1 font-lock-keyword-face)
337 '("\\<\\(type\\)[ \t]*\\(,.*::[ \t]*\\|[ \t]+\\)\\(\\sw+\\)"
338 3 font-lock-function-name-face)
339 "\\<\\(\\(end[ \t]*\\)?\\(interface\\|block[ \t]*data\\)\\|contains\\)\\>")
340 (list ; Emacs
341 '("\\<\\(end[ \t]*\\(program\\|module\\|function\\|subroutine\\|type\\)\\)\\>[ \t]*\\(\\sw+\\)?"
342 (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
343 '("\\<\\(program\\|call\\|module\\|subroutine\\|function\\|use\\)\\>[ \t]*\\(\\sw+\\)?"
344 (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
345 ;; Special highlighting of "module procedure foo-list"
346 '("\\<\\(module[ \t]*procedure\\)\\>" (1 font-lock-keyword-face t))
347 ;; Highlight definition of new type
348 '("\\<\\(type\\)[ \t]*\\(,.*::[ \t]*\\|[ \t]+\\)\\(\\sw+\\)"
349 (1 font-lock-keyword-face) (3 font-lock-function-name-face))
350 "\\<\\(\\(end[ \t]*\\)?\\(interface\\|block[ \t]*data\\)\\|contains\\)\\>"))
351 "This does fairly subdued highlighting of comments and function calls.")
352
353 (defvar f90-font-lock-keywords-2
354 (append f90-font-lock-keywords-1
355 (if (string-match "XEmacs" emacs-version)
356 (list ; XEmacs
357 ;; Variable declarations (avoid the real function call)
358 '("^[ \t0-9]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|logical\\|type[ \t]*(\\sw+)\\)"
359 1 font-lock-type-face)
360 '("^[ \t0-9]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|logical\\|type[ \t]*(\\sw+)\\)\\(.*::\\|[ \t]*(.*)\\)?\\(.*\\)"
361 4 font-lock-doc-string-face)
362 ;; do, if and select constructs
363 '("\\<\\(end[ \t]*\\(do\\|if\\|select\\)\\)\\>"
364 1 font-lock-keyword-face)
365 '("\\<\\(end[ \t]*\\(do\\|if\\|select\\)\\)\\>\\([ \t]+\\(\\sw+\\)\\)"
366 3 font-lock-doc-string-face)
367 '("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)\\(\\(if\\|do\\([ \t]*while\\)?\\|select[ \t]*case\\)\\)\\>"
368 2 font-lock-doc-string-face)
369 '("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)?\\(\\(if\\|do\\([ \t]*while\\)?\\|select[ \t]*case\\)\\)\\>"
370 3 font-lock-keyword-face)
371 ;; implicit declaration
372 '("\\<\\(implicit\\)[ \t]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|logical\\|type[ \t]*(\\sw+)\\|none\\)\\>"
373 1 font-lock-keyword-face)
374 '("\\<\\(implicit\\)[ \t]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|logical\\|type[ \t]*(\\sw+)\\|none\\)\\>"
375 2 font-lock-type-face)
376 '("\\<\\(namelist\\|common\\)[ \t]*\/\\(\\sw+\\)?\/"
377 1 font-lock-keyword-face)
378 '("\\<\\(namelist\\|common\\)[ \t]*\/\\(\\sw+\\)\/"
379 2 font-lock-doc-string-face nil t)
380 '("\\<\\(where\\|forall\\)[ \t]*(" . 1)
381 "\\<e\\(lse\\([ \t]*if\\|where\\)?\\|nd[ \t]*\\(where\\|forall\\)\\)\\>"
382 "\\<\\(then\\|continue\\|format\\|include\\|stop\\|return\\)\\>"
383 '("\\<\\(exit\\|cycle\\)\\>"
384 1 font-lock-keyword-face)
385 '("\\<\\(exit\\|cycle\\)[ \t]*\\(\\sw+\\)2\\>"
386 2 font-lock-doc-string-face)
387 '("\\<\\(case\\)[ \t]*\\(default\\|(\\)" . 1)
388 '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)"
389 1 font-lock-keyword-face)
390 '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)"
391 2 font-lock-doc-string-face)
392 '("^[ \t]*\\([0-9]+\\)" 1 font-lock-doc-string-face t))
393 (list ; Emacs
394 ;; Variable declarations (avoid the real function call)
395 '("^[ \t0-9]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|logical\\|type[ \t]*(\\sw+)\\)\\(.*::\\|[ \t]*(.*)\\)?\\(.*\\)"
396 (1 font-lock-type-face) (4 font-lock-variable-name-face))
397 ;; do, if and select constructs
398 '("\\<\\(end[ \t]*\\(do\\|if\\|select\\)\\)\\>\\([ \t]+\\(\\sw+\\)\\)?"
399 (1 font-lock-keyword-face) (3 font-lock-reference-face nil t))
400 '("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)?\\(\\(if\\|do\\([ \t]*while\\)?\\|select[ \t]*case\\)\\)\\>"
401 (2 font-lock-reference-face nil t) (3 font-lock-keyword-face))
402 ;; implicit declaration
403 '("\\<\\(implicit\\)[ \t]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|logical\\|type[ \t]*(\\sw+)\\|none\\)\\>" (1 font-lock-keyword-face) (2 font-lock-type-face))
404 '("\\<\\(namelist\\|common\\)[ \t]*\/\\(\\sw+\\)?\/" (1 font-lock-keyword-face) (2 font-lock-reference-face nil t))
405 '("\\<\\(where\\|forall\\)[ \t]*(" . 1)
406 "\\<e\\(lse\\([ \t]*if\\|where\\)?\\|nd[ \t]*\\(where\\|forall\\)\\)\\>"
407 "\\<\\(then\\|continue\\|format\\|include\\|stop\\|return\\)\\>"
408 '("\\<\\(exit\\|cycle\\)[ \t]*\\(\\sw+\\)?\\>"
409 (1 font-lock-keyword-face) (2 font-lock-reference-face nil t))
410 '("\\<\\(case\\)[ \t]*\\(default\\|(\\)" . 1)
411 '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)"
412 (1 font-lock-keyword-face) (2 font-lock-reference-face))
413 '("^[ \t]*\\([0-9]+\\)" (1 font-lock-reference-face t)))))
414 "Highlights declarations, do-loops and other constructions")
415
416 (defvar f90-font-lock-keywords-3
417 (append f90-font-lock-keywords-2
418 (list
419 f90-keywords-level-3-re
420 f90-operators-re
421 (if (string-match "XEmacs" emacs-version)
422 (append (list f90-procedures-re) '(1 font-lock-keyword-face t))
423 (list f90-procedures-re '(1 font-lock-keyword-face t)))
424 "\\<real\\>" ; Avoid overwriting real defs.
425 ))
426 "Highlights all F90 keywords and intrinsic procedures.")
427
428 (defvar f90-font-lock-keywords-4
429 (append f90-font-lock-keywords-3
430 (list f90-hpf-keywords-re))
431 "Highlights all F90 and HPF keywords.")
432
433 (defvar f90-font-lock-keywords
434 f90-font-lock-keywords-2
435 "*Default expressions to highlight in F90 mode.")
436
437 ;; syntax table
438 (defvar f90-mode-syntax-table nil
439 "Syntax table in use in F90 mode buffers.")
440
441 (if f90-mode-syntax-table
442 ()
443 (setq f90-mode-syntax-table (make-syntax-table))
444 (modify-syntax-entry ?\! "<" f90-mode-syntax-table) ; beg. comment
445 (modify-syntax-entry ?\n ">" f90-mode-syntax-table) ; end comment
446 (modify-syntax-entry ?_ "w" f90-mode-syntax-table) ; underscore in names
447 (modify-syntax-entry ?\' "\"" f90-mode-syntax-table) ; string quote
448 (modify-syntax-entry ?\" "\"" f90-mode-syntax-table) ; string quote
449 (modify-syntax-entry ?\` "w" f90-mode-syntax-table) ; for abbrevs
450 (modify-syntax-entry ?\r " " f90-mode-syntax-table) ; return is whitespace
451 (modify-syntax-entry ?+ "." f90-mode-syntax-table)
452 (modify-syntax-entry ?- "." f90-mode-syntax-table)
453 (modify-syntax-entry ?= "." f90-mode-syntax-table)
454 (modify-syntax-entry ?* "." f90-mode-syntax-table)
455 (modify-syntax-entry ?/ "." f90-mode-syntax-table)
456 (modify-syntax-entry ?\\ "/" f90-mode-syntax-table)) ; escape chars
457
458 ;; keys
459 (defvar f90-mode-map ()
460 "Keymap used in F90 mode.")
461
462 (if f90-mode-map
463 ()
464 (setq f90-mode-map (make-sparse-keymap))
465 (define-key f90-mode-map "`" 'f90-abbrev-start)
466 (define-key f90-mode-map "\C-c;" 'f90-comment-region)
467 (define-key f90-mode-map "\C-\M-a" 'f90-beginning-of-subprogram)
468 (define-key f90-mode-map "\C-\M-e" 'f90-end-of-subprogram)
469 (define-key f90-mode-map "\C-\M-h" 'f90-mark-subprogram)
470 (define-key f90-mode-map "\C-\M-q" 'f90-indent-subprogram)
471 (define-key f90-mode-map "\C-j" 'f90-indent-new-line) ; LFD equals C-j
472 (define-key f90-mode-map "\r" 'newline)
473 (define-key f90-mode-map "\C-c\r" 'f90-break-line)
474 ;; (define-key f90-mode-map [M-return] 'f90-break-line)
475 (define-key f90-mode-map "\C-c\C-d" 'f90-join-lines)
476 (define-key f90-mode-map "\C-c\C-f" 'f90-fill-region)
477 (define-key f90-mode-map "\C-c\C-p" 'f90-previous-statement)
478 (define-key f90-mode-map "\C-c\C-n" 'f90-next-statement)
479 (define-key f90-mode-map "\C-c\C-w" 'f90-insert-end)
480 (define-key f90-mode-map "\t" 'f90-indent-line))
481
482 ;; menus
483 (if (string-match "XEmacs" emacs-version)
484 (defvar f90-xemacs-menu
485 '("F90"
486 ["Indent Subprogram" f90-indent-subprogram t]
487 ["Mark Subprogram" f90-mark-subprogram t]
488 ["Beginning of Subprogram" f90-beginning-of-subprogram t]
489 ["End of Subprogram" f90-end-of-subprogram t]
490 "-----"
491 ["(Un)Comment Region" f90-comment-region t]
492 ["Indent Region" indent-region t]
493 ["Fill Region" f90-fill-region t]
494 "-----"
495 ["Break Line at Point" f90-break-line t]
496 ["Join with Next Line" f90-join-lines t]
497 ["Insert Newline" newline t]
498 ["Insert End" f90-insert-end t]
499 "-----"
500 ["Upcase Keywords (buffer)" f90-upcase-keywords t]
501 ["Upcase Keywords (region)" f90-upcase-region-keywords
502 t]
503 ["Capitalize Keywords (buffer)" f90-capitalize-keywords t]
504 ["Capitalize Keywords (region)"
505 f90-capitalize-region-keywords t]
506 ["Downcase Keywords (buffer)" f90-downcase-keywords t]
507 ["Downcase Keywords (region)"
508 f90-downcase-region-keywords t]
509 "-----"
510 ["Toggle abbrev-mode" abbrev-mode t]
511 ["Toggle auto-fill" f90-auto-fill-mode t])
512 "XEmacs menu for F90 mode.")
513 ;; Emacs
514 (define-key f90-mode-map [menu-bar] (make-sparse-keymap))
515 (define-key f90-mode-map [menu-bar f90]
516 (cons "F90" (make-sparse-keymap "f90")))
517 (define-key f90-mode-map [menu-bar f90 abbrev-mode]
518 '("Toggle abbrev-mode" . abbrev-mode))
519 (define-key f90-mode-map [menu-bar f90 f90-auto-fill-mode]
520 '("Toggle auto-fill" . f90-auto-fill-mode))
521 (define-key f90-mode-map [menu-bar f90 f90-downcase-region-keywords]
522 '("Downcase Keywords (region)" . f90-downcase-region-keywords))
523 (define-key f90-mode-map [menu-bar f90 f90-downcase-keywords]
524 '("Downcase Keywords (buffer)" . f90-downcase-keywords))
525 (define-key f90-mode-map [menu-bar f90 f90-capitalize-keywords]
526 '("Capitalize Keywords (region)" . f90-capitalize-region-keywords))
527 (define-key f90-mode-map [menu-bar f90 f90-capitalize-region-keywords]
528 '("Capitalize Keywords (buffer)" . f90-capitalize-keywords))
529 (define-key f90-mode-map [menu-bar f90 f90-upcase-region-keywords]
530 '("Upcase Keywords (region)" . f90-upcase-region-keywords))
531 (define-key f90-mode-map [menu-bar f90 f90-upcase-keywords]
532 '("Upcase Keywords (buffer)" . f90-upcase-keywords))
533 (define-key f90-mode-map [menu-bar f90 f90-insert-end]
534 '("Insert end" . f90-insert-end))
535 (define-key f90-mode-map [menu-bar f90 f90-join-lines]
536 '("Join with Next Line" . f90-join-lines))
537 (define-key f90-mode-map [menu-bar f90 f90-break-line]
538 '("Break Line at Point" . f90-break-line))
539 (define-key f90-mode-map [menu-bar f90 f90-fill-region]
540 '("Fill Region" . f90-fill-region))
541 (define-key f90-mode-map [menu-bar f90 indent-region]
542 '("Indent Region" . indent-region))
543 (define-key f90-mode-map [menu-bar f90 f90-comment-region]
544 '("(Un)Comment Region" . f90-comment-region))
545 (define-key f90-mode-map [menu-bar f90 f90-end-of-subprogram]
546 '("End of Subprogram" . f90-end-of-subprogram))
547 (define-key f90-mode-map [menu-bar f90 f90-beginning-of-subprogram]
548 '("Beginning of Subprogram" . f90-beginning-of-subprogram))
549 (define-key f90-mode-map [menu-bar f90 f90-mark-subprogram]
550 '("Mark Subprogram" . f90-mark-subprogram))
551 (define-key f90-mode-map [menu-bar f90 f90-indent-subprogram]
552 '("Indent Subprogram" . f90-indent-subprogram)))
553
554 ;; Regexps for finding program structures.
555 (defconst f90-blocks-re
556 "\\(block[ \t]*data\\|do\\|if\\|interface\\|function\\|module\\|\
557 program\\|select\\|subroutine\\|type\\|where\\|forall\\)\\>")
558 (defconst f90-program-block-re
559 "\\(program\\|module\\|subroutine\\|function\\)")
560 (defconst f90-else-like-re
561 "\\(else\\([ \t]*if\\|where\\)?\\|case[ \t]*\\(default\\|(\\)\\)")
562 (defconst f90-end-if-re
563 "end[ \t]*\\(if\\|select\\|where\\|forall\\)\\>")
564 (defconst f90-end-type-re
565 "end[ \t]*\\(type\\|interface\\|block[ \t]*data\\)")
566 (defconst f90-type-def-re
567 "\\<\\(type\\)[ \t]*\\(,.*::[ \t]*\\|[ \t]+\\)\\(\\sw+\\)")
568 (defconst f90-no-break-re "\\(\\*\\*\\|//\\|=>\\)")
569 ;; A temporary position to make region operators faster
570 (defvar f90-cache-position nil)
571 (make-variable-buffer-local 'f90-cache-position)
572
573 ;; Imenu support
574 (defvar f90-imenu-generic-expression
575 (cons
576 (concat
577 "^[ \t0-9]*\\("
578 "program[ \t]+\\(\\sw+\\)\\|"
579 "module[ \t]+\\(\\sw+\\)[ \t]*\\(!\\|$\\)\\|"
580 "\\(pure\\|recursive\\|extrinsic([^)]+)\\)?[ \t]*"
581 "subroutine[ \t]+\\(\\sw+\\)\\|"
582 ; avoid end function, but allow for most other things
583 "\\([^!]*\\([^e!].[^ \t!]\\|.[^n!][^ \t!]\\|..[^d \t!]\\)"
584 "\\|[^!]?[^!]?\\)[ \t]*function[ \t]+\\(\\sw+\\)"
585 "\\)")
586 (list 2 3 6 9))
587 "imenu generic expression for F90 mode.")
588
589 ;; When compiling under GNU Emacs, load imenu during compilation. If
590 ;; you have 19.22 or earlier, comment this out, or get imenu.
591 (and (fboundp 'eval-when-compile)
592 (eval-when-compile
593 (if (not (string-match "XEmacs" emacs-version))
594 (require 'imenu))
595 ()))
596
597
598
599 ;; abbrevs have generally two letters, except standard types `c, `i, `r, `t
600 (defvar f90-mode-abbrev-table nil)
601 (if f90-mode-abbrev-table
602 ()
603 (let ((ac abbrevs-changed))
604 (define-abbrev-table 'f90-mode-abbrev-table ())
605 (define-abbrev f90-mode-abbrev-table "`al" "allocate" nil)
606 (define-abbrev f90-mode-abbrev-table "`ab" "allocatable" nil)
607 (define-abbrev f90-mode-abbrev-table "`as" "assignment" nil)
608 (define-abbrev f90-mode-abbrev-table "`ba" "backspace" nil)
609 (define-abbrev f90-mode-abbrev-table "`bd" "block data" nil)
610 (define-abbrev f90-mode-abbrev-table "`c" "character" nil)
611 (define-abbrev f90-mode-abbrev-table "`cl" "close" nil)
612 (define-abbrev f90-mode-abbrev-table "`cm" "common" nil)
613 (define-abbrev f90-mode-abbrev-table "`cx" "complex" nil)
614 (define-abbrev f90-mode-abbrev-table "`cn" "contains" nil)
615 (define-abbrev f90-mode-abbrev-table "`cy" "cycle" nil)
616 (define-abbrev f90-mode-abbrev-table "`de" "deallocate" nil)
617 (define-abbrev f90-mode-abbrev-table "`df" "define" nil)
618 (define-abbrev f90-mode-abbrev-table "`di" "dimension" nil)
619 (define-abbrev f90-mode-abbrev-table "`dw" "do while" nil)
620 (define-abbrev f90-mode-abbrev-table "`el" "else" nil)
621 (define-abbrev f90-mode-abbrev-table "`eli" "else if" nil)
622 (define-abbrev f90-mode-abbrev-table "`elw" "elsewhere" nil)
623 (define-abbrev f90-mode-abbrev-table "`eq" "equivalence" nil)
624 (define-abbrev f90-mode-abbrev-table "`ex" "external" nil)
625 (define-abbrev f90-mode-abbrev-table "`ey" "entry" nil)
626 (define-abbrev f90-mode-abbrev-table "`fl" "forall" nil)
627 (define-abbrev f90-mode-abbrev-table "`fo" "format" nil)
628 (define-abbrev f90-mode-abbrev-table "`fu" "function" nil)
629 (define-abbrev f90-mode-abbrev-table "`fa" ".false." nil)
630 (define-abbrev f90-mode-abbrev-table "`im" "implicit none" nil)
631 (define-abbrev f90-mode-abbrev-table "`in " "include" nil)
632 (define-abbrev f90-mode-abbrev-table "`i" "integer" nil)
633 (define-abbrev f90-mode-abbrev-table "`it" "intent" nil)
634 (define-abbrev f90-mode-abbrev-table "`if" "interface" nil)
635 (define-abbrev f90-mode-abbrev-table "`lo" "logical" nil)
636 (define-abbrev f90-mode-abbrev-table "`mo" "module" nil)
637 (define-abbrev f90-mode-abbrev-table "`na" "namelist" nil)
638 (define-abbrev f90-mode-abbrev-table "`nu" "nullify" nil)
639 (define-abbrev f90-mode-abbrev-table "`op" "optional" nil)
640 (define-abbrev f90-mode-abbrev-table "`pa" "parameter" nil)
641 (define-abbrev f90-mode-abbrev-table "`po" "pointer" nil)
642 (define-abbrev f90-mode-abbrev-table "`pr" "print" nil)
643 (define-abbrev f90-mode-abbrev-table "`pi" "private" nil)
644 (define-abbrev f90-mode-abbrev-table "`pm" "program" nil)
645 (define-abbrev f90-mode-abbrev-table "`pu" "public" nil)
646 (define-abbrev f90-mode-abbrev-table "`r" "real" nil)
647 (define-abbrev f90-mode-abbrev-table "`rc" "recursive" nil)
648 (define-abbrev f90-mode-abbrev-table "`rt" "return" nil)
649 (define-abbrev f90-mode-abbrev-table "`rw" "rewind" nil)
650 (define-abbrev f90-mode-abbrev-table "`se" "select" nil)
651 (define-abbrev f90-mode-abbrev-table "`sq" "sequence" nil)
652 (define-abbrev f90-mode-abbrev-table "`su" "subroutine" nil)
653 (define-abbrev f90-mode-abbrev-table "`ta" "target" nil)
654 (define-abbrev f90-mode-abbrev-table "`tr" ".true." nil)
655 (define-abbrev f90-mode-abbrev-table "`t" "type" nil)
656 (define-abbrev f90-mode-abbrev-table "`wh" "where" nil)
657 (define-abbrev f90-mode-abbrev-table "`wr" "write" nil)
658 (setq abbrevs-changed ac)))
659
660 ;;;###autoload
661 (defun f90-mode ()
662 "Major mode for editing Fortran 90 code in free format.
663
664 \\[f90-indent-new-line] corrects current indentation and creates new\
665 indented line.
666 \\[f90-indent-line] indents the current line correctly.
667 \\[f90-indent-subprogram] indents the current subprogram.
668
669 Type `? or `\\[help-command] to display a list of built-in\
670 abbrevs for F90 keywords.
671
672 Key definitions:
673 \\{f90-mode-map}
674
675 Variables controlling indentation style and extra features:
676
677 f90-do-indent
678 Extra indentation within do blocks. (default 3)
679 f90-if-indent
680 Extra indentation within if/select case/where/forall blocks. (default 3)
681 f90-type-indent
682 Extra indentation within type/interface/block-data blocks. (default 3)
683 f90-program-indent
684 Extra indentation within program/module/subroutine/function blocks.
685 (default 2)
686 f90-continuation-indent
687 Extra indentation applied to continuation lines. (default 5)
688 f90-comment-region
689 String inserted by \\[f90-comment-region] at start of each line in
690 region. (default \"!!!$\")
691 f90-indented-comment-re
692 Regexp determining the type of comment to be intended like code.
693 (default \"!\")
694 f90-directive-comment-re
695 Regexp of comment-like directive like \"!HPF\\\\$\", not to be indented.
696 (default \"!hpf\\\\$\")
697 f90-break-delimiters
698 Regexp holding list of delimiters at which lines may be broken.
699 (default \"[-+*/><=,% \\t]\")
700 f90-break-before-delimiters
701 Non-nil causes `f90-do-auto-fill' to break lines before delimiters.
702 (default t)
703 f90-beginning-ampersand
704 Automatic insertion of \& at beginning of continuation lines. (default t)
705 f90-smart-end
706 From an END statement, check and fill the end using matching block start.
707 Allowed values are 'blink, 'no-blink, and nil, which determine
708 whether to blink the matching beginning.) (default 'blink)
709 f90-auto-keyword-case
710 Automatic change of case of keywords. (default nil)
711 The possibilities are 'downcase-word, 'upcase-word, 'capitalize-word.
712 f90-leave-line-no
713 Do not left-justify line numbers. (default nil)
714 f90-startup-message
715 Set to nil to inhibit message first time F90 mode is used. (default t)
716 f90-keywords
717 List of keywords used for highlighting/upcase-keywords etc.
718
719 Turning on F90 mode calls the value of the variable `f90-mode-hook'
720 with no args, if that value is non-nil."
721 (interactive)
722 (kill-all-local-variables)
723 (setq major-mode 'f90-mode)
724 (setq mode-name "F90")
725 (setq local-abbrev-table f90-mode-abbrev-table)
726 (set-syntax-table f90-mode-syntax-table)
727 (use-local-map f90-mode-map)
728 (make-local-variable 'indent-line-function)
729 (setq indent-line-function 'f90-indent-line)
730 (make-local-variable 'indent-region-function)
731 (setq indent-region-function 'f90-indent-region)
732 (make-local-variable 'require-final-newline)
733 (setq require-final-newline t)
734 (make-local-variable 'comment-start)
735 (setq comment-start "!")
736 (make-local-variable 'comment-start-skip)
737 (setq comment-start-skip "!+ *")
738 (make-local-variable 'comment-indent-function)
739 (setq comment-indent-function 'f90-comment-indent)
740 (make-local-variable 'abbrev-all-caps)
741 (setq abbrev-all-caps t)
742 (setq indent-tabs-mode nil)
743 ;; Setting up things for font-lock
744 (if (string-match "XEmacs" emacs-version)
745 (progn
746 (if (and current-menubar
747 (not (assoc "F90" current-menubar)))
748 (progn
749 (set-buffer-menubar (copy-sequence current-menubar))
750 (add-submenu nil f90-xemacs-menu)))
751 ;; XEmacs now does things like FSF Emacs -- ben
752 (make-local-variable 'font-lock-defaults)
753 (setq font-lock-defaults
754 '((f90-font-lock-keywords f90-font-lock-keywords-1
755 f90-font-lock-keywords-2
756 f90-font-lock-keywords-3
757 f90-font-lock-keywords-4)
758 nil t)))
759 ;; Emacs
760 (make-local-variable 'font-lock-defaults)
761 (setq font-lock-defaults
762 '((f90-font-lock-keywords f90-font-lock-keywords-1
763 f90-font-lock-keywords-2
764 f90-font-lock-keywords-3
765 f90-font-lock-keywords-4)
766 nil t))
767 ;; Tell imenu how to handle f90.
768 (make-local-variable 'imenu-generic-expression)
769 (setq imenu-generic-expression f90-imenu-generic-expression))
770 (run-hooks 'f90-mode-hook)
771 (if f90-startup-message
772 (message "Emacs F90 mode; please report bugs to %s" bug-f90-mode))
773 (setq f90-startup-message nil))
774
775 ;; inline-functions
776 (defsubst f90-get-beg-of-line ()
777 (save-excursion (beginning-of-line) (point)))
778
779 (defsubst f90-get-end-of-line ()
780 (save-excursion (end-of-line) (point)))
781
782 (defsubst f90-in-string ()
783 (let ((beg-pnt
784 (if (and f90-cache-position (> (point) f90-cache-position))
785 f90-cache-position
786 (point-min))))
787 (nth 3 (parse-partial-sexp beg-pnt (point)))))
788
789 (defsubst f90-in-comment ()
790 (let ((beg-pnt
791 (if (and f90-cache-position (> (point) f90-cache-position))
792 f90-cache-position
793 (point-min))))
794 (nth 4 (parse-partial-sexp beg-pnt (point)))))
795
796 (defsubst f90-line-continued ()
797 (save-excursion
798 (let ((bol (f90-get-beg-of-line)))
799 (end-of-line)
800 (while (f90-in-comment)
801 (search-backward "!" bol)
802 (skip-chars-backward "!"))
803 (skip-chars-backward " \t")
804 (= (preceding-char) ?&))))
805
806 (defsubst f90-current-indentation ()
807 "Return indentation of current line.
808 Line-numbers are considered whitespace characters."
809 (save-excursion
810 (beginning-of-line) (skip-chars-forward " \t0-9")
811 (current-column)))
812
813 (defsubst f90-indent-to (col &optional no-line-number)
814 "Indent current line to column COL.
815 If no-line-number nil, jump over a possible line-number."
816 (beginning-of-line)
817 (if (not no-line-number)
818 (skip-chars-forward " \t0-9"))
819 (delete-horizontal-space)
820 (if (zerop (current-column))
821 (indent-to col)
822 (indent-to col 1)))
823
824 (defsubst f90-match-piece (arg)
825 (if (match-beginning arg)
826 (buffer-substring (match-beginning arg) (match-end arg))))
827
828 (defsubst f90-get-present-comment-type ()
829 (save-excursion
830 (let ((type nil) (eol (f90-get-end-of-line)))
831 (if (f90-in-comment)
832 (progn
833 (beginning-of-line)
834 (re-search-forward "[!]+" eol)
835 (while (f90-in-string)
836 (re-search-forward "[!]+" eol))
837 (setq type (buffer-substring (match-beginning 0) (match-end 0)))))
838 type)))
839
840 (defsubst f90-equal-symbols (a b)
841 "Compare strings neglecting case and allowing for nil value."
842 (let ((a-local (if a (downcase a) nil))
843 (b-local (if b (downcase b) nil)))
844 (equal a-local b-local)))
845
846 ;; XEmacs 19.11 & 19.12 gives back a single char when matching an empty regular
847 ;; expression. Therefore, the next 2 functions are longer than necessary.
848
849 (defsubst f90-looking-at-do ()
850 "Return (\"do\" name) if a do statement starts after point.
851 Name is nil if the statement has no label."
852 (if (looking-at "\\(\\(\\sw+\\)[ \t]*\:\\)?[ \t]*\\(do\\)\\>")
853 (let (label
854 (struct (f90-match-piece 3)))
855 (if (looking-at "\\(\\sw+\\)[ \t]*\:")
856 (setq label (f90-match-piece 1)))
857 (list struct label))))
858
859 (defsubst f90-looking-at-select-case ()
860 "Return (\"select\" name) if a select-case statement starts after point.
861 Name is nil if the statement has no label."
862 (if (looking-at "\\(\\(\\sw+\\)[ \t]*\:\\)?[ \t]*\\(select\\)[ \t]*case[ \t]*(")
863 (let (label
864 (struct (f90-match-piece 3)))
865 (if (looking-at "\\(\\sw+\\)[ \t]*\:")
866 (setq label (f90-match-piece 1)))
867 (list struct label))))
868
869 (defsubst f90-looking-at-if-then ()
870 "Return (\"if\" name) if an if () then statement starts after point.
871 Name is nil if the statement has no label."
872 (save-excursion
873 (let (struct (label nil))
874 (if (looking-at "\\(\\(\\sw+\\)[ \t]*\:\\)?[ \t]*\\(if\\)\\>")
875 (progn
876 (setq struct (f90-match-piece 3))
877 (if (looking-at "\\(\\sw+\\)[ \t]*\:")
878 (setq label (f90-match-piece 1)))
879 (goto-char (scan-lists (point) 1 0))
880 (skip-chars-forward " \t")
881 (if (or (looking-at "then\\>")
882 (if (f90-line-continued)
883 (progn
884 (f90-next-statement)
885 (skip-chars-forward " \t0-9&")
886 (looking-at "then\\>"))))
887 (list struct label)))))))
888
889 (defsubst f90-looking-at-where-or-forall ()
890 "Return (kind nil) if where/forall...end starts after point."
891 (save-excursion
892 (let (command)
893 (if (looking-at "\\(where\\|forall\\)[ \t]*(")
894 (progn
895 (setq command (list (f90-match-piece 1) nil))
896 (goto-char (scan-lists (point) 1 0))
897 (skip-chars-forward " \t")
898 (if (looking-at "\\(!\\|$\\)")
899 command))))))
900
901 (defsubst f90-looking-at-type-like ()
902 "Return (kind name) at the start of a type/interface/block-data block.
903 Name is non-nil only for type."
904 (cond
905 ((looking-at f90-type-def-re)
906 (list (f90-match-piece 1) (f90-match-piece 3)))
907 ((looking-at "\\(interface\\|block[\t]*data\\)\\>")
908 (list (f90-match-piece 1) nil))))
909
910 (defsubst f90-looking-at-program-block-start ()
911 "Return (kind name) if a program block with name name starts after point."
912 (cond
913 ((looking-at "\\(program\\)[ \t]+\\(\\sw+\\)\\>")
914 (list (f90-match-piece 1) (f90-match-piece 2)))
915 ((and (not (looking-at "module[ \t]*procedure\\>"))
916 (looking-at "\\(module\\)[ \t]+\\(\\sw+\\)\\>"))
917 (list (f90-match-piece 1) (f90-match-piece 2)))
918 ((looking-at (concat
919 "\\(pure\\|recursive\\|extrinsic([^)]+)\\)?[ \t]*"
920 "\\(subroutine\\)[ \t]+\\(\\sw+\\)"))
921 (list (f90-match-piece 2) (f90-match-piece 3)))
922 ((and (not (looking-at "end[ \t]*function"))
923 (looking-at "[^!\"\&\\n]*\\(function\\)[ \t]+\\(\\sw+\\)"))
924 (list (f90-match-piece 1) (f90-match-piece 2)))))
925
926 (defsubst f90-looking-at-program-block-end ()
927 "Return list of type and name of end of block."
928 (if (looking-at (concat "end[ \t]*" f90-blocks-re
929 "?\\([ \t]+\\(\\sw+\\)\\)?\\>"))
930 (list (f90-match-piece 1) (f90-match-piece 3))))
931
932 (defsubst f90-comment-indent ()
933 (cond ((looking-at "!!!") 0)
934 ((and f90-directive-comment-re
935 (looking-at f90-directive-comment-re)) 0)
936 ((looking-at (regexp-quote f90-comment-region)) 0)
937 ((looking-at f90-indented-comment-re)
938 (f90-calculate-indent))
939 (t (skip-chars-backward " \t")
940 (max (if (bolp) 0 (1+ (current-column))) comment-column))))
941
942 (defsubst f90-present-statement-cont ()
943 "Return continuation properties of present statement."
944 (let (pcont cont)
945 (save-excursion
946 (setq pcont (if (f90-previous-statement) (f90-line-continued) nil)))
947 (setq cont (f90-line-continued))
948 (cond ((and (not pcont) (not cont)) 'single)
949 ((and (not pcont) cont) 'begin)
950 ((and pcont (not cont)) 'end)
951 ((and pcont cont) 'middle)
952 (t (error)))))
953
954 (defsubst f90-indent-line-no ()
955 (if f90-leave-line-no
956 ()
957 (if (and (not (zerop (skip-chars-forward " \t")))
958 (looking-at "[0-9]"))
959 (delete-horizontal-space)))
960 (skip-chars-forward " \t0-9"))
961
962 (defsubst f90-no-block-limit ()
963 (let ((eol (f90-get-end-of-line)))
964 (save-excursion
965 (not (or (looking-at "end")
966 (looking-at "\\(do\\|if\\|else\\|select[ \t]*case\\|\
967 case\\|where\\|forall\\)\\>")
968 (looking-at "\\(program\\|module\\|interface\\|\
969 block[ \t]*data\\)\\>")
970 (looking-at "\\(contains\\|\\sw+[ \t]*:\\)")
971 (looking-at f90-type-def-re)
972 (re-search-forward "\\(function\\|subroutine\\)" eol t))))))
973
974 (defsubst f90-update-line ()
975 (let (bol eol)
976 (if f90-auto-keyword-case
977 (progn (setq bol (f90-get-beg-of-line)
978 eol (f90-get-end-of-line))
979 (if f90-auto-keyword-case
980 (f90-change-keywords f90-auto-keyword-case bol eol))))))
981
982 (defun f90-get-correct-indent ()
983 "Get correct indent for a line starting with line number.
984 Does not check type and subprogram indentation."
985 (let ((epnt (f90-get-end-of-line)) icol cont)
986 (save-excursion
987 (while (and (f90-previous-statement)
988 (or (progn
989 (setq cont (f90-present-statement-cont))
990 (or (eq cont 'end) (eq cont 'middle)))
991 (looking-at "[ \t]*[0-9]"))))
992 (setq icol (current-indentation))
993 (beginning-of-line)
994 (if (re-search-forward "\\(if\\|do\\|select\\|where\\|forall\\)"
995 (f90-get-end-of-line) t)
996 (progn
997 (beginning-of-line) (skip-chars-forward " \t")
998 (cond ((f90-looking-at-do)
999 (setq icol (+ icol f90-do-indent)))
1000 ((or (f90-looking-at-if-then)
1001 (f90-looking-at-where-or-forall)
1002 (f90-looking-at-select-case))
1003 (setq icol (+ icol f90-if-indent))))
1004 (end-of-line)))
1005 (while (re-search-forward
1006 "\\(if\\|do\\|select\\|where\\|forall\\)" epnt t)
1007 (beginning-of-line) (skip-chars-forward " \t0-9")
1008 (cond ((f90-looking-at-do)
1009 (setq icol (+ icol f90-do-indent)))
1010 ((or (f90-looking-at-if-then)
1011 (f90-looking-at-where-or-forall)
1012 (f90-looking-at-select-case))
1013 (setq icol (+ icol f90-if-indent)))
1014 ((looking-at f90-end-if-re)
1015 (setq icol (- icol f90-if-indent)))
1016 ((looking-at "end[ \t]*do\\>")
1017 (setq icol (- icol f90-do-indent))))
1018 (end-of-line))
1019 icol)))
1020
1021
1022 (defun f90-calculate-indent ()
1023 "Calculate the indent column based on previous statements."
1024 (interactive)
1025 (let (icol cont (case-fold-search t) (pnt (point)))
1026 (save-excursion
1027 (if (not (f90-previous-statement))
1028 (setq icol 0)
1029 (setq cont (f90-present-statement-cont))
1030 (if (eq cont 'end)
1031 (while (not (eq 'begin (f90-present-statement-cont)))
1032 (f90-previous-statement)))
1033 (cond ((eq cont 'begin)
1034 (setq icol (+ (f90-current-indentation)
1035 f90-continuation-indent)))
1036 ((eq cont 'middle) (setq icol(current-indentation)))
1037 (t (setq icol (f90-current-indentation))
1038 (skip-chars-forward " \t")
1039 (if (looking-at "[0-9]")
1040 (setq icol (f90-get-correct-indent))
1041 (cond ((or (f90-looking-at-if-then)
1042 (f90-looking-at-where-or-forall)
1043 (f90-looking-at-select-case)
1044 (looking-at f90-else-like-re))
1045 (setq icol (+ icol f90-if-indent)))
1046 ((f90-looking-at-do)
1047 (setq icol (+ icol f90-do-indent)))
1048 ((f90-looking-at-type-like)
1049 (setq icol (+ icol f90-type-indent)))
1050 ((or (f90-looking-at-program-block-start)
1051 (looking-at "contains[ \t]*\\($\\|!\\)"))
1052 (setq icol (+ icol f90-program-indent)))))
1053 (goto-char pnt)
1054 (beginning-of-line)
1055 (cond ((looking-at "[ \t]*$"))
1056 ((looking-at "[ \t]*#") ; Check for cpp directive.
1057 (setq icol 0))
1058 (t
1059 (skip-chars-forward " \t0-9")
1060 (cond ((or (looking-at f90-else-like-re)
1061 (looking-at f90-end-if-re))
1062 (setq icol (- icol f90-if-indent)))
1063 ((looking-at "end[ \t]*do\\>")
1064 (setq icol (- icol f90-do-indent)))
1065 ((looking-at f90-end-type-re)
1066 (setq icol (- icol f90-type-indent)))
1067 ((or (looking-at "contains[ \t]*\\(!\\|$\\)")
1068 (f90-looking-at-program-block-end))
1069 (setq icol (- icol f90-program-indent))))))
1070 ))))
1071 icol))
1072
1073 ;; Statement = statement line, a line which is neither blank, nor a comment.
1074 (defun f90-previous-statement ()
1075 "Move point to beginning of the previous F90 statement.
1076 Return nil if no previous statement is found."
1077 (interactive)
1078 (let (not-first-statement)
1079 (beginning-of-line)
1080 (while (and (setq not-first-statement (zerop (forward-line -1)))
1081 (looking-at "[ \t0-9]*\\(!\\|$\\|#\\)")))
1082 not-first-statement))
1083
1084 (defun f90-next-statement ()
1085 "Move point to beginning of the next F90 statement.
1086 Return nil if no later statement is found."
1087 (interactive)
1088 (let (not-last-statement)
1089 (beginning-of-line)
1090 (while (and (setq not-last-statement
1091 (and (zerop (forward-line 1))
1092 (not (eobp))))
1093 (looking-at "[ \t0-9]*\\(!\\|$\\)")))
1094 not-last-statement))
1095
1096 (defun f90-beginning-of-subprogram ()
1097 "Move point to the beginning of subprogram.
1098 Return (type name) or nil if not found."
1099 (interactive)
1100 (let ((count 1) (case-fold-search t) matching-beg)
1101 (beginning-of-line) (skip-chars-forward " \t0-9")
1102 (if (setq matching-beg (f90-looking-at-program-block-start))
1103 (setq count (- count 1)))
1104 (while (and (not (zerop count))
1105 (re-search-backward f90-program-block-re nil 'move))
1106 (beginning-of-line) (skip-chars-forward " \t0-9")
1107 (cond
1108 ((setq matching-beg (f90-looking-at-program-block-start))
1109 (setq count (- count 1)))
1110 ((f90-looking-at-program-block-end)
1111 (setq count (+ count 1)))))
1112 (beginning-of-line)
1113 (if (zerop count)
1114 matching-beg
1115 (message "No beginning-found.")
1116 nil)))
1117
1118 (defun f90-end-of-subprogram ()
1119 "Move point to the end of subprogram.
1120 Return (type name) or nil if not found."
1121 (interactive)
1122 (let ((count 1) (case-fold-search t) matching-end)
1123 (beginning-of-line) (skip-chars-forward " \t0-9")
1124 (if (setq matching-end (f90-looking-at-program-block-end))
1125 (setq count (1- count)))
1126 (end-of-line)
1127 (while (and (not (zerop count))
1128 (re-search-forward f90-program-block-re nil 'move))
1129 (beginning-of-line) (skip-chars-forward " \t0-9")
1130 (cond ((f90-looking-at-program-block-start)
1131 (setq count (+ count 1)))
1132 ((setq matching-end (f90-looking-at-program-block-end))
1133 (setq count (1- count ))))
1134 (end-of-line))
1135 (forward-line 1)
1136 (if (zerop count)
1137 matching-end
1138 (message "No end found.")
1139 nil)))
1140
1141 (defun f90-mark-subprogram ()
1142 "Put mark at end of F90 subprogram, point at beginning.
1143 Marks are pushed and highlight (grey shadow) is turned on."
1144 (interactive)
1145 (let ((pos (point)) program)
1146 (f90-end-of-subprogram)
1147 (push-mark (point) t)
1148 (goto-char pos)
1149 (setq program (f90-beginning-of-subprogram))
1150 ;; The keywords in the preceding lists assume case-insensitivity.
1151 (if (string-match "XEmacs" emacs-version)
1152 (zmacs-activate-region)
1153 (setq mark-active t)
1154 (setq deactivate-mark nil))
1155 program))
1156
1157 (defun f90-comment-region (beg-region end-region)
1158 "Comment/uncomment every line in the region.
1159 Insert f90-comment-region at the beginning of every line in the region
1160 or, if already present, remove it."
1161 (interactive "*r")
1162 (let ((end (make-marker)))
1163 (set-marker end end-region)
1164 (goto-char beg-region)
1165 (beginning-of-line)
1166 (if (looking-at (regexp-quote f90-comment-region))
1167 (delete-region (point) (match-end 0))
1168 (insert f90-comment-region))
1169 (while (and (zerop (forward-line 1))
1170 (< (point) (marker-position end)))
1171 (if (looking-at (regexp-quote f90-comment-region))
1172 (delete-region (point) (match-end 0))
1173 (insert f90-comment-region)))
1174 (set-marker end nil)))
1175
1176 (defun f90-indent-line (&optional no-update)
1177 "Indent current line as F90 code."
1178 (interactive)
1179 (let (indent (no-line-number nil) (pos (make-marker)) (case-fold-search t))
1180 (set-marker pos (point))
1181 (beginning-of-line) ; Digits after & \n are not line-no
1182 (if (save-excursion (and (f90-previous-statement) (f90-line-continued)))
1183 (progn (setq no-line-number t) (skip-chars-forward " \t"))
1184 (f90-indent-line-no))
1185 (if (looking-at "!")
1186 (setq indent (f90-comment-indent))
1187 (if (and (looking-at "end") f90-smart-end)
1188 (f90-match-end))
1189 (setq indent (f90-calculate-indent)))
1190 (if (zerop (- indent (current-column)))
1191 nil
1192 (f90-indent-to indent no-line-number))
1193 ;; If initial point was within line's indentation,
1194 ;; position after the indentation. Else stay at same point in text.
1195 (if (< (point) (marker-position pos))
1196 (goto-char (marker-position pos)))
1197 (if (not no-update) (f90-update-line))
1198 (if (and auto-fill-function
1199 (> (save-excursion (end-of-line) (current-column)) fill-column))
1200 (save-excursion (f90-do-auto-fill)))
1201 (set-marker pos nil)))
1202
1203 (defun f90-indent-new-line ()
1204 "Reindent the current F90 line, insert a newline and indent the newline.
1205 An abbrev before point is expanded if `abbrev-mode' is non-nil.
1206 If run in the middle of a line, the line is not broken."
1207 (interactive)
1208 (let (string cont (case-fold-search t))
1209 (if abbrev-mode (expand-abbrev))
1210 (beginning-of-line) ; Reindent where likely to be needed.
1211 (f90-indent-line-no)
1212 (if (or (looking-at "\\(end\\|else\\|!\\)"))
1213 (f90-indent-line 'no-update))
1214 (end-of-line)
1215 (delete-horizontal-space) ;Destroy trailing whitespace
1216 (setq string (f90-in-string))
1217 (setq cont (f90-line-continued))
1218 (if (and string (not cont)) (insert "&"))
1219 (f90-update-line)
1220 (newline)
1221 (if (or string (and cont f90-beginning-ampersand)) (insert "&"))
1222 (f90-indent-line 'no-update)))
1223
1224
1225 (defun f90-indent-region (beg-region end-region)
1226 "Indent every line in region by forward parsing."
1227 (interactive "*r")
1228 (let ((end-region-mark (make-marker)) (save-point (point-marker))
1229 (block-list nil) ind-lev ind-curr ind-b cont
1230 struct beg-struct end-struct)
1231 (set-marker end-region-mark end-region)
1232 (goto-char beg-region)
1233 ;; first find a line which is not a continuation line or comment
1234 (beginning-of-line)
1235 (while (and (looking-at "[ \t]*[0-9]*\\(!\\|#\\|[ \t]*$\\)")
1236 (progn (f90-indent-line 'no-update)
1237 (zerop (forward-line 1)))
1238 (< (point) end-region-mark)))
1239 (setq cont (f90-present-statement-cont))
1240 (while (and (or (eq cont 'middle) (eq cont 'end))
1241 (f90-previous-statement))
1242 (setq cont (f90-present-statement-cont)))
1243 ;; process present line for beginning of block
1244 (setq f90-cache-position (point))
1245 (f90-indent-line 'no-update)
1246 (setq ind-lev (f90-current-indentation))
1247 (setq ind-curr ind-lev)
1248 (beginning-of-line) (skip-chars-forward " \t0-9")
1249 (setq struct nil)
1250 (setq ind-b (cond ((setq struct (f90-looking-at-do)) f90-do-indent)
1251 ((or (setq struct (f90-looking-at-if-then))
1252 (setq struct (f90-looking-at-select-case))
1253 (setq struct (f90-looking-at-where-or-forall))
1254 (looking-at f90-else-like-re))
1255 f90-if-indent)
1256 ((setq struct (f90-looking-at-type-like))
1257 f90-type-indent)
1258 ((or(setq struct (f90-looking-at-program-block-start))
1259 (looking-at "contains[ \t]*\\($\\|!\\)"))
1260 f90-program-indent)))
1261 (if ind-b (setq ind-lev (+ ind-lev ind-b)))
1262 (if struct (setq block-list (cons struct block-list)))
1263 (while (and (f90-line-continued) (zerop (forward-line 1))
1264 (< (point) end-region-mark))
1265 (if (not (zerop (- (current-indentation)
1266 (+ ind-curr f90-continuation-indent))))
1267 (f90-indent-to (+ ind-curr f90-continuation-indent) 'no-line-no)))
1268 ;; process all following lines
1269 (while (and (zerop (forward-line 1)) (< (point) end-region-mark))
1270 (beginning-of-line)
1271 (f90-indent-line-no)
1272 (setq f90-cache-position (point))
1273 (cond ((looking-at "[ \t]*$") (setq ind-curr 0))
1274 ((looking-at "[ \t]*#") (setq ind-curr 0))
1275 ((looking-at "!") (setq ind-curr (f90-comment-indent)))
1276 ((f90-no-block-limit) (setq ind-curr ind-lev))
1277 ((looking-at f90-else-like-re) (setq ind-curr
1278 (- ind-lev f90-if-indent)))
1279 ((looking-at "contains[ \t]*\\($\\|!\\)")
1280 (setq ind-curr (- ind-lev f90-program-indent)))
1281 ((setq ind-b
1282 (cond ((setq struct (f90-looking-at-do)) f90-do-indent)
1283 ((or (setq struct (f90-looking-at-if-then))
1284 (setq struct (f90-looking-at-select-case))
1285 (setq struct (f90-looking-at-where-or-forall)))
1286 f90-if-indent)
1287 ((setq struct (f90-looking-at-type-like))
1288 f90-type-indent)
1289 ((setq struct (f90-looking-at-program-block-start))
1290 f90-program-indent)))
1291 (setq ind-curr ind-lev)
1292 (if ind-b (setq ind-lev (+ ind-lev ind-b)))
1293 (setq block-list (cons struct block-list)))
1294 ((setq end-struct (f90-looking-at-program-block-end))
1295 (setq beg-struct (car block-list)
1296 block-list (cdr block-list))
1297 (if f90-smart-end
1298 (save-excursion
1299 (f90-block-match (car beg-struct)(car (cdr beg-struct))
1300 (car end-struct)(car (cdr end-struct)))))
1301 (setq ind-b
1302 (cond ((looking-at f90-end-if-re) f90-if-indent)
1303 ((looking-at "end[ \t]*do\\>") f90-do-indent)
1304 ((looking-at f90-end-type-re) f90-type-indent)
1305 ((f90-looking-at-program-block-end)
1306 f90-program-indent)))
1307 (if ind-b (setq ind-lev (- ind-lev ind-b)))
1308 (setq ind-curr ind-lev))
1309 (t (setq ind-curr ind-lev)))
1310 ;; do the indentation if necessary
1311 (if (not (zerop (- ind-curr (current-column))))
1312 (f90-indent-to ind-curr))
1313 (while (and (f90-line-continued) (zerop (forward-line 1))
1314 (< (point) end-region-mark))
1315 (if (not (zerop (- (current-indentation)
1316 (+ ind-curr f90-continuation-indent))))
1317 (f90-indent-to (+ ind-curr f90-continuation-indent) 'no-line-no))))
1318 ;; restore point etc
1319 (setq f90-cache-position nil)
1320 (goto-char save-point)
1321 (set-marker end-region-mark nil)
1322 (set-marker save-point nil)
1323 (if (string-match "XEmacs" emacs-version)
1324 (zmacs-deactivate-region)
1325 (deactivate-mark))))
1326
1327 (defun f90-indent-subprogram ()
1328 "Properly indent the subprogram which contains point."
1329 (interactive)
1330 (save-excursion
1331 (let (program)
1332 (setq program (f90-mark-subprogram))
1333 (if program
1334 (progn
1335 (message (concat "Indenting " (car program) " "
1336 (car (cdr program))"."))
1337 (f90-indent-region (point) (mark))
1338 (message (concat "Indenting " (car program) " "
1339 (car (cdr program)) "...done.")))
1340 (message "Indenting the whole file.")
1341 (f90-indent-region (point) (mark))
1342 (message (concat "Indenting the whole file...done."))))))
1343
1344 ;; autofill and break-line
1345 (defun f90-break-line (&optional no-update)
1346 "Break line at point, insert continuation marker(s) and indent."
1347 (interactive)
1348 (let (ctype)
1349 (cond ((f90-in-string)
1350 (insert "&") (newline) (insert "&"))
1351 ((f90-in-comment)
1352 (delete-horizontal-space)
1353 (setq ctype (f90-get-present-comment-type))
1354 (newline) (insert (concat ctype " ")))
1355 (t (delete-horizontal-space)
1356 (insert "&")
1357 (if (not no-update) (f90-update-line))
1358 (newline)
1359 (if f90-beginning-ampersand (insert "& ")))))
1360 (if (not no-update) (f90-indent-line)))
1361
1362 (defun f90-find-breakpoint ()
1363 "From fill-column, search backward for break-delimiter."
1364 (let ((bol (f90-get-beg-of-line)))
1365 (re-search-backward f90-break-delimiters bol)
1366 (if f90-break-before-delimiters
1367 (progn (backward-char)
1368 (if (not (looking-at f90-no-break-re))
1369 (forward-char)))
1370 (if (looking-at f90-no-break-re)
1371 (forward-char 2)
1372 (forward-char)))))
1373
1374 (defun f90-auto-fill-mode (arg)
1375 "Toggle f90-auto-fill mode.
1376 With ARG, turn `f90-auto-fill' mode on iff ARG is positive.
1377 In `f90-auto-fill' mode, inserting a space at a column beyond `fill-column'
1378 automatically breaks the line at a previous space."
1379 (interactive "P")
1380 (prog1 (setq auto-fill-function
1381 (if (if (null arg)
1382 (not auto-fill-function)
1383 (> (prefix-numeric-value arg) 0))
1384 'f90-do-auto-fill))
1385 (force-mode-line-update)))
1386
1387 (defun f90-do-auto-fill ()
1388 "Break line if non-white characters beyond fill-column."
1389 (interactive)
1390 ;; Break the line before or after the last delimiter (non-word char).
1391 ;; Will not break **, //, or => (specified by f90-no-break-re).
1392 ;; Start by checking that line is longer than fill-column.
1393 (if (> (save-excursion (end-of-line) (current-column)) fill-column)
1394 (progn
1395 (move-to-column fill-column)
1396 (if (and (looking-at "[ \t]*$") (not (f90-in-string)))
1397 (delete-horizontal-space)
1398 (f90-find-breakpoint)
1399 (f90-break-line)
1400 (end-of-line)))))
1401
1402 (defun f90-join-lines ()
1403 "Join present line with next line, if this line ends with \&."
1404 (interactive)
1405 (let (pos (oldpos (point)))
1406 (end-of-line)
1407 (skip-chars-backward " \t")
1408 (cond ((= (preceding-char) ?&)
1409 (delete-char -1)
1410 (setq pos (point))
1411 (forward-line 1)
1412 (skip-chars-forward " \t")
1413 (if (looking-at "\&") (delete-char 1))
1414 (delete-region pos (point))
1415 (if (not (f90-in-string))
1416 (progn (delete-horizontal-space) (insert " ")))
1417 (if (and auto-fill-function
1418 (> (save-excursion (end-of-line)
1419 (current-column))
1420 fill-column))
1421 (f90-do-auto-fill))
1422 (goto-char oldpos)
1423 t))))
1424
1425 (defun f90-fill-region (beg-region end-region)
1426 "Fill every line in region by forward parsing. Join lines if possible."
1427 (interactive "*r")
1428 (let ((end-region-mark (make-marker))
1429 (f90-smart-end nil) (f90-auto-keyword-case nil) indent (go-on t)
1430 (af-function auto-fill-function) (auto-fill-function nil))
1431 (set-marker end-region-mark end-region)
1432 (goto-char beg-region)
1433 (while go-on
1434 ;; join as much as possible
1435 (while (f90-join-lines));
1436 (setq indent (+ (f90-current-indentation) f90-continuation-indent))
1437 ;; chop the line if necessary
1438 (while (> (save-excursion (end-of-line) (current-column))
1439 fill-column)
1440 (move-to-column fill-column)
1441 (if (and (looking-at "[ \t]*$") (not (f90-in-string)))
1442 (delete-horizontal-space)
1443 (f90-find-breakpoint)
1444 (f90-break-line 'no-update)
1445 (f90-indent-to indent 'no-line-no)))
1446 (setq go-on (and (< (point) (marker-position end-region-mark))
1447 (zerop (forward-line 1))))
1448 (setq f90-cache-position (point)))
1449 (setq auto-fill-function af-function)
1450 (setq f90-cache-position nil)
1451 (if (string-match "XEmacs" emacs-version)
1452 (zmacs-deactivate-region)
1453 (deactivate-mark))))
1454
1455 (defun f90-block-match (beg-block beg-name end-block end-name)
1456 "Match end-struct with beg-struct and complete end-block if possible.
1457 Leave point at the end of line."
1458 (search-forward "end" (f90-get-end-of-line))
1459 (catch 'no-match
1460 (if (not (f90-equal-symbols beg-block end-block))
1461 (if end-block
1462 (progn
1463 (message "END %s does not match %s." end-block beg-block)
1464 (end-of-line)
1465 (throw 'no-match nil))
1466 (message "Inserting %s." beg-block)
1467 (insert (concat " " beg-block)))
1468 (search-forward end-block))
1469 (if (not (f90-equal-symbols beg-name end-name))
1470 (cond ((and beg-name (not end-name))
1471 (message "Inserting %s." beg-name)
1472 (insert (concat " " beg-name)))
1473 ((and beg-name end-name)
1474 (message "Replacing %s with %s." end-name beg-name)
1475 (search-forward end-name)
1476 (replace-match beg-name))
1477 ((and (not beg-name) end-name)
1478 (message "Deleting %s." end-name)
1479 (search-forward end-name)
1480 (replace-match "")))
1481 (if end-name (search-forward end-name)))
1482 (if (not (looking-at "[ \t]*!")) (delete-horizontal-space))))
1483
1484 (defun f90-match-end ()
1485 "From an end foo statement, find the corresponding foo including name."
1486 (interactive)
1487 (let ((count 1) (top-of-window (window-start)) (matching-beg nil)
1488 (end-point (point)) (case-fold-search t)
1489 beg-name end-name beg-block end-block end-struct)
1490 (if (save-excursion (beginning-of-line) (skip-chars-forward " \t0-9")
1491 (setq end-struct (f90-looking-at-program-block-end)))
1492 (progn
1493 (setq end-block (car end-struct))
1494 (setq end-name (car (cdr end-struct)))
1495 (save-excursion
1496 (beginning-of-line)
1497 (while
1498 (and (not (zerop count))
1499 (let ((stop nil) notexist)
1500 (while (not stop)
1501 (setq notexist
1502 (not (re-search-backward
1503 (concat "\\(" f90-blocks-re "\\)") nil t)))
1504 (if notexist
1505 (setq stop t)
1506 (setq stop
1507 (not (or (f90-in-string)
1508 (f90-in-comment))))))
1509 (not notexist)))
1510 (beginning-of-line) (skip-chars-forward " \t0-9")
1511 (cond ((setq matching-beg
1512 (cond
1513 ((f90-looking-at-do))
1514 ((f90-looking-at-if-then))
1515 ((f90-looking-at-where-or-forall))
1516 ((f90-looking-at-select-case))
1517 ((f90-looking-at-type-like))
1518 ((f90-looking-at-program-block-start))))
1519 (setq count (- count 1)))
1520 ((looking-at (concat "end[ \t]*" f90-blocks-re "\\b"))
1521 (setq count (+ count 1)))))
1522 (if (not (zerop count))
1523 (message "No matching beginning.")
1524 (f90-update-line)
1525 (if (eq f90-smart-end 'blink)
1526 (if (< (point) top-of-window)
1527 (message (concat
1528 "Matches " (what-line) ": "
1529 (buffer-substring
1530 (progn (beginning-of-line) (point))
1531 (progn (end-of-line) (point)))))
1532 (sit-for 1)))
1533 (setq beg-block (car matching-beg))
1534 (setq beg-name (car (cdr matching-beg)))
1535 (goto-char end-point)
1536 (beginning-of-line)
1537 (f90-block-match beg-block beg-name end-block end-name)))))))
1538
1539 (defun f90-insert-end ()
1540 "Inserts an complete end statement matching beginning of present block."
1541 (interactive)
1542 (let ((f90-smart-end (if f90-smart-end f90-smart-end 'blink)))
1543 (insert "end")
1544 (f90-indent-new-line)))
1545
1546 ;; abbrevs and keywords
1547
1548 (defun f90-abbrev-start ()
1549 "Typing `\\[help-command] or `? lists all the F90 abbrevs.
1550 Any other key combination is executed normally."
1551 (interactive)
1552 (let (e c)
1553 (insert last-command-char)
1554 (if (string-match "XEmacs" emacs-version)
1555 (progn
1556 (setq e (next-command-event))
1557 (setq c (event-to-character e)))
1558 (setq c (read-event)))
1559 ;; insert char if not equal to `?'
1560 (if (or (= c ??) (eq c help-char))
1561 (f90-abbrev-help)
1562 (if (string-match "XEmacs" emacs-version)
1563 (setq unread-command-event e)
1564 (setq unread-command-events (list c))))))
1565
1566 (defun f90-abbrev-help ()
1567 "List the currently defined abbrevs in F90 mode."
1568 (interactive)
1569 (message "Listing abbrev table...")
1570 (display-buffer (f90-prepare-abbrev-list-buffer))
1571 (message "Listing abbrev table...done"))
1572
1573 (defun f90-prepare-abbrev-list-buffer ()
1574 (save-excursion
1575 (set-buffer (get-buffer-create "*Abbrevs*"))
1576 (erase-buffer)
1577 (insert-abbrev-table-description 'f90-mode-abbrev-table t)
1578 (goto-char (point-min))
1579 (set-buffer-modified-p nil)
1580 (edit-abbrevs-mode))
1581 (get-buffer-create "*Abbrevs*"))
1582
1583 (defun f90-upcase-keywords ()
1584 "Upcase all F90 keywords in the buffer."
1585 (interactive)
1586 (f90-change-keywords 'upcase-word))
1587
1588 (defun f90-capitalize-keywords ()
1589 "Capitalize all F90 keywords in the buffer."
1590 (interactive)
1591 (f90-change-keywords 'capitalize-word))
1592
1593 (defun f90-downcase-keywords ()
1594 "Downcase all F90 keywords in the buffer."
1595 (interactive)
1596 (f90-change-keywords 'downcase-word))
1597
1598 (defun f90-upcase-region-keywords (beg end)
1599 "Upcase all F90 keywords in the region."
1600 (interactive "*r")
1601 (f90-change-keywords 'upcase-word beg end))
1602
1603 (defun f90-capitalize-region-keywords (beg end)
1604 "Capitalize all F90 keywords in the region."
1605 (interactive "*r")
1606 (f90-change-keywords 'capitalize-word beg end))
1607
1608 (defun f90-downcase-region-keywords (beg end)
1609 "Downcase all F90 keywords in the region."
1610 (interactive "*r")
1611 (f90-change-keywords 'downcase-word beg end))
1612
1613 ;; Change the keywords according to argument.
1614 (defun f90-change-keywords (change-word &optional beg end)
1615 (save-excursion
1616 (setq beg (if beg beg (point-min)))
1617 (setq end (if end end (point-max)))
1618 (let ((keyword-re
1619 (concat "\\("
1620 f90-keywords-re "\\|" f90-procedures-re "\\|"
1621 f90-hpf-keywords-re "\\|" f90-operators-re "\\)"))
1622 (ref-point (point-min)) state
1623 (modified (buffer-modified-p)) saveword back-point)
1624 (goto-char beg)
1625 (unwind-protect
1626 (while (re-search-forward keyword-re end t)
1627 (if (progn
1628 (setq state (parse-partial-sexp ref-point (point)))
1629 (or (nth 3 state) (nth 4 state)
1630 (save-excursion ; Check for cpp directive.
1631 (beginning-of-line)
1632 (skip-chars-forward " \t0-9")
1633 (looking-at "#"))))
1634 ()
1635 (setq ref-point (point)
1636 back-point (save-excursion (backward-word 1) (point)))
1637 (setq saveword (buffer-substring back-point ref-point))
1638 (funcall change-word -1)
1639 (or (string= saveword (buffer-substring back-point ref-point))
1640 (setq modified t))))
1641 (or modified (set-buffer-modified-p nil))))))
1642
1643 (provide 'f90)
1644
1645 ;;; f90.el ends here