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