Use set-temporary-overlay-map.
[bpt/emacs.git] / lisp / progmodes / f90.el
CommitLineData
48da7392 1;;; f90.el --- Fortran-90 mode (free format) -*- lexical-binding: t -*-
b578f267 2
acaf905b 3;; Copyright (C) 1995-1997, 2000-2012 Free Software Foundation, Inc.
034a9d40 4
239da61d 5;; Author: Torbjörn Einarsson <Torbjorn.Einarsson@era.ericsson.se>
9877fcf1 6;; Maintainer: Glenn Morris <rgm@gnu.org>
034a9d40
RS
7;; Keywords: fortran, f90, languages
8
b578f267
EN
9;; This file is part of GNU Emacs.
10
b1fc2b50 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
b1fc2b50
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) 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
b1fc2b50 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
034a9d40
RS
23
24;;; Commentary:
b578f267 25
87ee2359
GM
26;; Major mode for editing F90 programs in FREE FORMAT.
27;; The minor language revision F95 is also supported (with font-locking).
b1ca7740 28;; Some/many (?) aspects of F2003 are supported.
5d8e0d43 29;; Some aspects of F2008 are supported.
87ee2359 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 "`"
87ee2359 40;; For example, `i expands to integer (if abbrev-mode is on).
034a9d40 41
87ee2359 42;; There are two separate features for altering the appearance of code:
034a9d40 43;; 1) Upcasing or capitalizing of all keywords.
87ee2359
GM
44;; 2) Colors/fonts using font-lock-mode.
45;; Automatic upcase or downcase of keywords is controlled by the variable
46;; f90-auto-keyword-case.
034a9d40
RS
47
48;; The indentations of lines starting with ! is determined by the first of the
87ee2359 49;; following matches (values in the left column are the defaults):
ee30478d
KH
50
51;; start-string/regexp indent variable holding start-string/regexp
52;; !!! 0
53;; !hpf\\$ (re) 0 f90-directive-comment-re
54;; !!$ 0 f90-comment-region
55;; ! (re) as code f90-indented-comment-re
56;; default comment-column
57
58;; Ex: Here is the result of 3 different settings of f90-indented-comment-re
59;; f90-indented-comment-re !-indentation !!-indentation
60;; ! as code as code
61;; !! comment-column as code
62;; ![^!] as code comment-column
87ee2359
GM
63;; Trailing comments are indented to comment-column with indent-for-comment.
64;; The function f90-comment-region toggles insertion of
65;; the variable f90-comment-region in every line of the region.
034a9d40 66
a729409a 67;; One common convention for free vs. fixed format is that free format files
69658465 68;; have the ending .f90 or .f95 while fixed format files have the ending .f.
87ee2359
GM
69;; Emacs automatically loads Fortran files in the appropriate mode based
70;; on extension. You can modify this by adjusting the variable auto-mode-alist.
71;; For example:
72;; (add-to-list 'auto-mode-alist '("\\.f\\'" . f90-mode))
73
034a9d40 74;; Once you have entered f90-mode, you may get more info by using
69658465 75;; the command describe-mode (C-h m). For online help use
87ee2359
GM
76;; C-h f <Name of function you want described>, or
77;; C-h v <Name of variable you want described>.
034a9d40 78
87ee2359
GM
79;; To customize f90-mode for your taste, use, for example:
80;; (you don't have to specify values for all the parameters below)
81;;
4f91a816
SM
82;; (add-hook 'f90-mode-hook
83;; ;; These are the default values.
84;; (lambda () (setq f90-do-indent 3
034a9d40
RS
85;; f90-if-indent 3
86;; f90-type-indent 3
87;; f90-program-indent 2
88;; f90-continuation-indent 5
89;; f90-comment-region "!!$"
ee30478d
KH
90;; f90-directive-comment-re "!hpf\\$"
91;; f90-indented-comment-re "!"
87ee2359 92;; f90-break-delimiters "[-+\\*/><=,% \t]"
034a9d40
RS
93;; f90-break-before-delimiters t
94;; f90-beginning-ampersand t
95;; f90-smart-end 'blink
96;; f90-auto-keyword-case nil
87ee2359 97;; f90-leave-line-no nil
72e80cad 98;; indent-tabs-mode nil
b974df0a 99;; f90-font-lock-keywords f90-font-lock-keywords-2
72e80cad 100;; )
87ee2359 101;; ;; These are not default.
034a9d40 102;; (abbrev-mode 1) ; turn on abbreviation mode
b974df0a 103;; (f90-add-imenu-menu) ; extra menu with functions etc.
034a9d40
RS
104;; (if f90-auto-keyword-case ; change case of all keywords on startup
105;; (f90-change-keywords f90-auto-keyword-case))
640f9e26 106;; ))
87ee2359
GM
107;;
108;; in your .emacs file. You can also customize the lists
109;; f90-font-lock-keywords, etc.
110;;
111;; The auto-fill and abbreviation minor modes are accessible from the F90 menu,
b974df0a 112;; or by using M-x auto-fill-mode and M-x abbrev-mode, respectively.
034a9d40
RS
113
114;; Remarks
115;; 1) Line numbers are by default left-justified. If f90-leave-line-no is
116;; non-nil, the line numbers are never touched.
87ee2359 117;; 2) Multi-; statements like "do i=1,20 ; j=j+i ; end do" are not handled
034a9d40 118;; correctly, but I imagine them to be rare.
ee30478d 119;; 3) Regexps for hilit19 are no longer supported.
87ee2359 120;; 4) For FIXED FORMAT code, use fortran mode.
034a9d40 121;; 5) This mode does not work under emacs-18.x.
72e80cad
KH
122;; 6) Preprocessor directives, i.e., lines starting with # are left-justified
123;; and are untouched by all case-changing commands. There is, at present, no
124;; mechanism for treating multi-line directives (continued by \ ).
ee30478d
KH
125;; 7) f77 do-loops do 10 i=.. ; ; 10 continue are not correctly indented.
126;; You are urged to use f90-do loops (with labels if you wish).
c80718cc 127;; 8) The highlighting mode under XEmacs is not as complete as under Emacs.
034a9d40
RS
128
129;; List of user commands
130;; f90-previous-statement f90-next-statement
131;; f90-beginning-of-subprogram f90-end-of-subprogram f90-mark-subprogram
132;; f90-comment-region
133;; f90-indent-line f90-indent-new-line
134;; f90-indent-region (can be called by calling indent-region)
135;; f90-indent-subprogram
136;; f90-break-line f90-join-lines
034a9d40
RS
137;; f90-fill-region
138;; f90-insert-end
139;; f90-upcase-keywords f90-upcase-region-keywords
140;; f90-downcase-keywords f90-downcase-region-keywords
141;; f90-capitalize-keywords f90-capitalize-region-keywords
b974df0a
EN
142;; f90-add-imenu-menu
143;; f90-font-lock-1, f90-font-lock-2, f90-font-lock-3, f90-font-lock-4
034a9d40 144
87ee2359 145;; Original author's thanks
034a9d40
RS
146;; Thanks to all the people who have tested the mode. Special thanks to Jens
147;; Bloch Helmers for encouraging me to write this code, for creative
148;; suggestions as well as for the lists of hpf-commands.
149;; Also thanks to the authors of the fortran and pascal modes, on which some
150;; of this code is built.
151
a729409a
GM
152;;; Code:
153
87ee2359 154;; TODO
b1ca7740
GM
155;; 1. Any missing F2003 syntax?
156;; 2. Have "f90-mode" just recognize F90 syntax, then derived modes
5ab33946 157;; "f95-mode", "f2003-mode" for the language revisions.
b1ca7740
GM
158;; 3. Support for align.
159;; Font-locking:
160;; 1. OpenMP, OpenMPI?, preprocessor highlighting.
50e4518b
GM
161;; 2. integer_name = 1
162;; 3. Labels for "else" statements (F2003)?
87ee2359 163
34ba7e3d
GM
164(defvar comment-auto-fill-only-comments)
165(defvar font-lock-keywords)
0ee7f068 166
034a9d40 167;; User options
034a9d40 168
fcad5199 169(defgroup f90 nil
a729409a 170 "Major mode for editing free format Fortran 90,95 code."
8ec3bce0 171 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
d2d15846 172 :group 'languages)
034a9d40 173
fcad5199 174(defgroup f90-indent nil
a729409a 175 "Indentation in free format Fortran."
fcad5199 176 :prefix "f90-"
a729409a 177 :group 'f90)
034a9d40 178
034a9d40 179
fcad5199 180(defcustom f90-do-indent 3
d4654cff 181 "Extra indentation applied to DO blocks."
a729409a 182 :type 'integer
f38184aa 183 :safe 'integerp
fcad5199 184 :group 'f90-indent)
034a9d40 185
fcad5199 186(defcustom f90-if-indent 3
d4654cff 187 "Extra indentation applied to IF, SELECT CASE, WHERE and FORALL blocks."
a729409a 188 :type 'integer
f38184aa 189 :safe 'integerp
fcad5199 190 :group 'f90-indent)
034a9d40 191
fcad5199 192(defcustom f90-type-indent 3
5ab33946 193 "Extra indentation applied to TYPE, ENUM, INTERFACE and BLOCK DATA blocks."
a729409a 194 :type 'integer
f38184aa 195 :safe 'integerp
fcad5199 196 :group 'f90-indent)
034a9d40 197
fcad5199 198(defcustom f90-program-indent 2
d4654cff 199 "Extra indentation applied to PROGRAM, MODULE, SUBROUTINE, FUNCTION blocks."
a729409a 200 :type 'integer
f38184aa 201 :safe 'integerp
fcad5199 202 :group 'f90-indent)
034a9d40 203
5ab33946
GM
204(defcustom f90-associate-indent 2
205 "Extra indentation applied to ASSOCIATE blocks."
206 :type 'integer
f38184aa 207 :safe 'integerp
5ab33946
GM
208 :group 'f90-indent
209 :version "23.1")
210
e93db24a
GM
211(defcustom f90-critical-indent 2
212 "Extra indentation applied to BLOCK, CRITICAL blocks."
213 :type 'integer
214 :safe 'integerp
215 :group 'f90-indent
216 :version "24.1")
217
fcad5199 218(defcustom f90-continuation-indent 5
d4654cff 219 "Extra indentation applied to continuation lines."
a729409a 220 :type 'integer
f38184aa 221 :safe 'integerp
fcad5199 222 :group 'f90-indent)
034a9d40 223
fcad5199 224(defcustom f90-comment-region "!!$"
d4654cff 225 "String inserted by \\[f90-comment-region] at start of each line in region."
a729409a 226 :type 'string
f38184aa 227 :safe 'stringp
fcad5199
RS
228 :group 'f90-indent)
229
230(defcustom f90-indented-comment-re "!"
d4654cff 231 "Regexp matching comments to indent as code."
a729409a 232 :type 'regexp
f38184aa 233 :safe 'stringp
fcad5199
RS
234 :group 'f90-indent)
235
236(defcustom f90-directive-comment-re "!hpf\\$"
d4654cff 237 "Regexp of comment-like directive like \"!HPF\\\\$\", not to be indented."
a729409a 238 :type 'regexp
f38184aa 239 :safe 'stringp
fcad5199
RS
240 :group 'f90-indent)
241
242(defcustom f90-beginning-ampersand t
d4654cff 243 "Non-nil gives automatic insertion of \& at start of continuation line."
a729409a 244 :type 'boolean
f38184aa 245 :safe 'booleanp
fcad5199
RS
246 :group 'f90)
247
248(defcustom f90-smart-end 'blink
d4654cff 249 "Qualification of END statements according to the matching block start.
784d007b
GM
250For example, the END that closes an IF block is changed to END
251IF. If the block has a label, this is added as well. Allowed
252values are 'blink, 'no-blink, and nil. If nil, nothing is done.
253The other two settings have the same effect, but 'blink
254additionally blinks the cursor to the start of the block."
a729409a 255 :type '(choice (const blink) (const no-blink) (const nil))
f38184aa 256 :safe (lambda (value) (memq value '(blink no-blink nil)))
fcad5199 257 :group 'f90)
034a9d40 258
fcad5199 259(defcustom f90-break-delimiters "[-+\\*/><=,% \t]"
d4654cff 260 "Regexp matching delimiter characters at which lines may be broken.
3f150a60
GM
261There are some common two-character tokens where one or more of
262the members matches this regexp. Although Fortran allows breaks
263within lexical tokens (provided the next line has a beginning ampersand),
264the constant `f90-no-break-re' ensures that such tokens are not split."
f38184aa
GM
265 :type 'regexp
266 :safe 'stringp
fcad5199 267 :group 'f90)
034a9d40 268
fcad5199 269(defcustom f90-break-before-delimiters t
d4654cff 270 "Non-nil causes `f90-do-auto-fill' to break lines before delimiters."
f38184aa
GM
271 :type 'boolean
272 :safe 'booleanp
fcad5199 273 :group 'f90)
034a9d40 274
fcad5199 275(defcustom f90-auto-keyword-case nil
d4654cff 276 "Automatic case conversion of keywords.
87ee2359 277The options are 'downcase-word, 'upcase-word, 'capitalize-word and nil."
a729409a
GM
278 :type '(choice (const downcase-word) (const upcase-word)
279 (const capitalize-word) (const nil))
f38184aa
GM
280 :safe (lambda (value) (memq value '(downcase-word
281 capitalize-word upcase-word nil)))
fcad5199
RS
282 :group 'f90)
283
284(defcustom f90-leave-line-no nil
d4654cff 285 "If non-nil, line numbers are not left justified."
a729409a 286 :type 'boolean
f38184aa 287 :safe 'booleanp
fcad5199
RS
288 :group 'f90)
289
0ee7f068
GM
290(defcustom f90-mode-hook nil
291 "Hook run when entering F90 mode."
a729409a 292 :type 'hook
f38184aa
GM
293 ;; Not the only safe options, but some common ones.
294 :safe (lambda (value) (member value '((f90-add-imenu-menu) nil)))
0ee7f068 295 :options '(f90-add-imenu-menu)
a729409a 296 :group 'f90)
0ee7f068
GM
297
298;; User options end here.
1bb3ae5c 299
ee30478d 300(defconst f90-keywords-re
84021009 301 (regexp-opt '("allocatable" "allocate" "assign" "assignment" "backspace"
640f9e26
GM
302 "block" "call" "case" "character" "close" "common" "complex"
303 "contains" "continue" "cycle" "data" "deallocate"
304 "dimension" "do" "double" "else" "elseif" "elsewhere" "end"
305 "enddo" "endfile" "endif" "entry" "equivalence" "exit"
306 "external" "forall" "format" "function" "goto" "if"
307 "implicit" "include" "inquire" "integer" "intent"
308 "interface" "intrinsic" "logical" "module" "namelist" "none"
309 "nullify" "only" "open" "operator" "optional" "parameter"
310 "pause" "pointer" "precision" "print" "private" "procedure"
311 "program" "public" "read" "real" "recursive" "result" "return"
312 "rewind" "save" "select" "sequence" "stop" "subroutine"
313 "target" "then" "type" "use" "where" "while" "write"
314 ;; F95 keywords.
5ab33946
GM
315 "elemental" "pure"
316 ;; F2003
317 "abstract" "associate" "asynchronous" "bind" "class"
318 "deferred" "enum" "enumerator" "extends" "extends_type_of"
b1ca7740
GM
319 "final" "generic" "import" "non_intrinsic" "non_overridable"
320 "nopass" "pass" "protected" "same_type_as" "value" "volatile"
ccf7a5d5 321 ;; F2008.
d4f259f7
GM
322 "contiguous" "submodule" "concurrent" "codimension"
323 "sync all" "sync memory" "critical" "image_index"
5ab33946 324 ) 'words)
9877fcf1 325 "Regexp used by the function `f90-change-keywords'.")
ee30478d
KH
326
327(defconst f90-keywords-level-3-re
84021009
SM
328 (regexp-opt
329 '("allocatable" "allocate" "assign" "assignment" "backspace"
330 "close" "deallocate" "dimension" "endfile" "entry" "equivalence"
331 "external" "inquire" "intent" "intrinsic" "nullify" "only" "open"
5ab33946 332 ;; FIXME operator and assignment should be F2003 procedures?
84021009
SM
333 "operator" "optional" "parameter" "pause" "pointer" "print" "private"
334 "public" "read" "recursive" "result" "rewind" "save" "select"
335 "sequence" "target" "write"
336 ;; F95 keywords.
5ab33946
GM
337 "elemental" "pure"
338 ;; F2003. asynchronous separate.
b1ca7740 339 "abstract" "deferred" "import" "final" "non_intrinsic" "non_overridable"
5ab33946 340 "nopass" "pass" "protected" "value" "volatile"
ccf7a5d5
GM
341 ;; F2008.
342 ;; "concurrent" is only in the sense of "do [,] concurrent", but given
343 ;; the [,] it's simpler to just do every instance (cf "do while").
d4f259f7 344 "contiguous" "concurrent" "codimension" "sync all" "sync memory"
5ab33946 345 ) 'words)
84021009 346 "Keyword-regexp for font-lock level >= 3.")
ee30478d 347
ee30478d 348(defconst f90-procedures-re
84021009 349 (concat "\\<"
69658465
GM
350 (regexp-opt
351 '("abs" "achar" "acos" "adjustl" "adjustr" "aimag" "aint"
352 "all" "allocated" "anint" "any" "asin" "associated"
353 "atan" "atan2" "bit_size" "btest" "ceiling" "char" "cmplx"
354 "conjg" "cos" "cosh" "count" "cshift" "date_and_time" "dble"
355 "digits" "dim" "dot_product" "dprod" "eoshift" "epsilon"
356 "exp" "exponent" "floor" "fraction" "huge" "iachar" "iand"
357 "ibclr" "ibits" "ibset" "ichar" "ieor" "index" "int" "ior"
358 "ishft" "ishftc" "kind" "lbound" "len" "len_trim" "lge" "lgt"
359 "lle" "llt" "log" "log10" "logical" "matmul" "max"
360 "maxexponent" "maxloc" "maxval" "merge" "min" "minexponent"
361 "minloc" "minval" "mod" "modulo" "mvbits" "nearest" "nint"
362 "not" "pack" "precision" "present" "product" "radix"
363 ;; Real is taken out here to avoid highlighting declarations.
364 "random_number" "random_seed" "range" ;; "real"
365 "repeat" "reshape" "rrspacing" "scale" "scan"
366 "selected_int_kind" "selected_real_kind" "set_exponent"
367 "shape" "sign" "sin" "sinh" "size" "spacing" "spread" "sqrt"
368 "sum" "system_clock" "tan" "tanh" "tiny" "transfer"
369 "transpose" "trim" "ubound" "unpack" "verify"
370 ;; F95 intrinsic functions.
5ab33946
GM
371 "null" "cpu_time"
372 ;; F2003.
373 "move_alloc" "command_argument_count" "get_command"
374 "get_command_argument" "get_environment_variable"
375 "selected_char_kind" "wait" "flush" "new_line"
376 "extends" "extends_type_of" "same_type_as" "bind"
377 ;; F2003 ieee_arithmetic intrinsic module.
378 "ieee_support_underflow_control" "ieee_get_underflow_mode"
379 "ieee_set_underflow_mode"
380 ;; F2003 iso_c_binding intrinsic module.
381 "c_loc" "c_funloc" "c_associated" "c_f_pointer"
382 "c_f_procpointer"
89826559
GM
383 ;; F2008.
384 "bge" "bgt" "ble" "blt" "dshiftl" "dshiftr" "leadz" "popcnt"
385 "poppar" "trailz" "maskl" "maskr" "shifta" "shiftl" "shiftr"
386 "merge_bits" "iall" "iany" "iparity" "storage_size"
387 "bessel_j0" "bessel_j1" "bessel_jn"
388 "bessel_y0" "bessel_y1" "bessel_yn"
389 "erf" "erfc" "erfc_scaled" "gamma" "hypot" "log_gamma"
1a5db1f4 390 "norm2" "parity" "findloc" "is_contiguous"
d4f259f7
GM
391 "sync images" "lock" "unlock" "image_index"
392 "lcobound" "ucobound" "num_images" "this_image"
89826559
GM
393 ;; F2008 iso_fortran_env module.
394 "compiler_options" "compiler_version"
395 ;; F2008 iso_c_binding module.
396 "c_sizeof"
5ab33946 397 ) t)
69658465
GM
398 ;; A left parenthesis to avoid highlighting non-procedures.
399 "[ \t]*(")
ee30478d
KH
400 "Regexp whose first part matches F90 intrinsic procedures.")
401
402(defconst f90-operators-re
69658465
GM
403 (concat "\\."
404 (regexp-opt '("and" "eq" "eqv" "false" "ge" "gt" "le" "lt" "ne"
405 "neqv" "not" "or" "true") t)
406 "\\.")
ee30478d
KH
407 "Regexp matching intrinsic operators.")
408
409(defconst f90-hpf-keywords-re
84021009 410 (regexp-opt
ec2f376f 411 ;; Intrinsic procedures.
84021009
SM
412 '("all_prefix" "all_scatter" "all_suffix" "any_prefix"
413 "any_scatter" "any_suffix" "copy_prefix" "copy_scatter"
414 "copy_suffix" "count_prefix" "count_scatter" "count_suffix"
415 "grade_down" "grade_up"
416 "hpf_alignment" "hpf_distribution" "hpf_template" "iall" "iall_prefix"
417 "iall_scatter" "iall_suffix" "iany" "iany_prefix" "iany_scatter"
418 "iany_suffix" "ilen" "iparity" "iparity_prefix"
419 "iparity_scatter" "iparity_suffix" "leadz" "maxval_prefix"
420 "maxval_scatter" "maxval_suffix" "minval_prefix" "minval_scatter"
421 "minval_suffix" "number_of_processors" "parity"
422 "parity_prefix" "parity_scatter" "parity_suffix" "popcnt" "poppar"
423 "processors_shape" "product_prefix" "product_scatter"
424 "product_suffix" "sum_prefix" "sum_scatter" "sum_suffix"
ec2f376f 425 ;; Directives.
84021009 426 "align" "distribute" "dynamic" "independent" "inherit" "processors"
69658465 427 "realign" "redistribute" "template"
ec2f376f 428 ;; Keywords.
84021009 429 "block" "cyclic" "extrinsic" "new" "onto" "pure" "with") 'words)
ee30478d 430 "Regexp for all HPF keywords, procedures and directives.")
034a9d40 431
5ab33946
GM
432(defconst f90-constants-re
433 (regexp-opt '( ;; F2003 iso_fortran_env constants.
434 "iso_fortran_env"
435 "input_unit" "output_unit" "error_unit"
436 "iostat_end" "iostat_eor"
437 "numeric_storage_size" "character_storage_size"
438 "file_storage_size"
439 ;; F2003 iso_c_binding constants.
440 "iso_c_binding"
441 "c_int" "c_short" "c_long" "c_long_long" "c_signed_char"
442 "c_size_t"
443 "c_int8_t" "c_int16_t" "c_int32_t" "c_int64_t"
444 "c_int_least8_t" "c_int_least16_t" "c_int_least32_t"
445 "c_int_least64_t"
446 "c_int_fast8_t" "c_int_fast16_t" "c_int_fast32_t"
447 "c_int_fast64_t"
448 "c_intmax_t" "c_intptr_t"
449 "c_float" "c_double" "c_long_double"
450 "c_float_complex" "c_double_complex" "c_long_double_complex"
451 "c_bool" "c_char"
452 "c_null_char" "c_alert" "c_backspace" "c_form_feed"
453 "c_new_line" "c_carriage_return" "c_horizontal_tab"
454 "c_vertical_tab"
455 "c_ptr" "c_funptr" "c_null_ptr" "c_null_funptr"
b1ca7740
GM
456 "ieee_exceptions"
457 "ieee_arithmetic"
458 "ieee_features"
89826559
GM
459 ;; F2008 iso_fortran_env constants.
460 "character_kinds" "int8" "int16" "int32" "int64"
461 "integer_kinds" "iostat_inquire_internal_unit"
462 "logical_kinds" "real_kinds" "real32" "real64" "real128"
d4f259f7 463 "lock_type" "atomic_int_kind" "atomic_logical_kind"
5ab33946
GM
464 ) 'words)
465 "Regexp for Fortran intrinsic constants.")
034a9d40 466
b1ca7740
GM
467;; cf f90-looking-at-type-like.
468(defun f90-typedef-matcher (limit)
469 "Search for the start/end of the definition of a derived type, up to LIMIT.
470Set the match data so that subexpression 1,2 are the TYPE, and
471type-name parts, respectively."
472 (let (found l)
5fe2902f 473 (while (and (re-search-forward "\\<\\(\\(?:end[ \t]*\\)?type\\)\\>[ \t]*"
b1ca7740
GM
474 limit t)
475 (not (setq found
476 (progn
477 (setq l (match-data))
478 (unless (looking-at "\\(is\\>\\|(\\)")
479 (when (if (looking-at "\\(\\sw+\\)")
480 (goto-char (match-end 0))
481 (re-search-forward
482 "[ \t]*::[ \t]*\\(\\sw+\\)"
483 (line-end-position) t))
484 ;; 0 is wrong, but we don't use it.
485 (set-match-data
486 (append l (list (match-beginning 1)
487 (match-end 1))))
488 t)))))))
489 found))
490
ee30478d 491(defvar f90-font-lock-keywords-1
45d1e4d4 492 (list
ec2f376f 493 ;; Special highlighting of "module procedure".
b1ca7740
GM
494 '("\\<\\(module[ \t]*procedure\\)\\>\\([^()\n]*::\\)?[ \t]*\\([^&!\n]*\\)"
495 (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
eb9f0295 496 ;; Highlight definition of derived type.
b1ca7740
GM
497;;; '("\\<\\(\\(?:end[ \t]*\\)?type\\)\\>\\([^()\n]*::\\)?[ \t]*\\(\\sw+\\)"
498;;; (1 font-lock-keyword-face) (3 font-lock-function-name-face))
499 '(f90-typedef-matcher
500 (1 font-lock-keyword-face) (2 font-lock-function-name-face))
5d8e0d43
GM
501 ;; F2003. Prevent operators being highlighted as functions.
502 '("\\<\\(\\(?:end[ \t]*\\)?interface[ \t]*\\(?:assignment\\|operator\\|\
50e4518b
GM
503read\\|write\\)\\)[ \t]*(" (1 font-lock-keyword-face t))
504 ;; Other functions and declarations. Named interfaces = F2003.
5d8e0d43
GM
505 ;; F2008: end submodule submodule_name.
506 '("\\<\\(\\(?:end[ \t]*\\)?\\(program\\|\\(?:sub\\)?module\\|\
507function\\|associate\\|subroutine\\|interface\\)\\|use\\|call\\)\
508\\>[ \t]*\\(\\sw+\\)?"
84021009 509 (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
5d8e0d43
GM
510 ;; F2008: submodule (parent_name) submodule_name.
511 '("\\<\\(submodule\\)\\>[ \t]*([^)\n]+)[ \t]*\\(\\sw+\\)?"
512 (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
b1ca7740
GM
513 ;; F2003.
514 '("\\<\\(use\\)[ \t]*,[ \t]*\\(\\(?:non_\\)?intrinsic\\)[ \t]*::[ \t]*\
515\\(\\sw+\\)"
516 (1 font-lock-keyword-face) (2 font-lock-keyword-face)
517 (3 font-lock-function-name-face))
50e4518b
GM
518 "\\<\\(\\(end[ \t]*\\)?block[ \t]*data\\|contains\\)\\>"
519 ;; "abstract interface" is F2003.
520 '("\\<abstract[ \t]*interface\\>" (0 font-lock-keyword-face t)))
ee30478d
KH
521 "This does fairly subdued highlighting of comments and function calls.")
522
b1ca7740
GM
523;; NB not explicitly handling this, yet it seems to work.
524;; type(...) function foo()
525(defun f90-typedec-matcher (limit)
526 "Search for the declaration of variables of derived type, up to LIMIT.
527Set the match data so that subexpression 1,2 are the TYPE(...),
528and variable-name parts, respectively."
529 ;; Matcher functions must return nil only when there are no more
530 ;; matches within the search range.
531 (let (found l)
532 (while (and (re-search-forward "\\<\\(type\\|class\\)[ \t]*(" limit t)
533 (not
534 (setq found
535 (condition-case nil
536 (progn
537 ;; Set l after this to just highlight
538 ;; the "type" part.
539 (backward-char 1)
540 ;; Needed for: type( foo(...) ) :: bar
541 (forward-sexp)
542 (setq l (list (match-beginning 0) (point)))
543 (skip-chars-forward " \t")
544 (when
545 (re-search-forward
546 ;; type (foo) bar, qux
547 (if (looking-at "\\sw+")
548 "\\([^&!\n]+\\)"
549 ;; type (foo), stuff :: bar, qux
550 "::[ \t]*\\([^&!\n]+\\)")
551 (line-end-position) t)
552 (set-match-data
553 (append (list (car l) (match-end 1))
554 l (list (match-beginning 1)
555 (match-end 1))))
556 t))
557 (error nil))))))
558 found))
559
ee30478d 560(defvar f90-font-lock-keywords-2
69658465
GM
561 (append
562 f90-font-lock-keywords-1
563 (list
ec2f376f 564 ;; Variable declarations (avoid the real function call).
b1ca7740
GM
565 ;; NB by accident (?), this correctly fontifies the "integer" in:
566 ;; integer () function foo ()
567 ;; because "() function foo ()" matches \\3.
568 ;; The "pure" part does not really belong here, but was added to
569 ;; exploit that hack.
570 ;; The "function foo" bit is correctly fontified by keywords-1.
571 ;; TODO ? actually check for balanced parens in that case.
572 '("^[ \t0-9]*\\(?:pure\\|elemental\\)?[ \t]*\
573\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|\
e2bd4dd4 574enumerator\\|generic\\|procedure\\|logical\\|double[ \t]*precision\\)\
9877fcf1 575\\(.*::\\|[ \t]*(.*)\\)?\\([^&!\n]*\\)"
7aee8047 576 (1 font-lock-type-face t) (4 font-lock-variable-name-face t))
b1ca7740
GM
577 ;; Derived type/class variables.
578 ;; TODO ? If we just highlighted the "type" part, rather than
579 ;; "type(...)", this could be in the previous expression. And this
580 ;; would be consistent with integer( kind=8 ), etc.
581 '(f90-typedec-matcher
582 (1 font-lock-type-face) (2 font-lock-variable-name-face))
5ab33946
GM
583 ;; "real function foo (args)". Must override previous. Note hack
584 ;; to get "args" unhighlighted again. Might not always be right,
585 ;; but probably better than leaving them as variables.
b1ca7740 586 ;; NB not explicitly handling this case:
5ab33946 587 ;; integer( kind=1 ) function foo()
b1ca7740
GM
588 ;; thanks to the happy accident described above.
589 ;; Not anchored, so don't need to worry about "pure" etc.
5ab33946
GM
590 '("\\<\\(\\(real\\|integer\\|c\\(haracter\\|omplex\\)\\|\
591logical\\|double[ \t]*precision\\|\
592\\(?:type\\|class\\)[ \t]*([ \t]*\\sw+[ \t]*)\\)[ \t]*\\)\
593\\(function\\)\\>[ \t]*\\(\\sw+\\)[ \t]*\\(([^&!\n]*)\\)"
594 (1 font-lock-type-face t) (4 font-lock-keyword-face t)
595 (5 font-lock-function-name-face t) (6 'default t))
f43d8ecc
GM
596 ;; enum (F2003; must be followed by ", bind(C)").
597 '("\\<\\(enum\\)[ \t]*," (1 font-lock-keyword-face))
b1ca7740 598 ;; end do, enum (F2003), if, select, where, and forall constructs.
e93db24a
GM
599 ;; block, critical (F2008).
600 ;; Note that "block data" may get somewhat mixed up with F2008 blocks,
601 ;; but since the former is obsolete I'm not going to worry about it.
602 '("\\<\\(end[ \t]*\\(do\\|if\\|enum\\|select\\|forall\\|where\\|\
603block\\|critical\\)\\)\\>\
69658465
GM
604\\([ \t]+\\(\\sw+\\)\\)?"
605 (1 font-lock-keyword-face) (3 font-lock-constant-face nil t))
b1ca7740 606 '("^[ \t0-9]*\\(\\(\\sw+\\)[ \t]*:[ \t]*\\)?\\(\\(if\\|\
5ab33946 607do\\([ \t]*while\\)?\\|select[ \t]*\\(?:case\\|type\\)\\|where\\|\
e93db24a 608forall\\|block\\|critical\\)\\)\\>"
69658465 609 (2 font-lock-constant-face nil t) (3 font-lock-keyword-face))
ec2f376f 610 ;; Implicit declaration.
69658465 611 '("\\<\\(implicit\\)[ \t]*\\(real\\|integer\\|c\\(haracter\\|omplex\\)\
5ab33946
GM
612\\|enumerator\\|procedure\\|\
613logical\\|double[ \t]*precision\\|type[ \t]*(\\sw+)\\|none\\)[ \t]*"
69658465
GM
614 (1 font-lock-keyword-face) (2 font-lock-type-face))
615 '("\\<\\(namelist\\|common\\)[ \t]*\/\\(\\sw+\\)?\/"
616 (1 font-lock-keyword-face) (2 font-lock-constant-face nil t))
617 "\\<else\\([ \t]*if\\|where\\)?\\>"
7aee8047 618 '("\\(&\\)[ \t]*\\(!\\|$\\)" (1 font-lock-keyword-face))
69658465
GM
619 "\\<\\(then\\|continue\\|format\\|include\\|stop\\|return\\)\\>"
620 '("\\<\\(exit\\|cycle\\)[ \t]*\\(\\sw+\\)?\\>"
621 (1 font-lock-keyword-face) (2 font-lock-constant-face nil t))
622 '("\\<\\(case\\)[ \t]*\\(default\\|(\\)" . 1)
5ab33946
GM
623 ;; F2003 "class default".
624 '("\\<\\(class\\)[ \t]*default" . 1)
625 ;; F2003 "type is" in a "select type" block.
626 '("\\<\\(\\(type\\|class\\)[ \t]*is\\)[ \t]*(" (1 font-lock-keyword-face t))
627 '("\\<\\(do\\|go[ \t]*to\\)\\>[ \t]*\\([0-9]+\\)"
69658465 628 (1 font-lock-keyword-face) (2 font-lock-constant-face))
f14ca250 629 ;; Line numbers (lines whose first character after number is letter).
69658465 630 '("^[ \t]*\\([0-9]+\\)[ \t]*[a-z]+" (1 font-lock-constant-face t))))
87ee2359 631 "Highlights declarations, do-loops and other constructs.")
ee30478d
KH
632
633(defvar f90-font-lock-keywords-3
634 (append f90-font-lock-keywords-2
69658465
GM
635 (list
636 f90-keywords-level-3-re
637 f90-operators-re
1ea193a2
GM
638 ;; FIXME why isn't this font-lock-builtin-face, which
639 ;; otherwise we hardly use, as in fortran.el?
69658465 640 (list f90-procedures-re '(1 font-lock-keyword-face keep))
640f9e26 641 "\\<real\\>" ; avoid overwriting real defs
5ab33946 642 ;; As an attribute, but not as an optional argument.
599aeab9 643 '("\\<\\(asynchronous\\)[ \t]*[^=]" . 1)))
ee30478d
KH
644 "Highlights all F90 keywords and intrinsic procedures.")
645
646(defvar f90-font-lock-keywords-4
647 (append f90-font-lock-keywords-3
5ab33946
GM
648 (list (cons f90-constants-re 'font-lock-constant-face)
649 f90-hpf-keywords-re))
650 "Highlights all F90 and HPF keywords and constants.")
ee30478d
KH
651
652(defvar f90-font-lock-keywords
87ee2359 653 f90-font-lock-keywords-2
fb7ada5f 654 "Default expressions to highlight in F90 mode.
0ee7f068 655Can be overridden by the value of `font-lock-maximum-decoration'.")
034a9d40 656
ec2f376f 657
70186f7f
GM
658(defvar f90-mode-syntax-table
659 (let ((table (make-syntax-table)))
660 (modify-syntax-entry ?\! "<" table) ; begin comment
661 (modify-syntax-entry ?\n ">" table) ; end comment
5d16fdd7 662 ;; FIXME: This goes against the convention: it should be "_".
70186f7f
GM
663 (modify-syntax-entry ?_ "w" table) ; underscore in names
664 (modify-syntax-entry ?\' "\"" table) ; string quote
665 (modify-syntax-entry ?\" "\"" table) ; string quote
5d16fdd7
SM
666 ;; FIXME: We used to set ` to word syntax for the benefit of abbrevs, but
667 ;; we do not need it any more. Not sure if it should be "_" or "." now.
668 (modify-syntax-entry ?\` "_" table)
70186f7f
GM
669 (modify-syntax-entry ?\r " " table) ; return is whitespace
670 (modify-syntax-entry ?+ "." table) ; punctuation
671 (modify-syntax-entry ?- "." table)
672 (modify-syntax-entry ?= "." table)
673 (modify-syntax-entry ?* "." table)
674 (modify-syntax-entry ?/ "." table)
a8955be7 675 (modify-syntax-entry ?% "." table) ; bug#8820
fffa137c 676 ;; I think that the f95 standard leaves the behavior of \
784d007b
GM
677 ;; unspecified, but that f2k will require it to be non-special.
678 ;; Use `f90-backslash-not-special' to change.
70186f7f
GM
679 (modify-syntax-entry ?\\ "\\" table) ; escape chars
680 table)
681 "Syntax table used in F90 mode.")
682
683(defvar f90-mode-map
684 (let ((map (make-sparse-keymap)))
685 (define-key map "`" 'f90-abbrev-start)
686 (define-key map "\C-c;" 'f90-comment-region)
687 (define-key map "\C-\M-a" 'f90-beginning-of-subprogram)
688 (define-key map "\C-\M-e" 'f90-end-of-subprogram)
689 (define-key map "\C-\M-h" 'f90-mark-subprogram)
6f1d50da
GM
690 (define-key map "\C-\M-n" 'f90-end-of-block)
691 (define-key map "\C-\M-p" 'f90-beginning-of-block)
70186f7f
GM
692 (define-key map "\C-\M-q" 'f90-indent-subprogram)
693 (define-key map "\C-j" 'f90-indent-new-line) ; LFD equals C-j
83596348 694;;; (define-key map "\r" 'newline)
70186f7f
GM
695 (define-key map "\C-c\r" 'f90-break-line)
696;;; (define-key map [M-return] 'f90-break-line)
76bccf35
GM
697 (define-key map "\C-c\C-a" 'f90-previous-block)
698 (define-key map "\C-c\C-e" 'f90-next-block)
70186f7f
GM
699 (define-key map "\C-c\C-d" 'f90-join-lines)
700 (define-key map "\C-c\C-f" 'f90-fill-region)
701 (define-key map "\C-c\C-p" 'f90-previous-statement)
702 (define-key map "\C-c\C-n" 'f90-next-statement)
8a79905d 703 (define-key map "\C-c]" 'f90-insert-end)
70186f7f 704 (define-key map "\C-c\C-w" 'f90-insert-end)
83596348
GM
705 ;; Standard tab binding will call this, and also handle regions.
706;;; (define-key map "\t" 'f90-indent-line)
70186f7f
GM
707 (define-key map "," 'f90-electric-insert)
708 (define-key map "+" 'f90-electric-insert)
709 (define-key map "-" 'f90-electric-insert)
710 (define-key map "*" 'f90-electric-insert)
711 (define-key map "/" 'f90-electric-insert)
a729409a
GM
712
713 (easy-menu-define f90-menu map "Menu for F90 mode."
714 `("F90"
715 ("Customization"
716 ,(custom-menu-create 'f90)
68fcc3ec
GM
717 ;; FIXME useless?
718 ["Set" Custom-set :active t
719 :help "Set current value of all edited settings in the buffer"]
720 ["Save" Custom-save :active t
721 :help "Set and save all edited settings"]
722 ["Reset to Current" Custom-reset-current :active t
723 :help "Reset all edited settings to current"]
724 ["Reset to Saved" Custom-reset-saved :active t
725 :help "Reset all edited or set settings to saved"]
726 ["Reset to Standard Settings" Custom-reset-standard :active t
e4769531 727 :help "Erase all customizations in buffer"]
a729409a
GM
728 )
729 "--"
68fcc3ec
GM
730 ["Indent Subprogram" f90-indent-subprogram t]
731 ["Mark Subprogram" f90-mark-subprogram :active t :help
732 "Mark the end of the current subprogram, move point to the start"]
733 ["Beginning of Subprogram" f90-beginning-of-subprogram :active t
734 :help "Move point to the start of the current subprogram"]
735 ["End of Subprogram" f90-end-of-subprogram :active t
736 :help "Move point to the end of the current subprogram"]
a729409a 737 "--"
68fcc3ec
GM
738 ["(Un)Comment Region" f90-comment-region :active mark-active
739 :help "Comment or uncomment the region"]
740 ["Indent Region" f90-indent-region :active mark-active]
741 ["Fill Region" f90-fill-region :active mark-active
742 :help "Fill long lines in the region"]
a729409a 743 "--"
68fcc3ec
GM
744 ["Break Line at Point" f90-break-line :active t
745 :help "Break the current line at point"]
746 ["Join with Previous Line" f90-join-lines :active t
747 :help "Join the current line to the previous one"]
748 ["Insert Block End" f90-insert-end :active t
749 :help "Insert an end statement for the current code block"]
a729409a
GM
750 "--"
751 ("Highlighting"
68fcc3ec 752 :help "Fontify this buffer to varying degrees"
a729409a 753 ["Toggle font-lock-mode" font-lock-mode :selected font-lock-mode
68fcc3ec 754 :style toggle :help "Fontify text in this buffer"]
a729409a
GM
755 "--"
756 ["Light highlighting (level 1)" f90-font-lock-1 t]
757 ["Moderate highlighting (level 2)" f90-font-lock-2 t]
758 ["Heavy highlighting (level 3)" f90-font-lock-3 t]
759 ["Maximum highlighting (level 4)" f90-font-lock-4 t]
760 )
761 ("Change Keyword Case"
68fcc3ec 762 :help "Change the case of keywords in the buffer or region"
a729409a
GM
763 ["Upcase Keywords (buffer)" f90-upcase-keywords t]
764 ["Capitalize Keywords (buffer)" f90-capitalize-keywords t]
765 ["Downcase Keywords (buffer)" f90-downcase-keywords t]
766 "--"
767 ["Upcase Keywords (region)" f90-upcase-region-keywords
768 mark-active]
769 ["Capitalize Keywords (region)" f90-capitalize-region-keywords
770 mark-active]
771 ["Downcase Keywords (region)" f90-downcase-region-keywords
772 mark-active]
773 )
774 "--"
68fcc3ec
GM
775 ["Toggle Auto Fill" auto-fill-mode :selected auto-fill-function
776 :style toggle
777 :help "Automatically fill text while typing in this buffer"]
778 ["Toggle Abbrev Mode" abbrev-mode :selected abbrev-mode
779 :style toggle :help "Expand abbreviations while typing in this buffer"]
780 ["Add Imenu Menu" f90-add-imenu-menu
a729409a 781 :active (not (lookup-key (current-local-map) [menu-bar index]))
68fcc3ec
GM
782 :included (fboundp 'imenu-add-to-menubar)
783 :help "Add an index menu to the menu-bar"
784 ]))
70186f7f 785 map)
034a9d40 786 "Keymap used in F90 mode.")
ee30478d 787
b974df0a 788
599aeab9
GM
789(defun f90-font-lock-n (n)
790 "Set `font-lock-keywords' to F90 level N keywords."
791 (font-lock-mode 1)
792 (setq font-lock-keywords
793 (symbol-value (intern-soft (format "f90-font-lock-keywords-%d" n))))
794 (font-lock-fontify-buffer))
795
1a341882
GM
796(defun f90-font-lock-1 ()
797 "Set `font-lock-keywords' to `f90-font-lock-keywords-1'."
798 (interactive)
599aeab9 799 (f90-font-lock-n 1))
1a341882
GM
800
801(defun f90-font-lock-2 ()
802 "Set `font-lock-keywords' to `f90-font-lock-keywords-2'."
803 (interactive)
599aeab9 804 (f90-font-lock-n 2))
1a341882
GM
805
806(defun f90-font-lock-3 ()
807 "Set `font-lock-keywords' to `f90-font-lock-keywords-3'."
808 (interactive)
599aeab9 809 (f90-font-lock-n 3))
1a341882
GM
810
811(defun f90-font-lock-4 ()
812 "Set `font-lock-keywords' to `f90-font-lock-keywords-4'."
813 (interactive)
599aeab9 814 (f90-font-lock-n 4))
1a341882 815\f
ee30478d 816;; Regexps for finding program structures.
69658465 817(defconst f90-blocks-re
ec2f376f
GM
818 (concat "\\(block[ \t]*data\\|"
819 (regexp-opt '("do" "if" "interface" "function" "module" "program"
5ab33946
GM
820 "select" "subroutine" "type" "where" "forall"
821 ;; F2003.
5d8e0d43
GM
822 "enum" "associate"
823 ;; F2008.
e93db24a 824 "submodule" "block" "critical"))
ec2f376f
GM
825 "\\)\\>")
826 "Regexp potentially indicating a \"block\" of F90 code.")
827
69658465 828(defconst f90-program-block-re
5d8e0d43 829 (regexp-opt '("program" "module" "subroutine" "function" "submodule") 'paren)
ec2f376f
GM
830 "Regexp used to locate the start/end of a \"subprogram\".")
831
5ab33946 832;; "class is" is F2003.
69658465 833(defconst f90-else-like-re
5ab33946
GM
834 "\\(else\\([ \t]*if\\|where\\)?\\|case[ \t]*\\(default\\|(\\)\\|\
835\\(class\\|type\\)[ \t]*is[ \t]*(\\|class[ \t]*default\\)"
836 "Regexp matching an ELSE IF, ELSEWHERE, CASE, CLASS/TYPE IS statement.")
ec2f376f 837
69658465 838(defconst f90-end-if-re
ec2f376f
GM
839 (concat "end[ \t]*"
840 (regexp-opt '("if" "select" "where" "forall") 'paren)
841 "\\>")
842 "Regexp matching the end of an IF, SELECT, WHERE, FORALL block.")
843
69658465 844(defconst f90-end-type-re
5ab33946
GM
845 "end[ \t]*\\(type\\|enum\\|interface\\|block[ \t]*data\\)\\>"
846 "Regexp matching the end of a TYPE, ENUM, INTERFACE, BLOCK DATA section.")
847
848(defconst f90-end-associate-re
849 "end[ \t]*associate\\>"
850 "Regexp matching the end of an ASSOCIATE block.")
ec2f376f 851
5ab33946
GM
852;; This is for a TYPE block, not a variable of derived TYPE.
853;; Hence no need to add CLASS for F2003.
ee30478d 854(defconst f90-type-def-re
5ab33946
GM
855 ;; type word
856 ;; type :: word
857 ;; type, stuff :: word
d1f21341 858 ;; type, bind(c) :: word
5ab33946 859 ;; NOT "type ("
d1f21341
GM
860 "\\<\\(type\\)\\>\\(?:\\(?:[^()\n]*\\|\
861.*,[ \t]*bind[ \t]*([ \t]*c[ \t]*)[ \t]*\\)::\\)?[ \t]*\\(\\sw+\\)"
e7272ece 862 "Regexp matching the definition of a derived type.")
ec2f376f 863
5ab33946
GM
864(defconst f90-typeis-re
865 "\\<\\(class\\|type\\)[ \t]*is[ \t]*("
866 "Regexp matching a CLASS/TYPE IS statement.")
867
ec2f376f 868(defconst f90-no-break-re
b0d5b05b 869 (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=" "(/" "/)") 'paren)
3f150a60
GM
870 "Regexp specifying two-character tokens not to split when breaking lines.
871Each token has one or more of the characters from `f90-break-delimiters'.
872Note that if only one of the characters is from that variable,
873then the presence of the token here allows a line-break before or
874after the other character, where a break would not normally be
875allowed. This minor issue currently only affects \"(/\" and \"/)\".")
ec2f376f
GM
876
877(defvar f90-cache-position nil
878 "Temporary position used to speed up region operations.")
034a9d40 879(make-variable-buffer-local 'f90-cache-position)
ec2f376f 880
b974df0a 881\f
799dee7a
GM
882;; Hideshow support.
883(defconst f90-end-block-re
fcca5273 884 (concat "^[ \t0-9]*\\<end[ \t]*"
799dee7a 885 (regexp-opt '("do" "if" "forall" "function" "interface"
fcca5273 886 "module" "program" "select" "subroutine"
e93db24a
GM
887 "type" "where" "enum" "associate" "submodule"
888 "block" "critical") t)
5ab33946 889 "\\>")
fcca5273 890 "Regexp matching the end of an F90 \"block\", from the line start.
799dee7a
GM
891Used in the F90 entry in `hs-special-modes-alist'.")
892
893;; Ignore the fact that FUNCTION, SUBROUTINE, WHERE, FORALL have a
fcca5273 894;; following "(". DO, CASE, IF can have labels.
799dee7a
GM
895(defconst f90-start-block-re
896 (concat
897 "^[ \t0-9]*" ; statement number
898 "\\(\\("
899 "\\(\\sw+[ \t]*:[ \t]*\\)?" ; structure label
5ab33946 900 "\\(do\\|select[ \t]*\\(case\\|type\\)\\|"
fcca5273
GM
901 ;; See comments in fortran-start-block-re for the problems of IF.
902 "if[ \t]*(\\(.*\\|"
903 ".*\n\\([^if]*\\([^i].\\|.[^f]\\|.\\>\\)\\)\\)\\<then\\|"
799dee7a
GM
904 ;; Distinguish WHERE block from isolated WHERE.
905 "\\(where\\|forall\\)[ \t]*(.*)[ \t]*\\(!\\|$\\)\\)\\)"
906 "\\|"
5ab33946
GM
907 ;; Avoid F2003 "type is" in "select type",
908 ;; and also variables of derived type "type (foo)".
909 ;; "type, foo" must be a block (?).
b1ca7740
GM
910 "type[ \t,]\\("
911 "[^i(!\n\"\& \t]\\|" ; not-i(
912 "i[^s!\n\"\& \t]\\|" ; i not-s
913 "is\\sw\\)\\|"
5d8e0d43
GM
914 ;; "abstract interface" is F2003; "submodule" is F2008.
915 "program\\|\\(?:abstract[ \t]*\\)?interface\\|\\(?:sub\\)?module\\|"
5ab33946 916 ;; "enum", but not "enumerator".
e93db24a 917 "function\\|subroutine\\|enum[^e]\\|associate\\|block\\|critical"
799dee7a
GM
918 "\\)"
919 "[ \t]*")
fcca5273 920 "Regexp matching the start of an F90 \"block\", from the line start.
799dee7a
GM
921A simple regexp cannot do this in fully correct fashion, so this
922tries to strike a compromise between complexity and flexibility.
923Used in the F90 entry in `hs-special-modes-alist'.")
924
925;; hs-special-modes-alist is autoloaded.
926(add-to-list 'hs-special-modes-alist
927 `(f90-mode ,f90-start-block-re ,f90-end-block-re
928 "!" f90-end-of-block nil))
929
930\f
ec2f376f 931;; Imenu support.
b1ca7740
GM
932;; FIXME trivial to extend this to enum. Worth it?
933(defun f90-imenu-type-matcher ()
934 "Search backward for the start of a derived type.
935Set subexpression 1 in the match-data to the name of the type."
5d16fdd7 936 (let (found)
b1ca7740
GM
937 (while (and (re-search-backward "^[ \t0-9]*type[ \t]*" nil t)
938 (not (setq found
939 (save-excursion
940 (goto-char (match-end 0))
941 (unless (looking-at "\\(is\\>\\|(\\)")
942 (or (looking-at "\\(\\sw+\\)")
943 (re-search-forward
944 "[ \t]*::[ \t]*\\(\\sw+\\)"
945 (line-end-position) t))))))))
946 found))
947
ee30478d 948(defvar f90-imenu-generic-expression
b974df0a 949 (let ((good-char "[^!\"\&\n \t]") (not-e "[^e!\n\"\& \t]")
b1ca7740 950 (not-n "[^n!\n\"\& \t]") (not-d "[^d!\n\"\& \t]")
5d16fdd7
SM
951 ;; (not-ib "[^i(!\n\"\& \t]") (not-s "[^s!\n\"\& \t]")
952 )
b974df0a
EN
953 (list
954 '(nil "^[ \t0-9]*program[ \t]+\\(\\sw+\\)" 1)
5d8e0d43
GM
955 '("Submodules" "^[ \t0-9]*submodule[ \t]*([^)\n]+)[ \t]*\
956\\(\\sw+\\)[ \t]*\\(!\\|$\\)" 1)
b974df0a 957 '("Modules" "^[ \t0-9]*module[ \t]+\\(\\sw+\\)[ \t]*\\(!\\|$\\)" 1)
b1ca7740
GM
958 (list "Types" 'f90-imenu-type-matcher 1)
959 ;; Does not handle: "type[, stuff] :: foo".
960;;; (format "^[ \t0-9]*type[ \t]+\\(\\(%s\\|i%s\\|is\\sw\\)\\sw*\\)"
961;;; not-ib not-s)
962;;; 1)
963 ;; Can't get the subexpression numbers to match in the two branches.
964;;; (format "^[ \t0-9]*type\\([ \t]*,.*\\(::\\)[ \t]*\\(\\sw+\\)\\|[ \t]+\\(\\(%s\\|i%s\\|is\\sw\\)\\sw*\\)\\)" not-ib not-s)
965;;; 3)
b974df0a 966 (list
69658465 967 "Procedures"
b974df0a
EN
968 (concat
969 "^[ \t0-9]*"
970 "\\("
ec2f376f
GM
971 ;; At least three non-space characters before function/subroutine.
972 ;; Check that the last three non-space characters do not spell E N D.
b974df0a
EN
973 "[^!\"\&\n]*\\("
974 not-e good-char good-char "\\|"
975 good-char not-n good-char "\\|"
976 good-char good-char not-d "\\)"
977 "\\|"
ec2f376f 978 ;; Less than three non-space characters before function/subroutine.
b974df0a
EN
979 good-char "?" good-char "?"
980 "\\)"
981 "[ \t]*\\(function\\|subroutine\\)[ \t]+\\(\\sw+\\)")
69658465 982 4)))
a729409a 983 "Value for `imenu-generic-expression' in F90 mode.")
ee30478d 984
b974df0a 985(defun f90-add-imenu-menu ()
b974df0a 986 "Add an imenu menu to the menubar."
87ee2359 987 (interactive)
34ba7e3d 988 (if (lookup-key (current-local-map) [menu-bar index])
5c2a80ad
GM
989 (message "%s" "F90-imenu already exists.")
990 (imenu-add-to-menubar "F90-imenu")
901e8d1d 991 (redraw-frame (selected-frame))))
b974df0a 992
034a9d40 993\f
ec2f376f 994;; Abbrevs have generally two letters, except standard types `c, `i, `r, `t.
5d16fdd7
SM
995(define-abbrev-table 'f90-mode-abbrev-table
996 (mapcar (lambda (e) (list (car e) (cdr e) nil :system t))
997 '(("`al" . "allocate" )
998 ("`ab" . "allocatable" )
999 ("`ai" . "abstract interface")
1000 ("`as" . "assignment" )
1001 ("`asy" . "asynchronous" )
1002 ("`ba" . "backspace" )
1003 ("`bd" . "block data" )
e93db24a 1004 ("`bl" . "block" )
5d16fdd7
SM
1005 ("`c" . "character" )
1006 ("`cl" . "close" )
1007 ("`cm" . "common" )
1008 ("`cx" . "complex" )
1009 ("`cn" . "contains" )
e93db24a 1010 ("`cr" . "critical" )
5d16fdd7
SM
1011 ("`cy" . "cycle" )
1012 ("`de" . "deallocate" )
1013 ("`df" . "define" )
1014 ("`di" . "dimension" )
1015 ("`dp" . "double precision")
1016 ("`dw" . "do while" )
1017 ("`el" . "else" )
1018 ("`eli" . "else if" )
1019 ("`elw" . "elsewhere" )
1020 ("`em" . "elemental" )
1021 ("`e" . "enumerator" )
1022 ("`eq" . "equivalence" )
1023 ("`ex" . "external" )
1024 ("`ey" . "entry" )
1025 ("`fl" . "forall" )
1026 ("`fo" . "format" )
1027 ("`fu" . "function" )
1028 ("`fa" . ".false." )
1029 ("`im" . "implicit none")
1030 ("`in" . "include" )
1031 ("`i" . "integer" )
1032 ("`it" . "intent" )
1033 ("`if" . "interface" )
1034 ("`lo" . "logical" )
1035 ("`mo" . "module" )
1036 ("`na" . "namelist" )
1037 ("`nu" . "nullify" )
1038 ("`op" . "optional" )
1039 ("`pa" . "parameter" )
1040 ("`po" . "pointer" )
1041 ("`pr" . "print" )
1042 ("`pi" . "private" )
1043 ("`pm" . "program" )
1044 ("`pr" . "protected" )
1045 ("`pu" . "public" )
1046 ("`r" . "real" )
1047 ("`rc" . "recursive" )
1048 ("`rt" . "return" )
1049 ("`rw" . "rewind" )
1050 ("`se" . "select" )
1051 ("`sq" . "sequence" )
1052 ("`su" . "subroutine" )
1053 ("`ta" . "target" )
1054 ("`tr" . ".true." )
1055 ("`t" . "type" )
1056 ("`vo" . "volatile" )
1057 ("`wh" . "where" )
1058 ("`wr" . "write" )))
1059 "Abbrev table for F90 mode."
1060 ;; Accept ` as the first char of an abbrev. Also allow _ in abbrevs.
1061 :regexp "\\(?:[^[:word:]_`]\\|^\\)\\(`?[[:word:]_]+\\)[^[:word:]_]*")
0761b294 1062\f
034a9d40 1063;;;###autoload
e75c1e7d 1064(define-derived-mode f90-mode prog-mode "F90"
87ee2359 1065 "Major mode for editing Fortran 90,95 code in free format.
a729409a 1066For fixed format code, use `fortran-mode'.
034a9d40 1067
a729409a 1068\\[f90-indent-line] indents the current line.
ec2f376f 1069\\[f90-indent-new-line] indents current line and creates a new\
034a9d40 1070 indented line.
87ee2359 1071\\[f90-indent-subprogram] indents the current subprogram.
034a9d40
RS
1072
1073Type `? or `\\[help-command] to display a list of built-in\
1074 abbrevs for F90 keywords.
1075
1076Key definitions:
1077\\{f90-mode-map}
1078
1079Variables controlling indentation style and extra features:
1080
ec2f376f
GM
1081`f90-do-indent'
1082 Extra indentation within do blocks (default 3).
1083`f90-if-indent'
5ab33946 1084 Extra indentation within if/select/where/forall blocks (default 3).
ec2f376f 1085`f90-type-indent'
5ab33946 1086 Extra indentation within type/enum/interface/block-data blocks (default 3).
ec2f376f
GM
1087`f90-program-indent'
1088 Extra indentation within program/module/subroutine/function blocks
1089 (default 2).
e93db24a
GM
1090`f90-associate-indent'
1091 Extra indentation within associate blocks (default 2).
1092`f90-critical-indent'
1093 Extra indentation within critical/block blocks (default 2).
ec2f376f
GM
1094`f90-continuation-indent'
1095 Extra indentation applied to continuation lines (default 5).
1096`f90-comment-region'
e3f5ce56
GM
1097 String inserted by function \\[f90-comment-region] at start of each
1098 line in region (default \"!!!$\").
ec2f376f
GM
1099`f90-indented-comment-re'
1100 Regexp determining the type of comment to be intended like code
1101 (default \"!\").
1102`f90-directive-comment-re'
1103 Regexp of comment-like directive like \"!HPF\\\\$\", not to be indented
1104 (default \"!hpf\\\\$\").
1105`f90-break-delimiters'
1106 Regexp holding list of delimiters at which lines may be broken
1107 (default \"[-+*/><=,% \\t]\").
1108`f90-break-before-delimiters'
1109 Non-nil causes `f90-do-auto-fill' to break lines before delimiters
1110 (default t).
1111`f90-beginning-ampersand'
1112 Automatic insertion of \& at beginning of continuation lines (default t).
1113`f90-smart-end'
1114 From an END statement, check and fill the end using matching block start.
1115 Allowed values are 'blink, 'no-blink, and nil, which determine
1116 whether to blink the matching beginning (default 'blink).
1117`f90-auto-keyword-case'
1118 Automatic change of case of keywords (default nil).
1119 The possibilities are 'downcase-word, 'upcase-word, 'capitalize-word.
1120`f90-leave-line-no'
1121 Do not left-justify line numbers (default nil).
034a9d40
RS
1122
1123Turning on F90 mode calls the value of the variable `f90-mode-hook'
1124with no args, if that value is non-nil."
e75c1e7d 1125 :group 'f90
e75c1e7d 1126 :abbrev-table f90-mode-abbrev-table
e3f5ce56
GM
1127 (set (make-local-variable 'indent-line-function) 'f90-indent-line)
1128 (set (make-local-variable 'indent-region-function) 'f90-indent-region)
e3f5ce56
GM
1129 (set (make-local-variable 'comment-start) "!")
1130 (set (make-local-variable 'comment-start-skip) "!+ *")
1131 (set (make-local-variable 'comment-indent-function) 'f90-comment-indent)
1132 (set (make-local-variable 'abbrev-all-caps) t)
1133 (set (make-local-variable 'normal-auto-fill-function) 'f90-do-auto-fill)
70186f7f 1134 (setq indent-tabs-mode nil) ; auto buffer local
e3f5ce56
GM
1135 (set (make-local-variable 'font-lock-defaults)
1136 '((f90-font-lock-keywords f90-font-lock-keywords-1
1137 f90-font-lock-keywords-2
1138 f90-font-lock-keywords-3
1139 f90-font-lock-keywords-4)
1140 nil t))
45d1e4d4 1141 (set (make-local-variable 'imenu-case-fold-search) t)
e3f5ce56 1142 (set (make-local-variable 'imenu-generic-expression)
a729409a
GM
1143 f90-imenu-generic-expression)
1144 (set (make-local-variable 'beginning-of-defun-function)
1145 'f90-beginning-of-subprogram)
1146 (set (make-local-variable 'end-of-defun-function) 'f90-end-of-subprogram)
d2d15846 1147 (set (make-local-variable 'add-log-current-defun-function)
e75c1e7d 1148 #'f90-current-defun))
ec2f376f 1149
034a9d40 1150\f
ec2f376f 1151;; Inline-functions.
034a9d40 1152(defsubst f90-in-string ()
d14e6bbe 1153 "Return non-nil if point is inside a string.
ec2f376f 1154Checks from `point-min', or `f90-cache-position', if that is non-nil
d14e6bbe 1155and lies before point."
034a9d40 1156 (let ((beg-pnt
640f9e26
GM
1157 (if (and f90-cache-position (> (point) f90-cache-position))
1158 f90-cache-position
1159 (point-min))))
034a9d40 1160 (nth 3 (parse-partial-sexp beg-pnt (point)))))
69658465 1161
034a9d40 1162(defsubst f90-in-comment ()
d14e6bbe 1163 "Return non-nil if point is inside a comment.
ec2f376f 1164Checks from `point-min', or `f90-cache-position', if that is non-nil
d14e6bbe 1165and lies before point."
034a9d40 1166 (let ((beg-pnt
640f9e26
GM
1167 (if (and f90-cache-position (> (point) f90-cache-position))
1168 f90-cache-position
1169 (point-min))))
034a9d40
RS
1170 (nth 4 (parse-partial-sexp beg-pnt (point)))))
1171
1172(defsubst f90-line-continued ()
d14e6bbe
GM
1173 "Return t if the current line is a continued one.
1174This includes comment lines embedded in continued lines, but
1175not the last line of a continued statement."
034a9d40 1176 (save-excursion
6734e165
GM
1177 (beginning-of-line)
1178 (while (and (looking-at "[ \t]*\\(!\\|$\\)") (zerop (forward-line -1))))
e3f5ce56
GM
1179 (end-of-line)
1180 (while (f90-in-comment)
1181 (search-backward "!" (line-beginning-position))
1182 (skip-chars-backward "!"))
1183 (skip-chars-backward " \t")
1184 (= (preceding-char) ?&)))
034a9d40 1185
748dd5a8
GM
1186;; GM this is not right, eg a continuation line starting with a number.
1187;; Need f90-code-start-position function.
1188;; And yet, things seems to work with this...
7aee8047
GM
1189;; cf f90-indent-line
1190;; (beginning-of-line) ; digits after & \n are not line-nos
1191;; (if (not (save-excursion (and (f90-previous-statement)
1192;; (f90-line-continued))))
1193;; (f90-indent-line-no)
034a9d40
RS
1194(defsubst f90-current-indentation ()
1195 "Return indentation of current line.
1196Line-numbers are considered whitespace characters."
e3f5ce56 1197 (save-excursion (beginning-of-line) (skip-chars-forward " \t0-9")))
034a9d40
RS
1198
1199(defsubst f90-indent-to (col &optional no-line-number)
1200 "Indent current line to column COL.
d14e6bbe
GM
1201If optional argument NO-LINE-NUMBER is nil, jump over a possible
1202line-number before indenting."
034a9d40 1203 (beginning-of-line)
748dd5a8 1204 (or no-line-number
034a9d40
RS
1205 (skip-chars-forward " \t0-9"))
1206 (delete-horizontal-space)
748dd5a8
GM
1207 ;; Leave >= 1 space after line number.
1208 (indent-to col (if (zerop (current-column)) 0 1)))
034a9d40 1209
034a9d40 1210(defsubst f90-get-present-comment-type ()
d14e6bbe 1211 "If point lies within a comment, return the string starting the comment.
718d0706
GM
1212For example, \"!\" or \"!!\", followed by the appropriate amount of
1213whitespace, if any."
1214 ;; Include the whitespace for consistent auto-filling of comment blocks.
034a9d40 1215 (save-excursion
e3f5ce56
GM
1216 (when (f90-in-comment)
1217 (beginning-of-line)
718d0706 1218 (re-search-forward "!+[ \t]*" (line-end-position))
e3f5ce56 1219 (while (f90-in-string)
718d0706
GM
1220 (re-search-forward "!+[ \t]*" (line-end-position)))
1221 (match-string-no-properties 0))))
034a9d40
RS
1222
1223(defsubst f90-equal-symbols (a b)
ec2f376f 1224 "Compare strings A and B neglecting case and allowing for nil value."
f14ca250
GM
1225 (equal (if a (downcase a) nil)
1226 (if b (downcase b) nil)))
034a9d40 1227
034a9d40 1228(defsubst f90-looking-at-do ()
d14e6bbe
GM
1229 "Return (\"do\" NAME) if a do statement starts after point.
1230NAME is nil if the statement has no label."
f14ca250 1231 (if (looking-at "\\(\\(\\sw+\\)[ \t]*:\\)?[ \t]*\\(do\\)\\>")
0db701f0 1232 (list (match-string 3) (match-string 2))))
ee30478d
KH
1233
1234(defsubst f90-looking-at-select-case ()
5ab33946 1235 "Return (\"select\" NAME) if a select statement starts after point.
d14e6bbe 1236NAME is nil if the statement has no label."
f14ca250 1237 (if (looking-at "\\(\\(\\sw+\\)[ \t]*:\\)?[ \t]*\
5ab33946 1238\\(select\\)[ \t]*\\(case\\|type\\)[ \t]*(")
748dd5a8 1239 (list (match-string 3) (match-string 2))))
034a9d40
RS
1240
1241(defsubst f90-looking-at-if-then ()
d14e6bbe
GM
1242 "Return (\"if\" NAME) if an if () then statement starts after point.
1243NAME is nil if the statement has no label."
034a9d40 1244 (save-excursion
f14ca250
GM
1245 (when (looking-at "\\(\\(\\sw+\\)[ \t]*:\\)?[ \t]*\\(if\\)\\>")
1246 (let ((struct (match-string 3))
748dd5a8 1247 (label (match-string 2))
f14ca250
GM
1248 (pos (scan-lists (point) 1 0)))
1249 (and pos (goto-char pos))
5c2a80ad
GM
1250 (skip-chars-forward " \t")
1251 (if (or (looking-at "then\\>")
1252 (when (f90-line-continued)
1253 (f90-next-statement)
1254 (skip-chars-forward " \t0-9&")
1255 (looking-at "then\\>")))
1256 (list struct label))))))
034a9d40 1257
5ab33946
GM
1258;; FIXME label?
1259(defsubst f90-looking-at-associate ()
1260 "Return (\"associate\") if an associate block starts after point."
1261 (if (looking-at "\\<\\(associate\\)[ \t]*(")
1262 (list (match-string 1))))
1263
e93db24a 1264(defsubst f90-looking-at-critical ()
ee584d02 1265 "Return (KIND NAME) if a critical or block block starts after point."
e93db24a
GM
1266 (if (looking-at "\\(\\(\\sw+\\)[ \t]*:\\)?[ \t]*\\(critical\\|block\\)\\>")
1267 (let ((struct (match-string 3))
1268 (label (match-string 2)))
1269 (if (or (not (string-equal "block" struct))
1270 (save-excursion
1271 (skip-chars-forward " \t")
1272 (not (looking-at "data\\>"))))
1273 (list struct label)))))
1274
1275(defsubst f90-looking-at-end-critical ()
1276 "Return non-nil if a critical or block block ends after point."
1277 (if (looking-at "end[ \t]*\\(critical\\|block\\)\\>")
1278 (or (not (string-equal "block" (match-string 1)))
1279 (save-excursion
1280 (skip-chars-forward " \t")
1281 (not (looking-at "data\\>"))))))
1282
b32a3d99 1283(defsubst f90-looking-at-where-or-forall ()
d14e6bbe
GM
1284 "Return (KIND NAME) if a where or forall block starts after point.
1285NAME is nil if the statement has no label."
f14ca250
GM
1286 (save-excursion
1287 (when (looking-at "\\(\\(\\sw+\\)[ \t]*:\\)?[ \t]*\
1288\\(where\\|forall\\)\\>")
1289 (let ((struct (match-string 3))
748dd5a8 1290 (label (match-string 2))
f14ca250
GM
1291 (pos (scan-lists (point) 1 0)))
1292 (and pos (goto-char pos))
1293 (skip-chars-forward " \t")
1294 (if (looking-at "\\(!\\|$\\)") (list struct label))))))
034a9d40
RS
1295
1296(defsubst f90-looking-at-type-like ()
5ab33946 1297 "Return (KIND NAME) if a type/enum/interface/block-data starts after point.
7cf3f3d6 1298NAME is non-nil only for type and certain interfaces."
69658465 1299 (cond
5ab33946 1300 ((save-excursion
5fe2902f 1301 (and (looking-at "\\<type\\>[ \t]*")
5ab33946
GM
1302 (goto-char (match-end 0))
1303 (not (looking-at "\\(is\\>\\|(\\)"))
1304 (or (looking-at "\\(\\sw+\\)")
1305 (re-search-forward "[ \t]*::[ \t]*\\(\\sw+\\)"
1306 (line-end-position) t))))
1307 (list "type" (match-string 1)))
1308;;; ((and (not (looking-at f90-typeis-re))
1309;;; (looking-at f90-type-def-re))
1310;;; (list (match-string 1) (match-string 2)))
7cf3f3d6
GM
1311 ((looking-at "\\<\\(interface\\)\\>[ \t]*")
1312 (list (match-string 1)
1313 (save-excursion
1314 (goto-char (match-end 0))
1315 (if (or (looking-at "\\(operator\\|assignment\\|read\\|\
1316write\\)[ \t]*([^)\n]*)")
1317 (looking-at "\\sw+"))
1318 (match-string 0)))))
1319 ((looking-at "\\(enum\\|block[ \t]*data\\)\\>")
5ab33946
GM
1320 (list (match-string 1) nil))
1321 ((looking-at "abstract[ \t]*\\(interface\\)\\>")
6734e165 1322 (list (match-string 1) nil))))
034a9d40
RS
1323
1324(defsubst f90-looking-at-program-block-start ()
d14e6bbe 1325 "Return (KIND NAME) if a program block with name NAME starts after point."
784d007b 1326;;;NAME is nil for an un-named main PROGRAM block."
034a9d40 1327 (cond
ee30478d 1328 ((looking-at "\\(program\\)[ \t]+\\(\\sw+\\)\\>")
6734e165 1329 (list (match-string 1) (match-string 2)))
034a9d40 1330 ((and (not (looking-at "module[ \t]*procedure\\>"))
640f9e26 1331 (looking-at "\\(module\\)[ \t]+\\(\\sw+\\)\\>"))
6734e165 1332 (list (match-string 1) (match-string 2)))
5d8e0d43
GM
1333 ((looking-at "\\(submodule\\)[ \t]*([^)\n]+)[ \t]*\\(\\sw+\\)\\>")
1334 (list (match-string 1) (match-string 2)))
b974df0a 1335 ((and (not (looking-at "end[ \t]*\\(function\\|subroutine\\)"))
640f9e26 1336 (looking-at "[^!'\"\&\n]*\\(function\\|subroutine\\)[ \t]+\
748dd5a8 1337\\(\\sw+\\)"))
6734e165 1338 (list (match-string 1) (match-string 2)))))
784d007b
GM
1339;; Following will match an un-named main program block; however
1340;; one needs to check if there is an actual PROGRAM statement after
1341;; point (and before any END program). Adding this will require
1342;; change to eg f90-calculate-indent.
1343;;; ((save-excursion
1344;;; (not (f90-previous-statement)))
1345;;; '("program" nil))))
034a9d40
RS
1346
1347(defsubst f90-looking-at-program-block-end ()
d14e6bbe 1348 "Return (KIND NAME) if a block with name NAME ends after point."
7cf3f3d6
GM
1349 (cond ((looking-at "end[ \t]*\\(interface\\)[ \t]*\\(\
1350\\(?:assignment\\|operator\\|read\\|write\\)[ \t]*([^)\n]*)\\)")
1351 (list (match-string 1) (match-string 2)))
1352 ((looking-at (concat "end[ \t]*" f90-blocks-re
1353 "?\\([ \t]+\\(\\sw+\\)\\)?\\>"))
1354 (list (match-string 1) (match-string 3)))))
034a9d40
RS
1355
1356(defsubst f90-comment-indent ()
ec2f376f
GM
1357 "Return the indentation to be used for a comment starting at point.
1358Used for `comment-indent-function' by F90 mode.
1359\"!!!\", `f90-directive-comment-re', variable `f90-comment-region' return 0.
1360`f90-indented-comment-re' (if not trailing code) calls `f90-calculate-indent'.
89fa1ef5 1361All others return `comment-column', leaving at least one space after code."
034a9d40 1362 (cond ((looking-at "!!!") 0)
640f9e26
GM
1363 ((and f90-directive-comment-re
1364 (looking-at f90-directive-comment-re)) 0)
1365 ((looking-at (regexp-quote f90-comment-region)) 0)
1366 ((and (looking-at f90-indented-comment-re)
1367 ;; Don't attempt to indent trailing comment as code.
1368 (save-excursion
1369 (skip-chars-backward " \t")
1370 (bolp)))
1371 (f90-calculate-indent))
1372 (t (save-excursion
b464e0ee
GM
1373 (skip-chars-backward " \t")
1374 (max (if (bolp) 0 (1+ (current-column))) comment-column)))))
034a9d40
RS
1375
1376(defsubst f90-present-statement-cont ()
d14e6bbe
GM
1377 "Return continuation properties of present statement.
1378Possible return values are:
1379single - statement is not continued.
1380begin - current line is the first in a continued statement.
1381end - current line is the last in a continued statement
1382middle - current line is neither first nor last in a continued statement.
1383Comment lines embedded amongst continued lines return 'middle."
034a9d40
RS
1384 (let (pcont cont)
1385 (save-excursion
e3f5ce56 1386 (setq pcont (if (f90-previous-statement) (f90-line-continued))))
034a9d40
RS
1387 (setq cont (f90-line-continued))
1388 (cond ((and (not pcont) (not cont)) 'single)
640f9e26
GM
1389 ((and (not pcont) cont) 'begin)
1390 ((and pcont (not cont)) 'end)
1391 ((and pcont cont) 'middle)
1392 (t (error "The impossible occurred")))))
034a9d40
RS
1393
1394(defsubst f90-indent-line-no ()
d14e6bbe
GM
1395 "If `f90-leave-line-no' is nil, left-justify a line number.
1396Leaves point at the first non-blank character after the line number.
1397Call from beginning of line."
748dd5a8
GM
1398 (and (null f90-leave-line-no) (looking-at "[ \t]+[0-9]")
1399 (delete-horizontal-space))
034a9d40
RS
1400 (skip-chars-forward " \t0-9"))
1401
1402(defsubst f90-no-block-limit ()
d14e6bbe
GM
1403 "Return nil if point is at the edge of a code block.
1404Searches line forward for \"function\" or \"subroutine\",
1405if all else fails."
748dd5a8
GM
1406 (save-excursion
1407 (not (or (looking-at "end")
1408 (looking-at "\\(do\\|if\\|else\\(if\\|where\\)?\
e93db24a
GM
1409\\|select[ \t]*\\(case\\|type\\)\\|case\\|where\\|forall\\|\
1410block\\|critical\\)\\>")
5d8e0d43 1411 (looking-at "\\(program\\|\\(?:sub\\)?module\\|\
b1ca7740 1412\\(?:abstract[ \t]*\\)?interface\\|block[ \t]*data\\)\\>")
748dd5a8
GM
1413 (looking-at "\\(contains\\|\\sw+[ \t]*:\\)")
1414 (looking-at f90-type-def-re)
1415 (re-search-forward "\\(function\\|subroutine\\)"
1416 (line-end-position) t)))))
034a9d40
RS
1417
1418(defsubst f90-update-line ()
d14e6bbe
GM
1419 "Change case of current line as per `f90-auto-keyword-case'."
1420 (if f90-auto-keyword-case
1421 (f90-change-keywords f90-auto-keyword-case
1422 (line-beginning-position) (line-end-position))))
034a9d40 1423\f
d694ccd7 1424(defun f90-electric-insert (&optional arg)
d14e6bbe 1425 "Change keyword case and auto-fill line as operators are inserted."
d694ccd7
GM
1426 (interactive "*p")
1427 (self-insert-command arg)
d14e6bbe
GM
1428 (if auto-fill-function (f90-do-auto-fill) ; also updates line
1429 (f90-update-line)))
1430
055e4eea
GM
1431;; Behave like self-insert-command for delete-selection-mode (bug#5593).
1432(put 'f90-electric-insert 'delete-selection t)
7cae52cf 1433
034a9d40
RS
1434(defun f90-get-correct-indent ()
1435 "Get correct indent for a line starting with line number.
1436Does not check type and subprogram indentation."
239da61d 1437 (let ((epnt (line-end-position)) icol)
034a9d40
RS
1438 (save-excursion
1439 (while (and (f90-previous-statement)
239da61d 1440 (or (memq (f90-present-statement-cont) '(middle end))
640f9e26 1441 (looking-at "[ \t]*[0-9]"))))
034a9d40
RS
1442 (setq icol (current-indentation))
1443 (beginning-of-line)
5c2a80ad
GM
1444 (when (re-search-forward "\\(if\\|do\\|select\\|where\\|forall\\)"
1445 (line-end-position) t)
e3f5ce56
GM
1446 (beginning-of-line)
1447 (skip-chars-forward " \t")
5c2a80ad
GM
1448 (cond ((f90-looking-at-do)
1449 (setq icol (+ icol f90-do-indent)))
1450 ((or (f90-looking-at-if-then)
1451 (f90-looking-at-where-or-forall)
1452 (f90-looking-at-select-case))
5ab33946 1453 (setq icol (+ icol f90-if-indent)))
e93db24a
GM
1454 ;; FIXME this makes no sense, because this section/function is
1455 ;; only for if/do/select/where/forall ?
5ab33946
GM
1456 ((f90-looking-at-associate)
1457 (setq icol (+ icol f90-associate-indent))))
5c2a80ad 1458 (end-of-line))
034a9d40 1459 (while (re-search-forward
640f9e26
GM
1460 "\\(if\\|do\\|select\\|where\\|forall\\)" epnt t)
1461 (beginning-of-line)
e3f5ce56 1462 (skip-chars-forward " \t0-9")
640f9e26 1463 (cond ((f90-looking-at-do)
e3f5ce56
GM
1464 (setq icol (+ icol f90-do-indent)))
1465 ((or (f90-looking-at-if-then)
1466 (f90-looking-at-where-or-forall)
1467 (f90-looking-at-select-case))
1468 (setq icol (+ icol f90-if-indent)))
e93db24a
GM
1469 ;; FIXME this makes no sense, because this section/function is
1470 ;; only for if/do/select/where/forall ?
5ab33946
GM
1471 ((f90-looking-at-associate)
1472 (setq icol (+ icol f90-associate-indent)))
e3f5ce56
GM
1473 ((looking-at f90-end-if-re)
1474 (setq icol (- icol f90-if-indent)))
5ab33946
GM
1475 ((looking-at f90-end-associate-re)
1476 (setq icol (- icol f90-associate-indent)))
e93db24a
GM
1477 ((f90-looking-at-end-critical)
1478 (setq icol (- icol f90-critical-indent)))
e3f5ce56
GM
1479 ((looking-at "end[ \t]*do\\>")
1480 (setq icol (- icol f90-do-indent))))
640f9e26 1481 (end-of-line))
034a9d40 1482 icol)))
69658465 1483
034a9d40
RS
1484(defun f90-calculate-indent ()
1485 "Calculate the indent column based on previous statements."
1486 (interactive)
1487 (let (icol cont (case-fold-search t) (pnt (point)))
1488 (save-excursion
1489 (if (not (f90-previous-statement))
b78cbdf7
GM
1490 ;; If f90-previous-statement returns nil, we must have been
1491 ;; called from on or before the first line of the first statement.
0812589b
GM
1492 (setq icol (if (or (save-excursion
1493 (goto-char pnt)
1494 (beginning-of-line)
1495 ;; Preprocessor line before code statement.
1496 (looking-at "[ \t]*#"))
1497 (progn
1498 ;; f90-previous-statement has moved us over
1499 ;; comment/blank lines, so we need to get
1500 ;; back to the first code statement.
1501 (when (looking-at "[ \t]*\\([!#]\\|$\\)")
1502 (f90-next-statement))
1503 (skip-chars-forward " \t0-9")
1504 (f90-looking-at-program-block-start)))
784d007b
GM
1505 0
1506 ;; No explicit PROGRAM start statement.
1507 f90-program-indent))
640f9e26
GM
1508 (setq cont (f90-present-statement-cont))
1509 (if (eq cont 'end)
1510 (while (not (eq 'begin (f90-present-statement-cont)))
1511 (f90-previous-statement)))
1512 (cond ((eq cont 'begin)
1513 (setq icol (+ (f90-current-indentation)
1514 f90-continuation-indent)))
1515 ((eq cont 'middle) (setq icol (current-indentation)))
1516 (t (setq icol (f90-current-indentation))
1517 (skip-chars-forward " \t")
1518 (if (looking-at "[0-9]")
1519 (setq icol (f90-get-correct-indent))
1520 (cond ((or (f90-looking-at-if-then)
1521 (f90-looking-at-where-or-forall)
1522 (f90-looking-at-select-case)
1523 (looking-at f90-else-like-re))
1524 (setq icol (+ icol f90-if-indent)))
1525 ((f90-looking-at-do)
1526 (setq icol (+ icol f90-do-indent)))
1527 ((f90-looking-at-type-like)
1528 (setq icol (+ icol f90-type-indent)))
5ab33946
GM
1529 ((f90-looking-at-associate)
1530 (setq icol (+ icol f90-associate-indent)))
e93db24a
GM
1531 ((f90-looking-at-critical)
1532 (setq icol (+ icol f90-critical-indent)))
640f9e26
GM
1533 ((or (f90-looking-at-program-block-start)
1534 (looking-at "contains[ \t]*\\($\\|!\\)"))
1535 (setq icol (+ icol f90-program-indent)))))
1536 (goto-char pnt)
1537 (beginning-of-line)
1538 (cond ((looking-at "[ \t]*$"))
1539 ((looking-at "[ \t]*#") ; check for cpp directive
1540 (setq icol 0))
1541 (t
1542 (skip-chars-forward " \t0-9")
1543 (cond ((or (looking-at f90-else-like-re)
1544 (looking-at f90-end-if-re))
1545 (setq icol (- icol f90-if-indent)))
1546 ((looking-at "end[ \t]*do\\>")
1547 (setq icol (- icol f90-do-indent)))
1548 ((looking-at f90-end-type-re)
1549 (setq icol (- icol f90-type-indent)))
5ab33946
GM
1550 ((looking-at f90-end-associate-re)
1551 (setq icol (- icol f90-associate-indent)))
e93db24a
GM
1552 ((f90-looking-at-end-critical)
1553 (setq icol (- icol f90-critical-indent)))
640f9e26
GM
1554 ((or (looking-at "contains[ \t]*\\(!\\|$\\)")
1555 (f90-looking-at-program-block-end))
599aeab9 1556 (setq icol (- icol f90-program-indent))))))))))
034a9d40
RS
1557 icol))
1558\f
034a9d40
RS
1559(defun f90-previous-statement ()
1560 "Move point to beginning of the previous F90 statement.
784d007b
GM
1561If no previous statement is found (i.e. if called from the first
1562statement in the buffer), move to the start of the buffer and
1563return nil. A statement is a line which is neither blank nor a
1564comment."
034a9d40
RS
1565 (interactive)
1566 (let (not-first-statement)
1567 (beginning-of-line)
1568 (while (and (setq not-first-statement (zerop (forward-line -1)))
640f9e26 1569 (looking-at "[ \t0-9]*\\(!\\|$\\|#\\)")))
034a9d40
RS
1570 not-first-statement))
1571
1572(defun f90-next-statement ()
1573 "Move point to beginning of the next F90 statement.
1574Return nil if no later statement is found."
1575 (interactive)
1576 (let (not-last-statement)
1577 (beginning-of-line)
1578 (while (and (setq not-last-statement
640f9e26
GM
1579 (and (zerop (forward-line 1))
1580 (not (eobp))))
c02ee9d6 1581 (looking-at "[ \t0-9]*\\(!\\|$\\|#\\)")))
034a9d40
RS
1582 not-last-statement))
1583
1584(defun f90-beginning-of-subprogram ()
76bccf35 1585 "Move point to the beginning of the current subprogram.
ec2f376f 1586Return (TYPE NAME), or nil if not found."
034a9d40
RS
1587 (interactive)
1588 (let ((count 1) (case-fold-search t) matching-beg)
e3f5ce56 1589 (beginning-of-line)
76bccf35 1590 (while (and (> count 0)
640f9e26 1591 (re-search-backward f90-program-block-re nil 'move))
e3f5ce56
GM
1592 (beginning-of-line)
1593 (skip-chars-forward " \t0-9")
1594 (cond ((setq matching-beg (f90-looking-at-program-block-start))
1595 (setq count (1- count)))
1596 ((f90-looking-at-program-block-end)
1597 (setq count (1+ count)))))
034a9d40
RS
1598 (beginning-of-line)
1599 (if (zerop count)
640f9e26 1600 matching-beg
784d007b
GM
1601 ;; Note this includes the case of an un-named main program,
1602 ;; in which case we go to (point-min).
32226619
JB
1603 (if (called-interactively-p 'interactive)
1604 (message "No beginning found"))
034a9d40
RS
1605 nil)))
1606
1607(defun f90-end-of-subprogram ()
76bccf35 1608 "Move point to the end of the current subprogram.
ec2f376f 1609Return (TYPE NAME), or nil if not found."
034a9d40 1610 (interactive)
7aee8047 1611 (let ((case-fold-search t)
575b6746 1612 (count 1)
7aee8047 1613 matching-end)
034a9d40 1614 (end-of-line)
76bccf35 1615 (while (and (> count 0)
640f9e26 1616 (re-search-forward f90-program-block-re nil 'move))
e3f5ce56
GM
1617 (beginning-of-line)
1618 (skip-chars-forward " \t0-9")
034a9d40 1619 (cond ((f90-looking-at-program-block-start)
640f9e26
GM
1620 (setq count (1+ count)))
1621 ((setq matching-end (f90-looking-at-program-block-end))
1622 (setq count (1- count))))
034a9d40 1623 (end-of-line))
6f1d50da
GM
1624 ;; This means f90-end-of-subprogram followed by f90-start-of-subprogram
1625 ;; has a net non-zero effect, which seems odd.
1626;;; (forward-line 1)
034a9d40 1627 (if (zerop count)
640f9e26 1628 matching-end
32226619
JB
1629 (if (called-interactively-p 'interactive)
1630 (message "No end found"))
034a9d40
RS
1631 nil)))
1632
6f1d50da
GM
1633
1634(defun f90-end-of-block (&optional num)
1635 "Move point forward to the end of the current code block.
1636With optional argument NUM, go forward that many balanced blocks.
784d007b
GM
1637If NUM is negative, go backward to the start of a block. Checks
1638for consistency of block types and labels (if present), and
1639completes outermost block if `f90-smart-end' is non-nil.
1640Interactively, pushes mark before moving point."
6f1d50da 1641 (interactive "p")
7938ab41
GM
1642 ;; Can move some distance.
1643 (if (called-interactively-p 'any) (push-mark (point) t))
784d007b
GM
1644 (and num (< num 0) (f90-beginning-of-block (- num)))
1645 (let ((f90-smart-end (if f90-smart-end 'no-blink)) ; for final match-end
6f1d50da
GM
1646 (case-fold-search t)
1647 (count (or num 1))
1648 start-list start-this start-type start-label end-type end-label)
6f1d50da
GM
1649 (end-of-line) ; probably want this
1650 (while (and (> count 0) (re-search-forward f90-blocks-re nil 'move))
1651 (beginning-of-line)
1652 (skip-chars-forward " \t0-9")
1653 (cond ((or (f90-in-string) (f90-in-comment)))
1654 ((setq start-this
1655 (or
1656 (f90-looking-at-do)
1657 (f90-looking-at-select-case)
1658 (f90-looking-at-type-like)
5ab33946 1659 (f90-looking-at-associate)
e93db24a 1660 (f90-looking-at-critical)
6f1d50da
GM
1661 (f90-looking-at-program-block-start)
1662 (f90-looking-at-if-then)
1663 (f90-looking-at-where-or-forall)))
1664 (setq start-list (cons start-this start-list) ; not add-to-list!
1665 count (1+ count)))
1666 ((looking-at (concat "end[ \t]*" f90-blocks-re
1667 "[ \t]*\\(\\sw+\\)?"))
1668 (setq end-type (match-string 1)
1669 end-label (match-string 2)
1670 count (1- count))
1671 ;; Check any internal blocks.
1672 (when start-list
1673 (setq start-this (car start-list)
1674 start-list (cdr start-list)
1675 start-type (car start-this)
1676 start-label (cadr start-this))
748dd5a8 1677 (or (f90-equal-symbols start-type end-type)
6f1d50da
GM
1678 (error "End type `%s' does not match start type `%s'"
1679 end-type start-type))
748dd5a8 1680 (or (f90-equal-symbols start-label end-label)
6f1d50da
GM
1681 (error "End label `%s' does not match start label `%s'"
1682 end-label start-label)))))
1683 (end-of-line))
76bccf35 1684 (if (> count 0) (error "Missing block end"))
6f1d50da 1685 ;; Check outermost block.
784d007b
GM
1686 (when f90-smart-end
1687 (save-excursion
1688 (beginning-of-line)
1689 (skip-chars-forward " \t0-9")
1690 (f90-match-end)))))
6f1d50da
GM
1691
1692(defun f90-beginning-of-block (&optional num)
1693 "Move point backwards to the start of the current code block.
1694With optional argument NUM, go backward that many balanced blocks.
1695If NUM is negative, go forward to the end of a block.
1696Checks for consistency of block types and labels (if present).
784d007b
GM
1697Does not check the outermost block, because it may be incomplete.
1698Interactively, pushes mark before moving point."
6f1d50da 1699 (interactive "p")
7938ab41 1700 (if (called-interactively-p 'any) (push-mark (point) t))
784d007b 1701 (and num (< num 0) (f90-end-of-block (- num)))
6f1d50da
GM
1702 (let ((case-fold-search t)
1703 (count (or num 1))
748dd5a8
GM
1704 end-list end-this end-type end-label
1705 start-this start-type start-label)
6f1d50da
GM
1706 (beginning-of-line) ; probably want this
1707 (while (and (> count 0) (re-search-backward f90-blocks-re nil 'move))
1708 (beginning-of-line)
1709 (skip-chars-forward " \t0-9")
1710 (cond ((or (f90-in-string) (f90-in-comment)))
1711 ((looking-at (concat "end[ \t]*" f90-blocks-re
1712 "[ \t]*\\(\\sw+\\)?"))
1713 (setq end-list (cons (list (match-string 1) (match-string 2))
1714 end-list)
1715 count (1+ count)))
1716 ((setq start-this
1717 (or
1718 (f90-looking-at-do)
1719 (f90-looking-at-select-case)
1720 (f90-looking-at-type-like)
5ab33946 1721 (f90-looking-at-associate)
e93db24a 1722 (f90-looking-at-critical)
6f1d50da
GM
1723 (f90-looking-at-program-block-start)
1724 (f90-looking-at-if-then)
1725 (f90-looking-at-where-or-forall)))
1726 (setq start-type (car start-this)
1727 start-label (cadr start-this)
1728 count (1- count))
1729 ;; Check any internal blocks.
1730 (when end-list
1731 (setq end-this (car end-list)
1732 end-list (cdr end-list)
1733 end-type (car end-this)
1734 end-label (cadr end-this))
748dd5a8 1735 (or (f90-equal-symbols start-type end-type)
6f1d50da
GM
1736 (error "Start type `%s' does not match end type `%s'"
1737 start-type end-type))
748dd5a8 1738 (or (f90-equal-symbols start-label end-label)
6f1d50da
GM
1739 (error "Start label `%s' does not match end label `%s'"
1740 start-label end-label))))))
784d007b
GM
1741 ;; Includes an un-named main program block.
1742 (if (> count 0) (error "Missing block start"))))
6f1d50da 1743
76bccf35
GM
1744(defun f90-next-block (&optional num)
1745 "Move point forward to the next end or start of a code block.
1746With optional argument NUM, go forward that many blocks.
1747If NUM is negative, go backwards.
1748A block is a subroutine, if-endif, etc."
6f1d50da 1749 (interactive "p")
76bccf35
GM
1750 (let ((case-fold-search t)
1751 (count (if num (abs num) 1)))
1752 (while (and (> count 0)
1753 (if (> num 0) (re-search-forward f90-blocks-re nil 'move)
1754 (re-search-backward f90-blocks-re nil 'move)))
6f1d50da
GM
1755 (beginning-of-line)
1756 (skip-chars-forward " \t0-9")
76bccf35
GM
1757 (cond ((or (f90-in-string) (f90-in-comment)))
1758 ((or
1759 (looking-at "end[ \t]*")
1760 (f90-looking-at-do)
1761 (f90-looking-at-select-case)
1762 (f90-looking-at-type-like)
5ab33946 1763 (f90-looking-at-associate)
e93db24a 1764 (f90-looking-at-critical)
76bccf35
GM
1765 (f90-looking-at-program-block-start)
1766 (f90-looking-at-if-then)
1767 (f90-looking-at-where-or-forall))
1768 (setq count (1- count))))
1769 (if (> num 0) (end-of-line)
1770 (beginning-of-line)))))
1771
1772
1773(defun f90-previous-block (&optional num)
1774 "Move point backward to the previous end or start of a code block.
1775With optional argument NUM, go backward that many blocks.
1776If NUM is negative, go forwards.
1777A block is a subroutine, if-endif, etc."
6f1d50da 1778 (interactive "p")
76bccf35 1779 (f90-next-block (- (or num 1))))
6f1d50da
GM
1780
1781
034a9d40 1782(defun f90-mark-subprogram ()
a729409a 1783 "Put mark at end of F90 subprogram, point at beginning, push mark."
034a9d40
RS
1784 (interactive)
1785 (let ((pos (point)) program)
1786 (f90-end-of-subprogram)
0ee7f068 1787 (push-mark)
034a9d40
RS
1788 (goto-char pos)
1789 (setq program (f90-beginning-of-subprogram))
a445370f 1790 (if (featurep 'xemacs)
0ee7f068 1791 (zmacs-activate-region)
1bb3ae5c 1792 (setq mark-active t
0ee7f068 1793 deactivate-mark nil))
034a9d40
RS
1794 program))
1795
1796(defun f90-comment-region (beg-region end-region)
1797 "Comment/uncomment every line in the region.
d14e6bbe
GM
1798Insert the variable `f90-comment-region' at the start of every line
1799in the region, or, if already present, remove it."
034a9d40 1800 (interactive "*r")
748dd5a8 1801 (let ((end (copy-marker end-region)))
034a9d40
RS
1802 (goto-char beg-region)
1803 (beginning-of-line)
1804 (if (looking-at (regexp-quote f90-comment-region))
640f9e26 1805 (delete-region (point) (match-end 0))
034a9d40 1806 (insert f90-comment-region))
e3f5ce56 1807 (while (and (zerop (forward-line 1))
640f9e26 1808 (< (point) end))
034a9d40 1809 (if (looking-at (regexp-quote f90-comment-region))
640f9e26
GM
1810 (delete-region (point) (match-end 0))
1811 (insert f90-comment-region)))
034a9d40
RS
1812 (set-marker end nil)))
1813
1814(defun f90-indent-line (&optional no-update)
87ee2359
GM
1815 "Indent current line as F90 code.
1816Unless optional argument NO-UPDATE is non-nil, call `f90-update-line'
1817after indenting."
a729409a 1818 (interactive "*P")
748dd5a8
GM
1819 (let ((case-fold-search t)
1820 (pos (point-marker))
1821 indent no-line-number)
1822 (beginning-of-line) ; digits after & \n are not line-nos
1823 (if (not (save-excursion (and (f90-previous-statement)
1824 (f90-line-continued))))
1825 (f90-indent-line-no)
1826 (setq no-line-number t)
1827 (skip-chars-forward " \t"))
034a9d40 1828 (if (looking-at "!")
640f9e26 1829 (setq indent (f90-comment-indent))
ab09adac 1830 (and f90-smart-end (looking-at "end")
748dd5a8 1831 (f90-match-end))
034a9d40 1832 (setq indent (f90-calculate-indent)))
748dd5a8 1833 (or (= indent (current-column))
e3f5ce56 1834 (f90-indent-to indent no-line-number))
034a9d40
RS
1835 ;; If initial point was within line's indentation,
1836 ;; position after the indentation. Else stay at same point in text.
748dd5a8
GM
1837 (and (< (point) pos)
1838 (goto-char pos))
69658465 1839 (if auto-fill-function
c5e87d10 1840 ;; GM NO-UPDATE not honored, since this calls f90-update-line.
7aee8047 1841 (f90-do-auto-fill)
748dd5a8 1842 (or no-update (f90-update-line)))
034a9d40
RS
1843 (set-marker pos nil)))
1844
1845(defun f90-indent-new-line ()
a729409a 1846 "Re-indent current line, insert a newline and indent the newline.
87ee2359 1847An abbrev before point is expanded if the variable `abbrev-mode' is non-nil.
034a9d40 1848If run in the middle of a line, the line is not broken."
a729409a 1849 (interactive "*")
748dd5a8
GM
1850 (if abbrev-mode (expand-abbrev))
1851 (beginning-of-line) ; reindent where likely to be needed
7aee8047 1852 (f90-indent-line) ; calls indent-line-no, update-line
748dd5a8 1853 (end-of-line)
640f9e26 1854 (delete-horizontal-space) ; destroy trailing whitespace
748dd5a8
GM
1855 (let ((string (f90-in-string))
1856 (cont (f90-line-continued)))
1857 (and string (not cont) (insert "&"))
034a9d40 1858 (newline)
748dd5a8 1859 (if (or string (and cont f90-beginning-ampersand)) (insert "&")))
7aee8047 1860 (f90-indent-line 'no-update)) ; nothing to update
034a9d40
RS
1861
1862
784d007b
GM
1863;; TODO not add spaces to empty lines at the start.
1864;; Why is second line getting extra indent over first?
034a9d40
RS
1865(defun f90-indent-region (beg-region end-region)
1866 "Indent every line in region by forward parsing."
1867 (interactive "*r")
748dd5a8 1868 (let ((end-region-mark (copy-marker end-region))
e3f5ce56 1869 (save-point (point-marker))
cbc121c7 1870 (case-fold-search t)
640f9e26 1871 block-list ind-lev ind-curr ind-b cont struct beg-struct end-struct)
034a9d40 1872 (goto-char beg-region)
ec2f376f 1873 ;; First find a line which is not a continuation line or comment.
034a9d40 1874 (beginning-of-line)
ee30478d 1875 (while (and (looking-at "[ \t]*[0-9]*\\(!\\|#\\|[ \t]*$\\)")
640f9e26
GM
1876 (progn (f90-indent-line 'no-update)
1877 (zerop (forward-line 1)))
1878 (< (point) end-region-mark)))
034a9d40 1879 (setq cont (f90-present-statement-cont))
f38184aa 1880 (while (and (memq cont '(middle end))
640f9e26 1881 (f90-previous-statement))
034a9d40 1882 (setq cont (f90-present-statement-cont)))
ec2f376f 1883 ;; Process present line for beginning of block.
034a9d40
RS
1884 (setq f90-cache-position (point))
1885 (f90-indent-line 'no-update)
e3f5ce56
GM
1886 (setq ind-lev (f90-current-indentation)
1887 ind-curr ind-lev)
1888 (beginning-of-line)
1889 (skip-chars-forward " \t0-9")
1890 (setq struct nil
1891 ind-b (cond ((setq struct (f90-looking-at-do)) f90-do-indent)
640f9e26
GM
1892 ((or (setq struct (f90-looking-at-if-then))
1893 (setq struct (f90-looking-at-select-case))
1894 (setq struct (f90-looking-at-where-or-forall))
1895 (looking-at f90-else-like-re))
1896 f90-if-indent)
1897 ((setq struct (f90-looking-at-type-like))
1898 f90-type-indent)
5ab33946
GM
1899 ((setq struct (f90-looking-at-associate))
1900 f90-associate-indent)
e93db24a
GM
1901 ((setq struct (f90-looking-at-critical))
1902 f90-critical-indent)
640f9e26 1903 ((or (setq struct (f90-looking-at-program-block-start))
34ba7e3d 1904 (looking-at "contains[ \t]*\\($\\|!\\)"))
640f9e26 1905 f90-program-indent)))
034a9d40
RS
1906 (if ind-b (setq ind-lev (+ ind-lev ind-b)))
1907 (if struct (setq block-list (cons struct block-list)))
1908 (while (and (f90-line-continued) (zerop (forward-line 1))
640f9e26 1909 (< (point) end-region-mark))
ec2f376f
GM
1910 (if (looking-at "[ \t]*!")
1911 (f90-indent-to (f90-comment-indent))
748dd5a8
GM
1912 (or (= (current-indentation)
1913 (+ ind-curr f90-continuation-indent))
ec2f376f
GM
1914 (f90-indent-to (+ ind-curr f90-continuation-indent) 'no-line-no))))
1915 ;; Process all following lines.
d14e6bbe 1916 (while (and (zerop (forward-line 1)) (< (point) end-region-mark))
034a9d40
RS
1917 (beginning-of-line)
1918 (f90-indent-line-no)
1919 (setq f90-cache-position (point))
1920 (cond ((looking-at "[ \t]*$") (setq ind-curr 0))
640f9e26
GM
1921 ((looking-at "[ \t]*#") (setq ind-curr 0))
1922 ((looking-at "!") (setq ind-curr (f90-comment-indent)))
1923 ((f90-no-block-limit) (setq ind-curr ind-lev))
1924 ((looking-at f90-else-like-re) (setq ind-curr
1925 (- ind-lev f90-if-indent)))
1926 ((looking-at "contains[ \t]*\\($\\|!\\)")
1927 (setq ind-curr (- ind-lev f90-program-indent)))
1928 ((setq ind-b
1929 (cond ((setq struct (f90-looking-at-do)) f90-do-indent)
1930 ((or (setq struct (f90-looking-at-if-then))
1931 (setq struct (f90-looking-at-select-case))
1932 (setq struct (f90-looking-at-where-or-forall)))
1933 f90-if-indent)
1934 ((setq struct (f90-looking-at-type-like))
1935 f90-type-indent)
5ab33946
GM
1936 ((setq struct (f90-looking-at-associate))
1937 f90-associate-indent)
e93db24a
GM
1938 ((setq struct (f90-looking-at-critical))
1939 f90-critical-indent)
640f9e26
GM
1940 ((setq struct (f90-looking-at-program-block-start))
1941 f90-program-indent)))
1942 (setq ind-curr ind-lev)
1943 (if ind-b (setq ind-lev (+ ind-lev ind-b)))
1944 (setq block-list (cons struct block-list)))
1945 ((setq end-struct (f90-looking-at-program-block-end))
1946 (setq beg-struct (car block-list)
1947 block-list (cdr block-list))
1948 (if f90-smart-end
1949 (save-excursion
599aeab9
GM
1950 (f90-block-match (car beg-struct) (cadr beg-struct)
1951 (car end-struct) (cadr end-struct))))
640f9e26
GM
1952 (setq ind-b
1953 (cond ((looking-at f90-end-if-re) f90-if-indent)
1954 ((looking-at "end[ \t]*do\\>") f90-do-indent)
1955 ((looking-at f90-end-type-re) f90-type-indent)
5ab33946
GM
1956 ((looking-at f90-end-associate-re)
1957 f90-associate-indent)
e93db24a 1958 ((f90-looking-at-end-critical) f90-critical-indent)
640f9e26
GM
1959 ((f90-looking-at-program-block-end)
1960 f90-program-indent)))
1961 (if ind-b (setq ind-lev (- ind-lev ind-b)))
1962 (setq ind-curr ind-lev))
1963 (t (setq ind-curr ind-lev)))
ec2f376f 1964 ;; Do the indentation if necessary.
748dd5a8 1965 (or (= ind-curr (current-column))
640f9e26 1966 (f90-indent-to ind-curr))
034a9d40 1967 (while (and (f90-line-continued) (zerop (forward-line 1))
640f9e26 1968 (< (point) end-region-mark))
ec2f376f
GM
1969 (if (looking-at "[ \t]*!")
1970 (f90-indent-to (f90-comment-indent))
748dd5a8
GM
1971 (or (= (current-indentation)
1972 (+ ind-curr f90-continuation-indent))
ec2f376f
GM
1973 (f90-indent-to
1974 (+ ind-curr f90-continuation-indent) 'no-line-no)))))
1975 ;; Restore point, etc.
034a9d40
RS
1976 (setq f90-cache-position nil)
1977 (goto-char save-point)
1978 (set-marker end-region-mark nil)
1979 (set-marker save-point nil)
a445370f 1980 (if (featurep 'xemacs)
640f9e26 1981 (zmacs-deactivate-region)
034a9d40
RS
1982 (deactivate-mark))))
1983
1984(defun f90-indent-subprogram ()
ec2f376f 1985 "Properly indent the subprogram containing point."
a729409a 1986 (interactive "*")
034a9d40 1987 (save-excursion
e3f5ce56 1988 (let ((program (f90-mark-subprogram)))
034a9d40 1989 (if program
640f9e26
GM
1990 (progn
1991 (message "Indenting %s %s..."
599aeab9 1992 (car program) (cadr program))
640f9e26
GM
1993 (indent-region (point) (mark) nil)
1994 (message "Indenting %s %s...done"
599aeab9 1995 (car program) (cadr program)))
640f9e26
GM
1996 (message "Indenting the whole file...")
1997 (indent-region (point) (mark) nil)
1998 (message "Indenting the whole file...done")))))
034a9d40 1999
034a9d40 2000(defun f90-break-line (&optional no-update)
87ee2359
GM
2001 "Break line at point, insert continuation marker(s) and indent.
2002Unless in a string or comment, or if the optional argument NO-UPDATE
2003is non-nil, call `f90-update-line' after inserting the continuation marker."
a729409a 2004 (interactive "*P")
89fa1ef5
GM
2005 (cond ((f90-in-string)
2006 (insert "&\n&"))
2007 ((f90-in-comment)
f84e2fe2 2008 (delete-horizontal-space) ; remove trailing whitespace
89fa1ef5
GM
2009 (insert "\n" (f90-get-present-comment-type)))
2010 (t (insert "&")
2011 (or no-update (f90-update-line))
2012 (newline 1)
f38184aa
GM
2013 ;; FIXME also need leading ampersand if split lexical token (eg ==).
2014 ;; Or respect f90-no-break-re.
89fa1ef5 2015 (if f90-beginning-ampersand (insert "&"))))
84021009 2016 (indent-according-to-mode))
69658465 2017
034a9d40 2018(defun f90-find-breakpoint ()
87ee2359 2019 "From `fill-column', search backward for break-delimiter."
9d4433a2 2020 ;; Commented text more likely than commented code.
f84e2fe2
LM
2021 (if (f90-in-comment)
2022 (re-search-backward "\\s-" (line-beginning-position))
9d4433a2
GM
2023 (re-search-backward f90-break-delimiters (line-beginning-position))
2024 (if (not f90-break-before-delimiters)
2025 (forward-char (if (looking-at f90-no-break-re) 2 1))
2026 (backward-char)
2027 (or (looking-at f90-no-break-re)
2028 (forward-char)))))
034a9d40 2029
034a9d40 2030(defun f90-do-auto-fill ()
d14e6bbe
GM
2031 "Break line if non-white characters beyond `fill-column'.
2032Update keyword case first."
a729409a 2033 (interactive "*")
ec2f376f 2034 ;; Break line before or after last delimiter (non-word char) if
b974df0a 2035 ;; position is beyond fill-column.
ec2f376f 2036 ;; Will not break **, //, or => (as specified by f90-no-break-re).
7cae52cf 2037 (f90-update-line)
d595e95d
GM
2038 ;; Need this for `f90-electric-insert' and other f90- callers.
2039 (unless (and (boundp 'comment-auto-fill-only-comments)
2040 comment-auto-fill-only-comments
2041 (not (f90-in-comment)))
2042 (while (> (current-column) fill-column)
2043 (let ((pos-mark (point-marker)))
2044 (move-to-column fill-column)
2045 (or (f90-in-string) (f90-find-breakpoint))
2046 (f90-break-line)
2047 (goto-char pos-mark)
2048 (set-marker pos-mark nil)))))
b974df0a 2049
a259425b
GM
2050(defun f90-join-lines (&optional arg)
2051 "Join current line to previous, fix whitespace, continuation, comments.
a729409a 2052With optional argument ARG, join current line to following line.
a259425b
GM
2053Like `join-line', but handles F90 syntax."
2054 (interactive "*P")
2055 (beginning-of-line)
2056 (if arg (forward-line 1))
2057 (when (eq (preceding-char) ?\n)
2058 (skip-chars-forward " \t")
2059 (if (looking-at "\&") (delete-char 1))
2060 (beginning-of-line)
2061 (delete-region (point) (1- (point)))
034a9d40 2062 (skip-chars-backward " \t")
a259425b
GM
2063 (and (eq (preceding-char) ?&) (delete-char -1))
2064 (and (f90-in-comment)
2065 (looking-at "[ \t]*!+")
2066 (replace-match ""))
2067 (or (f90-in-string)
2068 (fixup-whitespace))))
034a9d40
RS
2069
2070(defun f90-fill-region (beg-region end-region)
d14e6bbe 2071 "Fill every line in region by forward parsing. Join lines if possible."
034a9d40 2072 (interactive "*r")
748dd5a8 2073 (let ((end-region-mark (copy-marker end-region))
e3f5ce56 2074 (go-on t)
640f9e26 2075 f90-smart-end f90-auto-keyword-case auto-fill-function)
034a9d40
RS
2076 (goto-char beg-region)
2077 (while go-on
ec2f376f 2078 ;; Join as much as possible.
a729409a 2079 (while (progn
a259425b
GM
2080 (end-of-line)
2081 (skip-chars-backward " \t")
2082 (eq (preceding-char) ?&))
2083 (f90-join-lines 'forward))
ec2f376f 2084 ;; Chop the line if necessary.
034a9d40 2085 (while (> (save-excursion (end-of-line) (current-column))
640f9e26
GM
2086 fill-column)
2087 (move-to-column fill-column)
2088 (f90-find-breakpoint)
2089 (f90-break-line 'no-update))
748dd5a8 2090 (setq go-on (and (< (point) end-region-mark)
e3f5ce56
GM
2091 (zerop (forward-line 1)))
2092 f90-cache-position (point)))
034a9d40 2093 (setq f90-cache-position nil)
748dd5a8 2094 (set-marker end-region-mark nil)
a445370f 2095 (if (featurep 'xemacs)
640f9e26 2096 (zmacs-deactivate-region)
034a9d40
RS
2097 (deactivate-mark))))
2098\f
2099(defun f90-block-match (beg-block beg-name end-block end-name)
2100 "Match end-struct with beg-struct and complete end-block if possible.
ec2f376f
GM
2101BEG-BLOCK is the type of block as indicated at the start (e.g., do).
2102BEG-NAME is the block start name (may be nil).
2103END-BLOCK is the type of block as indicated at the end (may be nil).
2104END-NAME is the block end name (may be nil).
034a9d40 2105Leave point at the end of line."
784d007b
GM
2106 ;; Hack to deal with the case when this is called from
2107 ;; f90-indent-region on a program block without an explicit PROGRAM
2108 ;; statement at the start. Should really be an error (?).
2109 (or beg-block (setq beg-block "program"))
6734e165 2110 (search-forward "end" (line-end-position))
034a9d40 2111 (catch 'no-match
784d007b 2112 (if (and end-block (f90-equal-symbols beg-block end-block))
748dd5a8
GM
2113 (search-forward end-block)
2114 (if end-block
2115 (progn
2116 (message "END %s does not match %s." end-block beg-block)
2117 (end-of-line)
2118 (throw 'no-match nil))
2119 (message "Inserting %s." beg-block)
2120 (insert (concat " " beg-block))))
2121 (if (f90-equal-symbols beg-name end-name)
2122 (and end-name (search-forward end-name))
2123 (cond ((and beg-name (not end-name))
2124 (message "Inserting %s." beg-name)
2125 (insert (concat " " beg-name)))
2126 ((and beg-name end-name)
2127 (message "Replacing %s with %s." end-name beg-name)
2128 (search-forward end-name)
2129 (replace-match beg-name))
2130 ((and (not beg-name) end-name)
2131 (message "Deleting %s." end-name)
2132 (search-forward end-name)
2133 (replace-match ""))))
2134 (or (looking-at "[ \t]*!") (delete-horizontal-space))))
034a9d40
RS
2135
2136(defun f90-match-end ()
ec2f376f 2137 "From an end block statement, find the corresponding block and name."
034a9d40 2138 (interactive)
748dd5a8
GM
2139 (let ((count 1)
2140 (top-of-window (window-start))
640f9e26 2141 (end-point (point))
748dd5a8 2142 (case-fold-search t)
640f9e26 2143 matching-beg beg-name end-name beg-block end-block end-struct)
5c2a80ad 2144 (when (save-excursion (beginning-of-line) (skip-chars-forward " \t0-9")
ab09adac
GM
2145 (setq end-struct (f90-looking-at-program-block-end)))
2146 (setq end-block (car end-struct)
599aeab9 2147 end-name (cadr end-struct))
5c2a80ad
GM
2148 (save-excursion
2149 (beginning-of-line)
784d007b
GM
2150 (while (and (> count 0)
2151 (not (= (line-beginning-position) (point-min))))
2152 (re-search-backward f90-blocks-re nil 'move)
e3f5ce56 2153 (beginning-of-line)
748dd5a8
GM
2154 ;; GM not a line number if continued line.
2155;;; (skip-chars-forward " \t")
2156;;; (skip-chars-forward "0-9")
e3f5ce56 2157 (skip-chars-forward " \t0-9")
6dd52caf
GM
2158 (cond ((or (f90-in-string) (f90-in-comment)))
2159 ((setq matching-beg
e3f5ce56
GM
2160 (or
2161 (f90-looking-at-do)
2162 (f90-looking-at-if-then)
2163 (f90-looking-at-where-or-forall)
2164 (f90-looking-at-select-case)
2165 (f90-looking-at-type-like)
5ab33946 2166 (f90-looking-at-associate)
e93db24a 2167 (f90-looking-at-critical)
784d007b
GM
2168 (f90-looking-at-program-block-start)
2169 ;; Interpret a single END without a block
2170 ;; start to be the END of a program block
2171 ;; without an initial PROGRAM line.
2172 (if (= (line-beginning-position) (point-min))
2173 '("program" nil))))
e3f5ce56 2174 (setq count (1- count)))
6dd52caf 2175 ((looking-at (concat "end[ \t]*" f90-blocks-re))
e3f5ce56 2176 (setq count (1+ count)))))
6dd52caf 2177 (if (> count 0)
5c2a80ad
GM
2178 (message "No matching beginning.")
2179 (f90-update-line)
2180 (if (eq f90-smart-end 'blink)
2181 (if (< (point) top-of-window)
2182 (message "Matches %s: %s"
2183 (what-line)
2184 (buffer-substring
2185 (line-beginning-position)
2186 (line-end-position)))
c046af95 2187 (sit-for blink-matching-delay)))
e3f5ce56 2188 (setq beg-block (car matching-beg)
599aeab9 2189 beg-name (cadr matching-beg))
5c2a80ad
GM
2190 (goto-char end-point)
2191 (beginning-of-line)
ab09adac 2192 (f90-block-match beg-block beg-name end-block end-name))))))
034a9d40
RS
2193
2194(defun f90-insert-end ()
87ee2359 2195 "Insert a complete end statement matching beginning of present block."
a729409a 2196 (interactive "*")
e3f5ce56 2197 (let ((f90-smart-end (or f90-smart-end 'blink)))
034a9d40
RS
2198 (insert "end")
2199 (f90-indent-new-line)))
2200\f
ec2f376f 2201;; Abbrevs and keywords.
034a9d40
RS
2202
2203(defun f90-abbrev-start ()
69658465 2204 "Typing `\\[help-command] or `? lists all the F90 abbrevs.
034a9d40 2205Any other key combination is executed normally."
7aee8047 2206 (interactive "*")
df96ab1e
SM
2207 (self-insert-command 1)
2208 (when abbrev-mode
2209 (set-temporary-overlay-map
2210 (let ((map (make-sparse-keymap)))
2211 (define-key map [??] 'f90-abbrev-help)
2212 (define-key map (vector help-char) 'f90-abbrev-help)
2213 map))))
034a9d40
RS
2214
2215(defun f90-abbrev-help ()
2216 "List the currently defined abbrevs in F90 mode."
2217 (interactive)
2218 (message "Listing abbrev table...")
2219 (display-buffer (f90-prepare-abbrev-list-buffer))
2220 (message "Listing abbrev table...done"))
2221
2222(defun f90-prepare-abbrev-list-buffer ()
ec2f376f 2223 "Create a buffer listing the F90 mode abbreviations."
5d16fdd7 2224 (with-current-buffer (get-buffer-create "*Abbrevs*")
034a9d40
RS
2225 (erase-buffer)
2226 (insert-abbrev-table-description 'f90-mode-abbrev-table t)
2227 (goto-char (point-min))
2228 (set-buffer-modified-p nil)
2229 (edit-abbrevs-mode))
2230 (get-buffer-create "*Abbrevs*"))
2231
2232(defun f90-upcase-keywords ()
2233 "Upcase all F90 keywords in the buffer."
a729409a 2234 (interactive "*")
034a9d40
RS
2235 (f90-change-keywords 'upcase-word))
2236
2237(defun f90-capitalize-keywords ()
2238 "Capitalize all F90 keywords in the buffer."
a729409a 2239 (interactive "*")
034a9d40
RS
2240 (f90-change-keywords 'capitalize-word))
2241
2242(defun f90-downcase-keywords ()
2243 "Downcase all F90 keywords in the buffer."
a729409a 2244 (interactive "*")
034a9d40
RS
2245 (f90-change-keywords 'downcase-word))
2246
2247(defun f90-upcase-region-keywords (beg end)
2248 "Upcase all F90 keywords in the region."
2249 (interactive "*r")
2250 (f90-change-keywords 'upcase-word beg end))
2251
2252(defun f90-capitalize-region-keywords (beg end)
2253 "Capitalize all F90 keywords in the region."
2254 (interactive "*r")
2255 (f90-change-keywords 'capitalize-word beg end))
2256
2257(defun f90-downcase-region-keywords (beg end)
2258 "Downcase all F90 keywords in the region."
2259 (interactive "*r")
2260 (f90-change-keywords 'downcase-word beg end))
2261
2262;; Change the keywords according to argument.
2263(defun f90-change-keywords (change-word &optional beg end)
ec2f376f 2264 "Change the case of F90 keywords in the region (if specified) or buffer.
02f85cba 2265CHANGE-WORD should be one of 'upcase-word, 'downcase-word, 'capitalize-word."
034a9d40 2266 (save-excursion
e3f5ce56
GM
2267 (setq beg (or beg (point-min))
2268 end (or end (point-max)))
69658465 2269 (let ((keyword-re
640f9e26
GM
2270 (concat "\\("
2271 f90-keywords-re "\\|" f90-procedures-re "\\|"
2272 f90-hpf-keywords-re "\\|" f90-operators-re "\\)"))
2273 (ref-point (point-min))
2274 (modified (buffer-modified-p))
e3f5ce56 2275 state saveword back-point)
034a9d40 2276 (goto-char beg)
ee30478d 2277 (unwind-protect
640f9e26
GM
2278 (while (re-search-forward keyword-re end t)
2279 (unless (progn
5c2a80ad
GM
2280 (setq state (parse-partial-sexp ref-point (point)))
2281 (or (nth 3 state) (nth 4 state)
748dd5a8 2282 ;; GM f90-directive-comment-re?
ec2f376f 2283 (save-excursion ; check for cpp directive
5c2a80ad
GM
2284 (beginning-of-line)
2285 (skip-chars-forward " \t0-9")
2286 (looking-at "#"))))
640f9e26
GM
2287 (setq ref-point (point)
2288 back-point (save-excursion (backward-word 1) (point))
e3f5ce56 2289 saveword (buffer-substring back-point ref-point))
640f9e26
GM
2290 (funcall change-word -1)
2291 (or (string= saveword (buffer-substring back-point ref-point))
2292 (setq modified t))))
5d16fdd7 2293 (or modified (restore-buffer-modified-p nil))))))
034a9d40 2294
d2d15846
DL
2295
2296(defun f90-current-defun ()
2297 "Function to use for `add-log-current-defun-function' in F90 mode."
2298 (save-excursion
2299 (nth 1 (f90-beginning-of-subprogram))))
2300
784d007b
GM
2301(defun f90-backslash-not-special (&optional all)
2302 "Make the backslash character (\\) be non-special in the current buffer.
2303With optional argument ALL, change the default for all present
2304and future F90 buffers. F90 mode normally treats backslash as an
2305escape character."
175069ef 2306 (or (derived-mode-p 'f90-mode)
784d007b
GM
2307 (error "This function should only be used in F90 buffers"))
2308 (when (equal (char-syntax ?\\ ) ?\\ )
2309 (or all (set-syntax-table (copy-syntax-table (syntax-table))))
2310 (modify-syntax-entry ?\\ ".")))
2311
2312
034a9d40 2313(provide 'f90)
db97b872 2314
239da61d
GM
2315;; Local Variables:
2316;; coding: utf-8
239da61d
GM
2317;; End:
2318
034a9d40 2319;;; f90.el ends here