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