1;;; fortran.el --- Fortran mode for GNU Emacs 2 3;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 4;; 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 5 6;; Author: Michael D. Prange <prange@erl.mit.edu> 7;; Maintainer: Glenn Morris <rgm@gnu.org> 8;; Keywords: fortran, languages 9 10;; This file is part of GNU Emacs. 11 12;; GNU Emacs is free software; you can redistribute it and/or modify 13;; it under the terms of the GNU General Public License as published by 14;; the Free Software Foundation; either version 2, or (at your option) 15;; any later version. 16 17;; GNU Emacs is distributed in the hope that it will be useful, 18;; but WITHOUT ANY WARRANTY; without even the implied warranty of 19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20;; GNU General Public License for more details. 21 22;; You should have received a copy of the GNU General Public License 23;; along with GNU Emacs; see the file COPYING. If not, write to the 24;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 25;; Boston, MA 02110-1301, USA. 26 27;;; Commentary: 28 29;; This mode is documented in the Emacs manual. 30;; 31;; Note that it is for editing Fortran77 or Fortran90 fixed source 32;; form. For editing Fortran 90 free format source, use `f90-mode' 33;; (f90.el). It is meant to support the GNU Fortran language 34;; implemented by g77 (its extensions to Fortran77 and 35;; interpretations, e.g. of blackslash in strings). 36 37;;; History: 38 39;; Fortran mode was upgraded by Stephen A. Wood (saw@cebaf.gov). 40 41;; We acknowledge many contributions and valuable suggestions by 42;; Lawrence R. Dodd, Ralf Fassel, Ralph Finch, Stephen Gildea, 43;; Dr. Anil Gokhale, Ulrich Mueller, Mark Neale, Eric Prestemon, 44;; Gary Sabot and Richard Stallman. 45 46;;; Code: 47 48;; Todo: 49 50;; * Tidy it all up (more)! 51;; * Implement insertion and removal of statement continuations in 52;; mixed f77/f90 style, with the first `&' past column 72 and the 53;; second in column 6. 54;; * Support any other extensions to f77 grokked by GNU Fortran I've missed. 55 56;; silence compiler 57(defvar dabbrev-case-fold-search) 58(defvar font-lock-syntactic-keywords) 59(defvar gud-find-expr-function) 60(defvar imenu-case-fold-search) 61(defvar imenu-syntax-alist) 62 63 64(defgroup fortran nil 65 "Major mode for editing fixed format Fortran code." 66 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) 67 :link '(custom-manual "(emacs)Fortran") 68 :group 'languages) 69 70(defgroup fortran-indent nil 71 "Indentation variables in Fortran mode." 72 :prefix "fortran-" 73 :group 'fortran) 74 75(defgroup fortran-comment nil 76 "Comment-handling variables in Fortran mode." 77 :prefix "fortran-" 78 :group 'fortran) 79 80 81;;;###autoload 82(defcustom fortran-tab-mode-default nil 83 "*Default tabbing/carriage control style for empty files in Fortran mode. 84A non-nil value specifies tab-digit style of continuation control. 85A value of nil specifies that continuation lines are marked 86with a character in column 6." 87 :type 'boolean 88 :group 'fortran-indent) 89 90(defcustom fortran-tab-mode-string "/t" 91 "*String to appear in mode line in TAB format buffers." 92 :type 'string 93 :group 'fortran-indent) 94 95(defcustom fortran-do-indent 3 96 "*Extra indentation applied to DO blocks." 97 :type 'integer 98 :group 'fortran-indent) 99 100(defcustom fortran-if-indent 3 101 "*Extra indentation applied to IF, SELECT CASE and WHERE blocks." 102 :type 'integer 103 :group 'fortran-indent) 104 105(defcustom fortran-structure-indent 3 106 "*Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks." 107 :type 'integer 108 :group 'fortran-indent) 109 110(defcustom fortran-continuation-indent 5 111 "*Extra indentation applied to continuation lines." 112 :type 'integer 113 :group 'fortran-indent) 114 115(defcustom fortran-comment-indent-style 'fixed 116 "*How to indent comments. 117nil forces comment lines not to be touched; 118`fixed' indents to `fortran-comment-line-extra-indent' columns beyond 119 `fortran-minimum-statement-indent-fixed' (if `indent-tabs-mode' nil), or 120 `fortran-minimum-statement-indent-tab' (if `indent-tabs-mode' non-nil); 121`relative' indents to current Fortran indentation plus 122 `fortran-comment-line-extra-indent'." 123 :type '(radio (const :tag "Untouched" nil) (const fixed) (const relative)) 124 :group 'fortran-indent) 125 126(defcustom fortran-comment-line-extra-indent 0 127 "*Amount of extra indentation for text within full-line comments." 128 :type 'integer 129 :group 'fortran-indent 130 :group 'fortran-comment) 131 132(defcustom fortran-comment-line-start "C" 133 "*Delimiter inserted to start new full-line comment. 134You might want to change this to \"*\", for instance." 135 :version "21.1" 136 :type 'string 137 :group 'fortran-comment) 138 139;; This used to match preprocessor lines too, but that messes up 140;; filling and doesn't seem to be necessary. 141(defcustom fortran-comment-line-start-skip 142 "^[CcDd*!]\\(\\([^ \t\n]\\)\\2+\\)?[ \t]*" 143 "*Regexp to match the start of a full-line comment." 144 :version "21.1" 145 :type 'regexp 146 :group 'fortran-comment) 147 148(defcustom fortran-directive-re 149 "^[ \t]*#.*" 150 "*Regexp to match a directive line. 151The matching text will be fontified with `font-lock-keyword-face'. 152The matching line will be given zero indentation." 153 :version "22.1" 154 :type 'regexp 155 :group 'fortran-indent) 156 157(defcustom fortran-minimum-statement-indent-fixed 6 158 "*Minimum statement indentation for fixed format continuation style." 159 :type 'integer 160 :group 'fortran-indent) 161 162(defcustom fortran-minimum-statement-indent-tab (max tab-width 6) 163 "*Minimum statement indentation for TAB format continuation style." 164 :type 'integer 165 :group 'fortran-indent) 166 167;; Note that this is documented in the v18 manuals as being a string 168;; of length one rather than a single character. 169;; The code in this file accepts either format for compatibility. 170(defcustom fortran-comment-indent-char " " 171 "*Single-character string inserted for Fortran comment indentation. 172Normally a space." 173 :type 'string 174 :group 'fortran-comment) 175 176(defcustom fortran-line-number-indent 1 177 "*Maximum indentation for Fortran line numbers. 1785 means right-justify them within their five-column field." 179 :type 'integer 180 :group 'fortran-indent) 181 182(defcustom fortran-check-all-num-for-matching-do nil 183 "*Non-nil causes all numbered lines to be treated as possible DO loop ends." 184 :type 'boolean 185 :group 'fortran) 186 187(defcustom fortran-blink-matching-if nil 188 "*Non-nil causes \\[fortran-indent-line] on ENDIF to blink on matching IF. 189Also, from an ENDDO statement blink on matching DO [WHILE] statement." 190 :type 'boolean 191 :group 'fortran) 192 193(defcustom fortran-continuation-string "$" 194 "*Single-character string used for Fortran continuation lines. 195In fixed format continuation style, this character is inserted in 196column 6 by \\[fortran-split-line] to begin a continuation line. 197Also, if \\[fortran-indent-line] finds this at the beginning of a 198line, it will convert the line into a continuation line of the 199appropriate style. Normally $." 200 :type 'string 201 :group 'fortran) 202 203(defcustom fortran-comment-region "c$$$" 204 "*String inserted by \\[fortran-comment-region] at start of each \ 205line in region." 206 :type 'string 207 :group 'fortran-comment) 208 209(defcustom fortran-electric-line-number t 210 "*Non-nil causes line numbers to be moved to the correct column as typed." 211 :type 'boolean 212 :group 'fortran) 213 214(defcustom fortran-column-ruler-fixed 215 "0 4 6 10 20 30 40 5\ 2160 60 70\n\ 217\[ ]|{ | | | | | | | | \ 218\| | | | |}\n" 219 "String displayed above current line by \\[fortran-column-ruler]. 220This variable is used in fixed format mode. 221See the variable `fortran-column-ruler-tab' for TAB format mode." 222 :type 'string 223 :group 'fortran) 224 225(defcustom fortran-column-ruler-tab 226 "0 810 20 30 40 5\ 2270 60 70\n\ 228\[ ]| { | | | | | | | | \ 229\| | | | |}\n" 230 "String displayed above current line by \\[fortran-column-ruler]. 231This variable is used in TAB format mode. 232See the variable `fortran-column-ruler-fixed' for fixed format mode." 233 :type 'string 234 :group 'fortran) 235 236(defcustom fortran-analyze-depth 100 237 "Number of lines to scan to identify fixed or TAB format style." 238 :type 'integer 239 :group 'fortran) 240 241(defcustom fortran-break-before-delimiters t 242 "*Non-nil causes filling to break lines before delimiters. 243Delimiters are characters matching the regexp `fortran-break-delimiters-re'." 244 :type 'boolean 245 :group 'fortran) 246 247(defconst fortran-break-delimiters-re "[-+*/><=, \t]" 248 "Regexp matching delimiter characters at which lines may be broken. 249There are certain tokens comprised entirely of characters 250matching this regexp that should not be split, and these are 251specified by the constant `fortran-no-break-re'.") 252 253;; The ">=", etc F77 extensions are supported by g77. 254(defconst fortran-no-break-re 255 (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=") 'paren) 256 "Regexp specifying where not to break lines when filling. 257This regexp matches certain tokens comprised entirely of 258characters matching the regexp `fortran-break-delimiters-re' that should 259not be split by filling. Each element is assumed to be two 260characters long.") 261 262(defcustom fortran-mode-hook nil 263 "Hook run when entering Fortran mode." 264 :type 'hook 265 :group 'fortran) 266 267 268(defvar fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(" 269 "Regexp matching the start of an IF statement.") 270 271(defvar fortran-end-prog-re1 272 "end\ 273\\([ \t]*\\(program\\|subroutine\\|function\\|block[ \t]*data\\)\\>\ 274\\([ \t]*\\(\\sw\\|\\s_\\)+\\)?\\)?" 275 "Regexp possibly matching the end of a subprogram.") 276 277(defvar fortran-end-prog-re 278 (concat "^[ \t0-9]*" fortran-end-prog-re1) 279 "Regexp possibly matching the end of a subprogram, from the line start. 280See also `fortran-end-prog-re1'.") 281 282(defconst fortran-type-types 283 (concat "\\<" 284 (mapconcat 'identity ; " " -> "[ \t]*" 285 (split-string 286 (regexp-opt 287 (let ((simple-types 288 '("character" "byte" "integer" "logical" 289 "none" "real" "complex" 290 "double precision" "double complex")) 291 (structured-types '("structure" "union" "map")) 292 (other-types '("record" "dimension" 293 "parameter" "common" "save" 294 "external" "intrinsic" "data" 295 "equivalence"))) 296 (append 297 (mapcar (lambda (x) (concat "implicit " x)) 298 simple-types) 299 simple-types 300 (mapcar (lambda (x) (concat "end " x)) 301 structured-types) 302 structured-types 303 other-types)) 'paren)) 304 "[ \t]*") "\\>") 305 "Regexp matching Fortran types.") 306 307(defvar fortran-font-lock-keywords-1 308 ;; Program, subroutine and function declarations, plus calls. 309 '(("\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|\ 310program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?" 311 (1 font-lock-keyword-face) 312 (2 font-lock-function-name-face nil t))) 313 "Subdued level highlighting for Fortran mode.") 314 315(defvar fortran-font-lock-keywords-2 316 (append fortran-font-lock-keywords-1 317 (list 318 ;; Fontify all type specifiers (must be first - see below). 319 (cons fortran-type-types 'font-lock-type-face) 320 ;; Builtin keywords (except logical, do and goto - see below). 321 (concat "\\<" (regexp-opt 322 '("continue" "format" "end" "enddo" 323 "if" "then" "else" "endif" "elseif" 324 "while" "inquire" "stop" "return" 325 "include" "open" "close" "read" 326 "write" "format" "print" "select" "case" 327 "cycle" "exit" "rewind" "backspace" 328 "where" "elsewhere") 329 'paren) "\\>") 330 ;; Builtin operators. 331 (concat "\\." (regexp-opt 332 '("and" "or" "not" "lt" "le" "eq" "ge" 333 "gt" "ne" "true" "false") 334 'paren) "\\.") 335 ;; do/goto keywords and targets, and goto tags. 336 '("\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?" 337 (1 font-lock-keyword-face) 338 (2 font-lock-constant-face nil t)) 339 '("^ *\\([0-9]+\\)" . font-lock-constant-face))) 340 "Medium level highlighting for Fortran mode.") 341 342(defvar fortran-font-lock-keywords-3 343 (append 344 fortran-font-lock-keywords-1 345 ;; All type specifiers plus their declared items. 346 (list 347 (list (concat fortran-type-types "[ \t(/]*\\(*\\)?") 348 ;; Type specifier. 349 '(1 font-lock-type-face) 350 ;; Declaration item (or just /.../ block name). 351 `(font-lock-match-c-style-declaration-item-and-skip-to-next 352 ;; Start after any *(...) expression. 353 (condition-case nil 354 (and (match-beginning ,(1+ (regexp-opt-depth 355 fortran-type-types))) 356 (forward-sexp) 357 (forward-sexp)) 358 (error nil)) 359 ;; No need to clean up. 360 nil 361 ;; Fontify as a variable name, functions fontified elsewhere. 362 (1 font-lock-variable-name-face nil t)))) 363 ;; Things extra to `fortran-font-lock-keywords-3' (must be done first). 364 (list 365 ;; Goto-like `err=label'/`end=label' in read/write statements. 366 '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?" 367 (1 font-lock-keyword-face) (4 font-lock-constant-face nil t)) 368 ;; Standard continuation character and in a TAB-formatted line. 369 '("^ \\{5\\}\\([^ 0\n]\\)" 1 font-lock-string-face) 370 '("^\t\\([1-9]\\)" 1 font-lock-string-face)) 371 `((,fortran-directive-re (0 font-lock-keyword-face t))) 372 ;; `fortran-font-lock-keywords-2' without types (see above). 373 (cdr (nthcdr (length fortran-font-lock-keywords-1) 374 fortran-font-lock-keywords-2))) 375 "Gaudy level highlighting for Fortran mode.") 376 377(defvar fortran-font-lock-keywords-4 378 (append fortran-font-lock-keywords-3 379 (list (list 380 (concat "\\<" 381 (regexp-opt 382 '("int" "ifix" "idint" "real" "float" "sngl" 383 "dble" "cmplx" "ichar" "char" "aint" "dint" 384 "anint" "dnint" "nint" "idnint" "iabs" "abs" 385 "dabs" "cabs" "mod" "amod" "dmod" "isign" 386 "sign" "dsign" "idim" "dim" "ddim" "dprod" 387 "max" "max0" "amax1" "dmax1" "amax0" "max1" 388 "min" "min0" "amin1" "dmin1" "amin0" "min1" 389 "len" "index" "lge" "lgt" "lle" "llt" "aimag" 390 "conjg" "sqrt" "dsqrt" "csqrt" "exp" "dexp" 391 "cexp" "log" "alog" "dlog" "clog" "log10" 392 "alog10" "dlog10" "sin" "dsin" "csin" "cos" 393 "dcos" "ccos" "tan" "dtan" "asin" "dasin" 394 "acos" "dacos" "atan" "datan" "atan2" "datan2" 395 "sinh" "dsinh" "cosh" "dcosh" "tanh" "dtanh") 396 'paren) "[ \t]*(") '(1 font-lock-builtin-face)))) 397 "Maximum highlighting for Fortran mode. 398Consists of level 3 plus all other intrinsics not already highlighted.") 399 400;; Comments are real pain in Fortran because there is no way to 401;; represent the standard comment syntax in an Emacs syntax table. 402;; (We can do so for F90-style). Therefore an unmatched quote in a 403;; standard comment will throw fontification off on the wrong track. 404;; So we do syntactic fontification with regexps. 405(defvar fortran-font-lock-syntactic-keywords 406 '(("^[cd\\*]" 0 (11)) 407 ("^[^cd\\*\t\n].\\{71\\}\\([^\n]+\\)" 1 (11))) 408 "`font-lock-syntactic-keywords' for Fortran. 409These get fixed-format comments fontified.") 410 411(defvar fortran-font-lock-keywords fortran-font-lock-keywords-1 412 "Default expressions to highlight in Fortran mode.") 413 414(defvar fortran-imenu-generic-expression 415 ;; These patterns could be confused by sequence nos. in cols 72+ and 416 ;; don't allow continuations everywhere. 417 (list 418 (list 419 nil 420 ;; [This will be fooled by `end function' allowed by G77. Also, 421 ;; it assumes sensible whitespace is employed.] 422 (concat 423 ;; leading whitespace: 424 "^\\s-+\\(" 425 ;; function declaration with optional type, e.g. `real', 426 ;; `real*4', character(*), `double precision': 427 "\\(\\sw\\|\\s-\\|[*()+]\\)*" 428 "\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)" 429 ;; Possible statement continuation: 430 "[ \t" fortran-continuation-string "]+" 431 ;; Variable to index: 432 "\\(\\sw+\\)") 433 3) 434 ;; Un-named block data. 435 '(nil "^\\s-+\\(block\\s-*data\\)\\s-*$" 1)) 436 "Value for `imenu-generic-expression' in Fortran mode.") 437 438 439;; Hideshow support. 440(defconst fortran-blocks-re 441 (concat "block[ \t]*data\\|select[ \t]*case\\|" 442 (regexp-opt '("do" "if" "interface" "function" "map" "program" 443 "structure" "subroutine" "union" "where"))) 444 "Regexp potentially indicating the start or end of a Fortran \"block\". 445Omits naked END statements, and DO-loops closed by anything other 446than ENDDO.") 447 448(defconst fortran-end-block-re 449 ;; Do-loops terminated by things other than ENDDO cannot be handled 450 ;; with a regexp. This omission does not seem to matter to hideshow... 451 (concat "^[ \t0-9]*\\<end[ \t]*\\(" 452 fortran-blocks-re 453 ;; Naked END statement. 454 "\\|!\\|$\\)") 455 "Regexp matching the end of a Fortran \"block\", from the line start. 456Note that only ENDDO is handled for the end of a DO-loop. Used 457in the Fortran entry in `hs-special-modes-alist'.") 458 459(defconst fortran-start-block-re 460 (concat 461 "^[ \t0-9]*\\(" ; statement number 462 ;; Structure label for DO, IF, SELECT, WHERE. 463 "\\(\\(\\sw+[ \t]*:[ \t]*\\)?" 464 ;; IF blocks are a nuisance: 465 ;; IF ( ... ) foo is not a block, but a single statement. 466 ;; IF ( ... ) THEN can be split over multiple lines. 467 ;; [So can, eg, a DO WHILE (... ), but that is less common, I hope.] 468 ;; The regexp below allows for it to be split over at most 2 lines. 469 ;; That leads to the problem of not matching two consecutive IF 470 ;; statements as one, eg: 471 ;; IF ( ... ) foo 472 ;; IF ( ... ) THEN 473 ;; It simply is not possible to do this in a 100% correct fashion 474 ;; using a regexp - see the functions fortran-end-if, 475 ;; fortran-beginning-if for the hoops we have to go through. 476 ;; An alternative is to match on THEN at a line end, eg: 477 ;; ".*)[ \t]*then[ \t]*\\($\\|!\\)" 478 ;; This would also match ELSE branches, though. This does not seem 479 ;; right to me, because then one has neighbouring blocks that are 480 ;; not nested in each other. 481 "\\(if[ \t]*(\\(.*\\|" 482 ".*\n\\([^if]*\\([^i].\\|.[^f]\\|.\\>\\)\\)\\)\\<then\\|" 483 "do\\|select[ \t]*case\\|where\\)\\)\\|" 484 (regexp-opt '("interface" "function" "map" "program" 485 "structure" "subroutine" "union")) 486 "\\|block[ \t]*data\\)[ \t]*") 487 "Regexp matching the start of a Fortran \"block\", from the line start. 488A simple regexp cannot do this in fully correct fashion, so this 489tries to strike a compromise between complexity and flexibility. 490Used in the Fortran entry in `hs-special-modes-alist'.") 491 492(add-to-list 'hs-special-modes-alist 493 `(fortran-mode ,fortran-start-block-re ,fortran-end-block-re 494 "^[cC*!]" fortran-end-of-block nil)) 495 496 497(defvar fortran-mode-syntax-table 498 (let ((table (make-syntax-table))) 499 ;; We might like `;' to be punctuation (g77 multi-statement 500 ;; lines), but that screws abbrevs. 501 (modify-syntax-entry ?\; "w" table) 502 (modify-syntax-entry ?\r " " table) 503 (modify-syntax-entry ?+ "." table) 504 (modify-syntax-entry ?- "." table) 505 (modify-syntax-entry ?= "." table) 506 (modify-syntax-entry ?* "." table) 507 (modify-syntax-entry ?/ "." table) 508 (modify-syntax-entry ?\' "\"" table) 509 (modify-syntax-entry ?\" "\"" table) 510 ;; Consistent with GNU Fortran's default -- see the manual. 511 ;; The F77 standard imposes no rule on this issue. 512 (modify-syntax-entry ?\\ "\\" table) 513 ;; This might be better as punctuation, as for C, but this way you 514 ;; can treat floating-point numbers as symbols. 515 (modify-syntax-entry ?. "_" table) ; e.g. `a.ne.b' 516 (modify-syntax-entry ?_ "_" table) 517 (modify-syntax-entry ?$ "_" table) ; esp. VMSisms 518 (modify-syntax-entry ?\! "<" table) 519 (modify-syntax-entry ?\n ">" table) 520 table) 521 "Syntax table used in Fortran mode.") 522 523(defvar fortran-gud-syntax-table 524 (let ((st (make-syntax-table fortran-mode-syntax-table))) 525 (modify-syntax-entry ?\n "." st) 526 st) 527 "Syntax table used to parse Fortran expressions for printing in GUD.") 528 529(defvar fortran-mode-map 530 (let ((map (make-sparse-keymap))) 531 (define-key map ";" 'fortran-abbrev-start) 532 (define-key map "\C-c;" 'fortran-comment-region) 533 (define-key map "\M-;" 'fortran-indent-comment) 534 (define-key map "\M-\n" 'fortran-split-line) 535 (define-key map "\M-\C-n" 'fortran-end-of-block) 536 (define-key map "\M-\C-p" 'fortran-beginning-of-block) 537 (define-key map "\M-\C-q" 'fortran-indent-subprogram) 538 (define-key map "\C-c\C-w" 'fortran-window-create-momentarily) 539 (define-key map "\C-c\C-r" 'fortran-column-ruler) 540 (define-key map "\C-c\C-p" 'fortran-previous-statement) 541 (define-key map "\C-c\C-n" 'fortran-next-statement) 542 (define-key map "\C-c\C-d" 'fortran-join-line) ; like f90 543 (define-key map "\M-^" 'fortran-join-line) ; subvert delete-indentation 544 (define-key map "0" 'fortran-electric-line-number) 545 (define-key map "1" 'fortran-electric-line-number) 546 (define-key map "2" 'fortran-electric-line-number) 547 (define-key map "3" 'fortran-electric-line-number) 548 (define-key map "4" 'fortran-electric-line-number) 549 (define-key map "5" 'fortran-electric-line-number) 550 (define-key map "6" 'fortran-electric-line-number) 551 (define-key map "7" 'fortran-electric-line-number) 552 (define-key map "8" 'fortran-electric-line-number) 553 (define-key map "9" 'fortran-electric-line-number) 554 555 (easy-menu-define fortran-menu map "Menu for Fortran mode." 556 `("Fortran" 557 ["Manual" (info "(emacs)Fortran")] 558 ("Customization" 559 ,(custom-menu-create 'fortran) 560 ["Set" Custom-set t] 561 ["Save" Custom-save t] 562 ["Reset to Current" Custom-reset-current t] 563 ["Reset to Saved" Custom-reset-saved t] 564 ["Reset to Standard Settings" Custom-reset-standard t] 565 ) 566 "--" 567 ["Comment Region" fortran-comment-region mark-active] 568 ["Uncomment Region" 569 (fortran-comment-region (region-beginning) (region-end) 1) 570 mark-active] 571 ["Indent Region" indent-region mark-active] 572 ["Indent Subprogram" fortran-indent-subprogram t] 573 "--" 574 ["Beginning of Subprogram" fortran-beginning-of-subprogram t] 575 ["End of Subprogram" fortran-end-of-subprogram t] 576 ("Mark" 577 ["Subprogram" mark-defun t] 578 ["IF Block" fortran-mark-if t] 579 ["DO Block" fortran-mark-do t] 580 ) 581 ["Narrow to Subprogram" narrow-to-defun t] 582 ["Widen" widen t] 583 "--" 584 ["Temporary column ruler" fortran-column-ruler t] 585 ["72-column window" fortran-window-create t] 586 ["Full Width Window" 587 (enlarge-window-horizontally (- (frame-width) (window-width))) 588 (< (window-width) (frame-width))] 589 ["Momentary 72-column window" fortran-window-create-momentarily t] 590 "--" 591 ["Break Line at Point" fortran-split-line t] 592 ["Join Line" fortran-join-line t] 593 ["Fill Statement/Comment" fill-paragraph t] 594 "--" 595 ["Toggle auto-fill" auto-fill-mode :selected auto-fill-function 596 :style toggle] 597 ["Toggle abbrev-mode" abbrev-mode :selected abbrev-mode 598 :style toggle] 599 ["Add imenu Menu" imenu-add-menubar-index 600 :active (not (lookup-key (current-local-map) [menu-bar index])) 601 :included (fboundp 'imenu-add-to-menubar)])) 602 map) 603 "Keymap used in Fortran mode.") 604 605 606(defvar fortran-mode-abbrev-table 607 (progn 608 (define-abbrev-table 'fortran-mode-abbrev-table nil) 609 fortran-mode-abbrev-table) 610 "Abbrev table for Fortran mode.") 611 612(let (abbrevs-changed) 613 ;; Use the 6th arg (SYSTEM-FLAG) of define-abbrev if possible. 614 ;; Only use `apply' to quieten the byte-compiler. 615 (mapcar 616 (function (lambda (element) 617 (condition-case nil 618 (apply 'define-abbrev fortran-mode-abbrev-table 619 (append element '(nil 0 t))) 620 (wrong-number-of-arguments 621 (apply 'define-abbrev fortran-mode-abbrev-table 622 (append element '(nil 0))))))) 623 '((";au" "automatic" ) 624 (";b" "byte" ) 625 (";bd" "block data" ) 626 (";ch" "character" ) 627 (";cl" "close" ) 628 (";c" "continue" ) 629 (";cm" "common" ) 630 (";cx" "complex" ) 631 (";df" "define" ) 632 (";di" "dimension" ) 633 (";do" "double" ) 634 (";dc" "double complex" ) 635 (";dp" "double precision" ) 636 (";dw" "do while" ) 637 (";e" "else" ) 638 (";ed" "enddo" ) 639 (";el" "elseif" ) 640 (";en" "endif" ) 641 (";eq" "equivalence" ) 642 (";ew" "endwhere" ) 643 (";ex" "external" ) 644 (";ey" "entry" ) 645 (";f" "format" ) 646 (";fa" ".false." ) 647 (";fu" "function" ) 648 (";g" "goto" ) 649 (";im" "implicit" ) 650 (";ib" "implicit byte" ) 651 (";ic" "implicit complex" ) 652 (";ich" "implicit character") 653 (";ii" "implicit integer" ) 654 (";il" "implicit logical" ) 655 (";ir" "implicit real" ) 656 (";inc" "include" ) 657 (";in" "integer" ) 658 (";intr" "intrinsic" ) 659 (";l" "logical" ) 660 (";n" "namelist" ) 661 (";o" "open" ) ; was ;op 662 (";pa" "parameter" ) 663 (";pr" "program" ) 664 (";ps" "pause" ) 665 (";p" "print" ) 666 (";rc" "record" ) 667 (";re" "real" ) 668 (";r" "read" ) 669 (";rt" "return" ) 670 (";rw" "rewind" ) 671 (";s" "stop" ) 672 (";sa" "save" ) 673 (";st" "structure" ) 674 (";sc" "static" ) 675 (";su" "subroutine" ) 676 (";tr" ".true." ) 677 (";ty" "type" ) 678 (";vo" "volatile" ) 679 (";w" "write" ) 680 (";wh" "where" )))) 681 682 683;;;###autoload 684(defun fortran-mode () 685 "Major mode for editing Fortran code in fixed format. 686For free format code, use `f90-mode'. 687 688\\[fortran-indent-line] indents the current Fortran line correctly. 689Note that DO statements must not share a common CONTINUE. 690 691Type ;? or ;\\[help-command] to display a list of built-in abbrevs for\ 692 Fortran keywords. 693 694Key definitions: 695\\{fortran-mode-map} 696 697Variables controlling indentation style and extra features: 698 699`fortran-comment-line-start' 700 To use comments starting with `!', set this to the string \"!\". 701`fortran-do-indent' 702 Extra indentation within DO blocks (default 3). 703`fortran-if-indent' 704 Extra indentation within IF blocks (default 3). 705`fortran-structure-indent' 706 Extra indentation within STRUCTURE, UNION, MAP and INTERFACE blocks. 707 (default 3) 708`fortran-continuation-indent' 709 Extra indentation applied to continuation statements (default 5). 710`fortran-comment-line-extra-indent' 711 Amount of extra indentation for text in full-line comments (default 0). 712`fortran-comment-indent-style' 713 How to indent the text in full-line comments. Allowed values are: 714 nil don't change the indentation 715 fixed indent to `fortran-comment-line-extra-indent' beyond the 716 value of either 717 `fortran-minimum-statement-indent-fixed' (fixed format) or 718 `fortran-minimum-statement-indent-tab' (TAB format), 719 depending on the continuation format in use. 720 relative indent to `fortran-comment-line-extra-indent' beyond the 721 indentation for a line of code. 722 (default 'fixed) 723`fortran-comment-indent-char' 724 Single-character string to be inserted instead of space for 725 full-line comment indentation (default \" \"). 726`fortran-minimum-statement-indent-fixed' 727 Minimum indentation for statements in fixed format mode (default 6). 728`fortran-minimum-statement-indent-tab' 729 Minimum indentation for statements in TAB format mode (default 9). 730`fortran-line-number-indent' 731 Maximum indentation for line numbers (default 1). A line number will 732 get less than this much indentation if necessary to avoid reaching 733 column 5. 734`fortran-check-all-num-for-matching-do' 735 Non-nil causes all numbered lines to be treated as possible \"continue\" 736 statements (default nil). 737`fortran-blink-matching-if' 738 Non-nil causes \\[fortran-indent-line] on an ENDIF (or ENDDO) statement 739 to blink on the matching IF (or DO [WHILE]). (default nil) 740`fortran-continuation-string' 741 Single-character string to be inserted in column 5 of a continuation 742 line (default \"$\"). 743`fortran-comment-region' 744 String inserted by \\[fortran-comment-region] at start of each line in 745 the region (default \"c$$$\"). 746`fortran-electric-line-number' 747 Non-nil causes line number digits to be moved to the correct column 748 as typed (default t). 749`fortran-break-before-delimiters' 750 Non-nil causes lines to be broken before delimiters (default t). 751 752Turning on Fortran mode calls the value of the variable `fortran-mode-hook' 753with no args, if that value is non-nil." 754 (interactive) 755 (kill-all-local-variables) 756 (setq major-mode 'fortran-mode 757 mode-name "Fortran" 758 local-abbrev-table fortran-mode-abbrev-table) 759 (set-syntax-table fortran-mode-syntax-table) 760 (use-local-map fortran-mode-map) 761 (set (make-local-variable 'indent-line-function) 'fortran-indent-line) 762 (set (make-local-variable 'indent-region-function) 763 (lambda (start end) 764 (let (fortran-blink-matching-if ; avoid blinking delay 765 indent-region-function) 766 (indent-region start end nil)))) 767 (set (make-local-variable 'require-final-newline) mode-require-final-newline) 768 ;; The syntax tables don't understand the column-0 comment-markers. 769 (set (make-local-variable 'comment-use-syntax) nil) 770 (set (make-local-variable 'comment-padding) "$$$") 771 (set (make-local-variable 'comment-start) fortran-comment-line-start) 772 (set (make-local-variable 'comment-start-skip) 773 ;; We can't reuse `fortran-comment-line-start-skip' directly because 774 ;; it contains backrefs whereas we need submatch-1 to end at the 775 ;; beginning of the comment delimiter. 776 ;; (concat "\\(\\)\\(![ \t]*\\|" fortran-comment-line-start-skip "\\)") 777 "\\(\\)\\(?:^[CcDd*]\\|!\\)\\(?:\\([^ \t\n]\\)\\2+\\)?[ \t]*") 778 (set (make-local-variable 'comment-indent-function) 'fortran-comment-indent) 779 (set (make-local-variable 'abbrev-all-caps) t) 780 (set (make-local-variable 'normal-auto-fill-function) 'fortran-auto-fill) 781 (set (make-local-variable 'indent-tabs-mode) (fortran-analyze-file-format)) 782 (setq mode-line-process '(indent-tabs-mode fortran-tab-mode-string)) 783 (set (make-local-variable 'fill-column) 72) 784 (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph) 785 (set (make-local-variable 'font-lock-defaults) 786 '((fortran-font-lock-keywords 787 fortran-font-lock-keywords-1 788 fortran-font-lock-keywords-2 789 fortran-font-lock-keywords-3 790 fortran-font-lock-keywords-4) 791 nil t ((?/ . "$/") ("_$" . "w")) 792 fortran-beginning-of-subprogram)) 793 (set (make-local-variable 'font-lock-syntactic-keywords) 794 fortran-font-lock-syntactic-keywords) 795 (set (make-local-variable 'imenu-case-fold-search) t) 796 (set (make-local-variable 'imenu-generic-expression) 797 fortran-imenu-generic-expression) 798 (set (make-local-variable 'imenu-syntax-alist) '(("_$" . "w"))) 799 (set (make-local-variable 'beginning-of-defun-function) 800 #'fortran-beginning-of-subprogram) 801 (set (make-local-variable 'end-of-defun-function) 802 #'fortran-end-of-subprogram) 803 (set (make-local-variable 'add-log-current-defun-function) 804 #'fortran-current-defun) 805 (set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search) 806 (set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr) 807 (run-mode-hooks 'fortran-mode-hook)) 808 809 810(defun fortran-gud-find-expr () 811 ;; Consider \n as punctuation (end of expression). 812 (with-syntax-table fortran-gud-syntax-table 813 (gud-find-c-expr))) 814 815(defsubst fortran-comment-indent () 816 "Return the indentation appropriate for the current comment line. 817This is 0 for a line matching `fortran-comment-line-start-skip', else 818the value of `comment-column' (leaving at least one space after code)." 819 (if (looking-at fortran-comment-line-start-skip) 0 820 (save-excursion 821 (skip-chars-backward " \t") 822 (max (1+ (current-column)) comment-column)))) 823 824(defun fortran-indent-comment () 825 "Align or create comment on current line. 826Existing comments of all types are recognized and aligned. 827If the line has no comment, a side-by-side comment is inserted and aligned, 828if the value of `comment-start' is not nil and allows such comments. 829Otherwise, a separate-line comment is inserted, on this line 830or on a new line inserted before this line if this line is not blank." 831 (interactive "*") 832 (beginning-of-line) 833 ;; Recognize existing comments of either kind. 834 (cond ((fortran-find-comment-start-skip 'all) 835 (goto-char (match-beginning 0)) 836 (if (bolp) 837 (fortran-indent-line) 838 (unless (= (current-column) (fortran-comment-indent)) 839 (delete-horizontal-space) 840 (indent-to (fortran-comment-indent))))) 841 ;; No existing comment. 842 ;; If side-by-side comments are defined, insert one, 843 ;; unless line is now blank. 844 ((and comment-start (not (looking-at "[ \t]*$")) 845 (string-match comment-start-skip (concat " " comment-start))) 846 (end-of-line) 847 (delete-horizontal-space) 848 (indent-to (fortran-comment-indent)) 849 (insert comment-start)) 850 ;; Else insert separate-line comment, making a new line if nec. 851 (t 852 (if (looking-at "^[ \t]*$") 853 (delete-horizontal-space) 854 (beginning-of-line) 855 (insert ?\n) 856 (forward-char -1)) 857 (insert fortran-comment-line-start) 858 (insert-char (if (stringp fortran-comment-indent-char) 859 (aref fortran-comment-indent-char 0) 860 fortran-comment-indent-char) 861 (- (fortran-calculate-indent) (current-column)))))) 862 863(defun fortran-comment-region (beg-region end-region arg) 864 "Comment every line in the region. 865Inserts the string variable `fortran-comment-region' at the beginning of 866every line in the region. 867BEG-REGION and END-REGION specify the region boundaries. 868With non-nil ARG, uncomments the region." 869 (interactive "*r\nP") 870 (let ((end-region-mark (copy-marker end-region)) 871 (save-point (point-marker))) 872 (goto-char beg-region) 873 (beginning-of-line) 874 (if arg 875 (let ((com (regexp-quote fortran-comment-region))) ; uncomment 876 (if (looking-at com) 877 (delete-region (point) (match-end 0))) 878 (while (and (zerop (forward-line 1)) 879 (< (point) end-region-mark)) 880 (if (looking-at com) 881 (delete-region (point) (match-end 0))))) 882 (insert fortran-comment-region) ; comment 883 (while (and (zerop (forward-line 1)) 884 (< (point) end-region-mark)) 885 (insert fortran-comment-region))) 886 (goto-char save-point) 887 (set-marker end-region-mark nil) 888 (set-marker save-point nil))) 889 890 891(defun fortran-abbrev-start () 892 "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs. 893Any other key combination is executed normally." 894 (interactive "*") 895 (insert last-command-char) 896 (let* ((event (if (fboundp 'next-command-event) ; XEmacs 897 (next-command-event) 898 (read-event))) 899 (char (if (fboundp 'event-to-character) 900 (event-to-character event) event))) 901 ;; Insert char if not equal to `?', or if abbrev-mode is off. 902 (if (and abbrev-mode (or (eq char ??) (eq char help-char) 903 (memq event help-event-list))) 904 (fortran-abbrev-help) 905 (push event unread-command-events)))) 906 907(defun fortran-abbrev-help () 908 "List the currently defined abbrevs in Fortran mode." 909 (interactive) 910 (message "Listing abbrev table...") 911 (display-buffer (fortran-prepare-abbrev-list-buffer)) 912 (message "Listing abbrev table...done")) 913 914(defun fortran-prepare-abbrev-list-buffer () 915 "Create a buffer listing the Fortran mode abbreviations." 916 (with-current-buffer (get-buffer-create "*Abbrevs*") 917 (erase-buffer) 918 (insert-abbrev-table-description 'fortran-mode-abbrev-table t) 919 (goto-char (point-min)) 920 (set-buffer-modified-p nil) 921 (edit-abbrevs-mode)) 922 (get-buffer-create "*Abbrevs*")) 923 924(defun fortran-column-ruler () 925 "Insert a column ruler momentarily above current line, till next keystroke. 926The ruler is defined by the value of `fortran-column-ruler-fixed' in fixed 927format mode, and `fortran-column-ruler-tab' in TAB format mode. 928The next key typed is executed unless it is SPC." 929 (interactive) 930 (momentary-string-display 931 (if indent-tabs-mode 932 fortran-column-ruler-tab 933 fortran-column-ruler-fixed) 934 (save-excursion 935 (beginning-of-line) 936 (if (eq (window-start (selected-window)) 937 (window-point (selected-window))) 938 (line-beginning-position 2) 939 (point))) 940 nil "Type SPC or any command to erase ruler.")) 941 942(defun fortran-window-create () 943 "Make the window 72 columns wide. 944See also `fortran-window-create-momentarily'." 945 (interactive) 946 (let ((window-min-width 2)) 947 (if (< (window-width) (frame-width)) 948 (enlarge-window-horizontally (- (frame-width) 949 (window-width) 1))) 950 (let* ((window-edges (window-edges)) 951 (scroll-bar-width (- (nth 2 window-edges) 952 (car window-edges) 953 (window-width)))) 954 (split-window-horizontally (+ 72 scroll-bar-width))) 955 (other-window 1) 956 (switch-to-buffer " fortran-window-extra" t) 957 (select-window (previous-window)))) 958 959(defun fortran-window-create-momentarily (&optional arg) 960 "Momentarily make the window 72 columns wide. 961Optional ARG non-nil and non-unity disables the momentary feature. 962See also `fortran-window-create'." 963 (interactive "p") 964 (if (or (not arg) 965 (= arg 1)) 966 (save-window-excursion 967 (progn 968 (condition-case nil 969 (fortran-window-create) 970 (error (error "No room for Fortran window"))) 971 (message "Type SPC to continue editing.") 972 (let ((char (read-event))) 973 (or (equal char ?\s) 974 (setq unread-command-events (list char)))))) 975 (fortran-window-create))) 976 977(defun fortran-split-line () 978 "Break line at point and insert continuation marker and alignment." 979 (interactive "*") 980 (delete-horizontal-space) 981 (if (save-excursion 982 (let ((pos (point))) 983 (beginning-of-line) 984 (and (fortran-find-comment-start-skip 'all) 985 (< (match-beginning 0) pos)))) 986 (insert ?\n (match-string 0)) 987 (if indent-tabs-mode 988 (insert ?\n ?\t (fortran-numerical-continuation-char)) 989 (insert "\n " fortran-continuation-string))) ; space after \n important 990 (fortran-indent-line)) ; when cont string is C, c or * 991 992(defun fortran-remove-continuation () 993 "Delete any Fortran continuation characters at point. 994Returns t if anything actually deleted." 995 (when (looking-at "\\( \\{5\\}[^ 0\n]\\|\t[1-9]\\|&\\)") 996 (replace-match "") 997 (delete-indentation) 998 t)) 999 1000(defun fortran-join-line (arg) 1001 "Join current line to the previous one and re-indent. 1002With a prefix argument, repeat this operation that many times. 1003If the prefix argument ARG is negative, join the next -ARG lines. 1004Continuation lines are correctly handled." 1005 (interactive "*p") 1006 (save-excursion 1007 (when (> 0 arg) 1008 (setq arg (- arg)) 1009 (forward-line arg)) 1010 (while (not (zerop arg)) 1011 (beginning-of-line) 1012 (or (fortran-remove-continuation) 1013 (delete-indentation)) 1014 (setq arg (1- arg))) 1015 (fortran-indent-line))) 1016 1017(defun fortran-numerical-continuation-char () 1018 "Return a digit for tab-digit style of continuation lines. 1019If previous line is a tab-digit continuation line, return that digit 1020plus one, otherwise return 1. Zero not allowed." 1021 (save-excursion 1022 (forward-line -1) 1023 (if (looking-at "\t[1-9]") 1024 (+ ?1 (% (- (char-after (1+ (point))) ?0) 9)) 1025 ?1))) 1026 1027(put 'fortran-electric-line-number 'delete-selection t) 1028(defun fortran-electric-line-number (arg) 1029 "Self insert, but if part of a Fortran line number indent it automatically. 1030Auto-indent does not happen if a numeric ARG is used." 1031 (interactive "*P") 1032 (if (or arg (not fortran-electric-line-number)) 1033 (if arg 1034 (self-insert-command (prefix-numeric-value arg)) 1035 (self-insert-command 1)) 1036 (if (or (and (= 5 (current-column)) 1037 (save-excursion 1038 (beginning-of-line) 1039 ;; In col 5 with only spaces to the left. 1040 (looking-at " \\{5\\}"))) 1041 (and (= (if indent-tabs-mode 1042 fortran-minimum-statement-indent-tab 1043 fortran-minimum-statement-indent-fixed) (current-column)) 1044 ;; In col 8 with a single tab to the left. 1045 (eq ?\t (char-after (line-beginning-position))) 1046 (not (or (eq last-command 'fortran-indent-line) 1047 (eq last-command 1048 'fortran-indent-new-line)))) 1049 (save-excursion 1050 (re-search-backward "[^ \t0-9]" 1051 (line-beginning-position) 1052 t)) ; not a line number 1053 (looking-at "[0-9]")) ; within a line number 1054 (self-insert-command (prefix-numeric-value arg)) 1055 (skip-chars-backward " \t") 1056 (insert last-command-char) 1057 (fortran-indent-line)))) 1058 1059 1060(defun fortran-check-end-prog-re () 1061 "Check a preliminary match against `fortran-end-prog-re'." 1062 ;; Having got a possible match for the subprogram end, we need a 1063 ;; match of whitespace, avoiding possible column 73+ stuff. 1064 (save-match-data 1065 (string-match "^\\s-*\\(\\'\\|\\s<\\)" 1066 (buffer-substring (match-end 0) 1067 (min (line-end-position) 1068 (+ 72 (line-beginning-position))))))) 1069 1070;; Note that you can't just check backwards for `subroutine' &c in 1071;; case of un-marked main programs not at the start of the file. 1072(defun fortran-beginning-of-subprogram () 1073 "Move point to the beginning of the current Fortran subprogram." 1074 (interactive) 1075 (save-match-data 1076 (let ((case-fold-search t)) 1077 (beginning-of-line -1) 1078 (if (catch 'ok 1079 (while (re-search-backward fortran-end-prog-re nil 'move) 1080 (if (fortran-check-end-prog-re) 1081 (throw 'ok t)))) 1082 (forward-line))))) 1083 1084(defun fortran-end-of-subprogram () 1085 "Move point to the end of the current Fortran subprogram." 1086 (interactive) 1087 (save-match-data 1088 (let ((case-fold-search t)) 1089 (if (save-excursion ; on END 1090 (beginning-of-line) 1091 (and (looking-at fortran-end-prog-re) 1092 (fortran-check-end-prog-re))) 1093 (forward-line) 1094 (beginning-of-line 2) 1095 (catch 'ok 1096 (while (re-search-forward fortran-end-prog-re nil 'move) 1097 (if (fortran-check-end-prog-re) 1098 (throw 'ok t)))) 1099 (goto-char (match-beginning 0)) 1100 (forward-line))))) 1101 1102(defun fortran-previous-statement () 1103 "Move point to beginning of the previous Fortran statement. 1104Returns 'first-statement if that statement is the first 1105non-comment Fortran statement in the file, and nil otherwise. 1106Directive lines are treated as comments." 1107 (interactive) 1108 (let (not-first-statement continue-test) 1109 (beginning-of-line) 1110 (setq continue-test 1111 (and 1112 (not (looking-at fortran-comment-line-start-skip)) 1113 (not (looking-at fortran-directive-re)) 1114 (or (looking-at 1115 (concat "[ \t]*" 1116 (regexp-quote fortran-continuation-string))) 1117 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")))) 1118 (while (and (setq not-first-statement (zerop (forward-line -1))) 1119 (or (looking-at fortran-comment-line-start-skip) 1120 (looking-at fortran-directive-re) 1121 (looking-at 1122 (concat "[ \t]*" 1123 (regexp-quote fortran-continuation-string))) 1124 (looking-at "[ \t]*$\\| \\{5\\}[^ 0\n]\\|\t[1-9]") 1125 (looking-at (concat "[ \t]*" comment-start-skip))))) 1126 (cond ((and continue-test 1127 (not not-first-statement)) 1128 (message "Incomplete continuation statement.")) 1129 (continue-test 1130 (fortran-previous-statement)) 1131 ((not not-first-statement) 1132 'first-statement)))) 1133 1134(defun fortran-next-statement () 1135 "Move point to beginning of the next Fortran statement. 1136Returns 'last-statement if that statement is the last 1137non-comment Fortran statement in the file, and nil otherwise. 1138Directive lines are treated as comments." 1139 (interactive) 1140 (let (not-last-statement) 1141 (beginning-of-line) 1142 (while (and (setq not-last-statement 1143 (and (zerop (forward-line 1)) 1144 (not (eobp)))) 1145 (or (looking-at fortran-comment-line-start-skip) 1146 (looking-at fortran-directive-re) 1147 (looking-at "[ \t]*$\\| [^ 0\n]\\|\t[1-9]") 1148 (looking-at (concat "[ \t]*" comment-start-skip))))) 1149 (if (not not-last-statement) 1150 'last-statement))) 1151 1152(defun fortran-looking-at-if-then () 1153 "Return non-nil if at the start of a line with an IF ... THEN statement." 1154 ;; cf f90-looking-at-if-then. 1155 (let ((p (point)) 1156 (i (fortran-beginning-if))) 1157 (if i 1158 (save-excursion 1159 (goto-char i) 1160 (beginning-of-line) 1161 (= (point) p))))) 1162 1163;; Used in hs-special-modes-alist. 1164(defun fortran-end-of-block (&optional num) 1165 "Move point forward to the end of the current code block. 1166With optional argument NUM, go forward that many balanced blocks. 1167If NUM is negative, go backward to the start of a block. Does 1168not check for consistency of block types. Interactively, pushes 1169mark before moving point." 1170 (interactive "p") 1171 (if (interactive-p) (push-mark (point) t)) 1172 (and num (< num 0) (fortran-beginning-of-block (- num))) 1173 (let ((case-fold-search t) 1174 (count (or num 1))) 1175 (end-of-line) 1176 (while (and (> count 0) 1177 (re-search-forward 1178 (concat "\\(" fortran-blocks-re 1179 (if fortran-check-all-num-for-matching-do 1180 "\\|^[ \t]*[0-9]+" "") 1181 "\\|continue\\|end\\)\\>") 1182 nil 'move)) 1183 (beginning-of-line) 1184 (if (if (looking-at (concat "^[0-9 \t]*" fortran-if-start-re)) 1185 (fortran-looking-at-if-then) 1186 (looking-at fortran-start-block-re)) 1187 (setq count (1+ count)) 1188 (if (or (looking-at fortran-end-block-re) 1189 (and (or (looking-at "^[0-9 \t]*continue") 1190 (and fortran-check-all-num-for-matching-do 1191 (looking-at "[ \t]*[0-9]+"))) 1192 (fortran-check-for-matching-do))) 1193 (setq count (1- count)))) 1194 (end-of-line)) 1195 (if (> count 0) (error "Missing block end")))) 1196 1197(defun fortran-beginning-of-block (&optional num) 1198 "Move point backwards to the start of the current code block. 1199With optional argument NUM, go backward that many balanced 1200blocks. If NUM is negative, go forward to the end of a block. 1201Does not check for consistency of block types. Interactively, 1202pushes mark before moving point." 1203 (interactive "p") 1204 (if (interactive-p) (push-mark (point) t)) 1205 (and num (< num 0) (fortran-end-of-block (- num))) 1206 (let ((case-fold-search t) 1207 (count (or num 1))) 1208 (beginning-of-line) 1209 (while (and (> count 0) 1210 (re-search-backward 1211 (concat "\\(" fortran-blocks-re 1212 (if fortran-check-all-num-for-matching-do 1213 "\\|^[ \t]*[0-9]+" "") 1214 "\\|continue\\|end\\)\\>") 1215 nil 'move)) 1216 (beginning-of-line) 1217 (if (if (looking-at (concat "^[0-9 \t]*" fortran-if-start-re)) 1218 (fortran-looking-at-if-then) 1219 (looking-at fortran-start-block-re)) 1220 (setq count (1- count)) 1221 (if (or (looking-at fortran-end-block-re) 1222 (and (or (looking-at "^[0-9 \t]*continue") 1223 (and fortran-check-all-num-for-matching-do 1224 (looking-at "[ \t]*[0-9]+"))) 1225 (fortran-check-for-matching-do))) 1226 (setq count (1+ count))))) 1227 ;; Includes an un-named main program block. 1228 (if (> count 0) (error "Missing block start")))) 1229 1230 1231(defun fortran-blink-match (regex keyword find-begin) 1232 "From a line matching REGEX, blink matching KEYWORD statement line. 1233Use function FIND-BEGIN to match it." 1234 (let ((top-of-window (window-start)) 1235 (end-point (point)) 1236 (case-fold-search t) 1237 matching 1238 message) 1239 (when (save-excursion 1240 (beginning-of-line) 1241 (skip-chars-forward " \t0-9") 1242 (looking-at regex)) 1243 (if (not (setq matching (funcall find-begin))) 1244 (setq message (concat "No matching " keyword ".")) 1245 (if (< matching top-of-window) 1246 (save-excursion 1247 (goto-char matching) 1248 (beginning-of-line) 1249 (setq message 1250 (concat "Matches " 1251 (buffer-substring (point) 1252 (line-end-position))))))) 1253 (if message 1254 (message "%s" message) 1255 (goto-char matching) 1256 (sit-for blink-matching-delay) 1257 (goto-char end-point))))) 1258 1259(defun fortran-blink-matching-if () 1260 "From an ENDIF or ELSE statement, blink the matching IF statement." 1261 (fortran-blink-match "e\\(nd[ \t]*if\\|lse\\([ \t]*if\\)?\\)\\b" 1262 "if" #'fortran-beginning-if)) 1263 1264(defun fortran-blink-matching-do () 1265 "From an ENDDO statement, blink the matching DO or DO WHILE statement." 1266 (fortran-blink-match "end[ \t]*do\\b" "do" #'fortran-beginning-do)) 1267 1268(defun fortran-mark-do () 1269 "Put mark at end of Fortran DO [WHILE]-ENDDO construct, point at beginning. 1270The marks are pushed." 1271 (interactive) 1272 (let (enddo-point do-point) 1273 (if (setq enddo-point (fortran-end-do)) 1274 (if (not (setq do-point (fortran-beginning-do))) 1275 (message "No matching do.") 1276 (goto-char enddo-point) 1277 (push-mark) 1278 (goto-char do-point))))) 1279 1280(defun fortran-end-do () 1281 "Search forward for first unmatched ENDDO. 1282Return point or nil." 1283 (let ((case-fold-search t)) 1284 (if (save-excursion (beginning-of-line) 1285 (skip-chars-forward " \t0-9") 1286 (looking-at "end[ \t]*do\\b")) 1287 ;; Sitting on one. 1288 (match-beginning 0) 1289 ;; Search for one. 1290 (save-excursion 1291 (let ((count 1)) 1292 (while (and (not (zerop count)) 1293 (not (eq (fortran-next-statement) 'last-statement)) 1294 ;; Keep local to subprogram. 1295 (not (and (looking-at fortran-end-prog-re) 1296 (fortran-check-end-prog-re)))) 1297 (skip-chars-forward " \t0-9") 1298 (cond ((looking-at "end[ \t]*do\\b") 1299 (setq count (1- count))) 1300 ((looking-at 1301 "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]") 1302 (setq count (1+ count))))) 1303 (and (zerop count) 1304 ;; All pairs accounted for. 1305 (point))))))) 1306 1307(defun fortran-beginning-do () 1308 "Search backwards for first unmatched DO [WHILE]. 1309Return point or nil. Ignores labelled DO loops (ie DO 10 ... 10 CONTINUE)." 1310 (let ((case-fold-search t) 1311 (dostart-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]")) 1312 (if (save-excursion 1313 (beginning-of-line) 1314 (skip-chars-forward " \t0-9") 1315 (looking-at dostart-re)) 1316 ;; Sitting on one. 1317 (match-beginning 0) 1318 ;; Search for one. 1319 (save-excursion 1320 (let ((count 1)) 1321 (while (and (not (zerop count)) 1322 (not (eq (fortran-previous-statement) 'first-statement)) 1323 ;; Keep local to subprogram. 1324 (not (and (looking-at fortran-end-prog-re) 1325 (fortran-check-end-prog-re)))) 1326 (skip-chars-forward " \t0-9") 1327 (cond ((looking-at dostart-re) 1328 (setq count (1- count))) 1329 ;; Note labelled loop ends not considered. 1330 ((looking-at "end[ \t]*do\\b") 1331 (setq count (1+ count))))) 1332 (and (zerop count) 1333 ;; All pairs accounted for. 1334 (point))))))) 1335 1336(defun fortran-mark-if () 1337 "Put mark at end of Fortran IF-ENDIF construct, point at beginning. 1338The marks are pushed." 1339 (interactive) 1340 (let (endif-point if-point) 1341 (if (setq endif-point (fortran-end-if)) 1342 (if (not (setq if-point (fortran-beginning-if))) 1343 (message "No matching if.") 1344 ;; Set mark, move point. 1345 (goto-char endif-point) 1346 (push-mark) 1347 (goto-char if-point))))) 1348 1349(defun fortran-end-if () 1350 "Search forwards for first unmatched ENDIF. 1351Return point or nil." 1352 (let ((case-fold-search t)) 1353 (if (save-excursion (beginning-of-line) 1354 (skip-chars-forward " \t0-9") 1355 (looking-at "end[ \t]*if\\b")) 1356 ;; Sitting on one. 1357 (match-beginning 0) 1358 ;; Search for one. The point has been already been moved to first 1359 ;; letter on line but this should not cause troubles. 1360 (save-excursion 1361 (let ((count 1)) 1362 (while (and (not (zerop count)) 1363 (not (eq (fortran-next-statement) 'last-statement)) 1364 ;; Keep local to subprogram. 1365 (not (and (looking-at fortran-end-prog-re) 1366 (fortran-check-end-prog-re)))) 1367 (skip-chars-forward " \t0-9") 1368 (cond ((looking-at "end[ \t]*if\\b") 1369 (setq count (1- count))) 1370 ((looking-at fortran-if-start-re) 1371 (save-excursion 1372 (if (or 1373 (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") 1374 (let (then-test) ; multi-line if-then 1375 (while 1376 (and 1377 (zerop (forward-line 1)) 1378 ;; Search forward for then. 1379 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]") 1380 (not 1381 (setq then-test 1382 (looking-at 1383 ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) 1384 then-test)) 1385 (setq count (1+ count))))))) 1386 (and (zerop count) 1387 ;; All pairs accounted for. 1388 (point))))))) 1389 1390(defun fortran-beginning-if () 1391 "Search backwards for first unmatched IF-THEN. 1392Return point or nil." 1393 (let ((case-fold-search t)) 1394 (if (save-excursion 1395 ;; May be sitting on multi-line if-then statement, first 1396 ;; move to beginning of current statement. Note: 1397 ;; `fortran-previous-statement' moves to previous statement 1398 ;; *unless* current statement is first one. Only move 1399 ;; forward if not first-statement. 1400 (if (not (eq (fortran-previous-statement) 'first-statement)) 1401 (fortran-next-statement)) 1402 (skip-chars-forward " \t0-9") 1403 (and 1404 (looking-at fortran-if-start-re) 1405 (save-match-data 1406 (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") 1407 ;; Multi-line if-then. 1408 (let (then-test) 1409 (while 1410 (and (zerop (forward-line 1)) 1411 ;; Search forward for then. 1412 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]") 1413 (not 1414 (setq then-test 1415 (looking-at 1416 ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) 1417 then-test))))) 1418 ;; Sitting on one. 1419 (match-beginning 0) 1420 ;; Search for one. 1421 (save-excursion 1422 (let ((count 1)) 1423 (while (and (not (zerop count)) 1424 (not (eq (fortran-previous-statement) 'first-statement)) 1425 ;; Keep local to subprogram. 1426 (not (and (looking-at fortran-end-prog-re) 1427 (fortran-check-end-prog-re)))) 1428 (skip-chars-forward " \t0-9") 1429 (cond ((looking-at fortran-if-start-re) 1430 (save-excursion 1431 (if (or 1432 (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") 1433 (let (then-test) ; multi-line if-then 1434 (while 1435 (and 1436 (zerop (forward-line 1)) 1437 ;; Search forward for then. 1438 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]") 1439 (not 1440 (setq then-test 1441 (looking-at 1442 (concat ".*then\\b[ \t]*" 1443 "[^ \t(=a-z0-9]")))))) 1444 then-test)) 1445 (setq count (1- count))))) 1446 ((looking-at "end[ \t]*if\\b") 1447 (setq count (1+ count))))) 1448 (and (zerop count) 1449 ;; All pairs accounted for. 1450 (point))))))) 1451 1452 1453(defun fortran-indent-line () 1454 "Indent current Fortran line based on its contents and on previous lines." 1455 (interactive "*") 1456 (let ((cfi (fortran-calculate-indent))) 1457 (save-excursion 1458 (beginning-of-line) 1459 (if (or (not (= cfi (fortran-current-line-indentation))) 1460 (and (re-search-forward "^[ \t]*[0-9]+" (+ (point) 4) t) 1461 (not (fortran-line-number-indented-correctly-p)))) 1462 (fortran-indent-to-column cfi) 1463 (beginning-of-line) 1464 (if (fortran-find-comment-start-skip) 1465 (fortran-indent-comment)))) 1466 ;; Never leave point in left margin. 1467 (if (< (current-column) cfi) 1468 (move-to-column cfi)) 1469 (and auto-fill-function 1470 (> (save-excursion (end-of-line) (current-column)) 1471 fill-column) 1472 (save-excursion 1473 (end-of-line) 1474 (fortran-fill))) 1475 (when fortran-blink-matching-if 1476 (fortran-blink-matching-if) 1477 (fortran-blink-matching-do)))) 1478 1479(defun fortran-auto-fill () 1480 "Function to use for `normal-auto-fill-function' in Fortran mode." 1481 (if (> (current-column) (current-fill-column)) 1482 (let ((cfi (fortran-calculate-indent))) 1483 (save-excursion 1484 (beginning-of-line) 1485 (if (or (not (= cfi (fortran-current-line-indentation))) 1486 (and (re-search-forward "^[ \t]*[0-9]+" 1487 (+ (point) 4) t) 1488 (not (fortran-line-number-indented-correctly-p)))) 1489 (fortran-indent-to-column cfi) 1490 (beginning-of-line) 1491 (if (fortran-find-comment-start-skip) 1492 (fortran-indent-comment)))) 1493 (fortran-fill) 1494 ;; Never leave point in left margin. 1495 (if (< (current-column) cfi) 1496 (move-to-column cfi))))) 1497 1498;; Historically this was a separate function which advertised itself 1499;; as reindenting but only did so where `most likely to be necessary'. 1500(defalias 'fortran-indent-new-line 'reindent-then-newline-and-indent) 1501 1502(defun fortran-indent-subprogram () 1503 "Properly indent the Fortran subprogram containing point." 1504 (interactive "*") 1505 (save-excursion 1506 (mark-defun) 1507 (message "Indenting subprogram...") 1508 (indent-region (point) (mark) nil)) 1509 (message "Indenting subprogram...done.")) 1510 1511(defun fortran-calculate-indent () 1512 "Calculates the Fortran indent column based on previous lines." 1513 (let (icol first-statement (case-fold-search t) 1514 (fortran-minimum-statement-indent 1515 (if indent-tabs-mode 1516 fortran-minimum-statement-indent-tab 1517 fortran-minimum-statement-indent-fixed))) 1518 (save-excursion 1519 (setq first-statement (fortran-previous-statement)) 1520 (if first-statement 1521 (setq icol fortran-minimum-statement-indent) 1522 (if (= (point) (point-min)) 1523 (setq icol fortran-minimum-statement-indent) 1524 (setq icol (fortran-current-line-indentation))) 1525 (skip-chars-forward " \t0-9") 1526 (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(") 1527 (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]") 1528 (let (then-test) ; multi-line if-then 1529 (while (and (zerop (forward-line 1)) 1530 ;; Search forward for then. 1531 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]") 1532 (not (setq then-test 1533 (looking-at 1534 ".*then\\b[ \t]\ 1535*[^ \t_$(=a-z0-9]"))))) 1536 then-test)) 1537 (setq icol (+ icol fortran-if-indent)))) 1538 ((looking-at "else\\(if\\)?\\b") 1539 (setq icol (+ icol fortran-if-indent))) 1540 ((looking-at "select[ \t]*case[ \t](.*)") 1541 (setq icol (+ icol fortran-if-indent))) 1542 ((looking-at "case[ \t]*(.*)") 1543 (setq icol (+ icol fortran-if-indent))) 1544 ((looking-at "case[ \t]*default\\b") 1545 (setq icol (+ icol fortran-if-indent))) 1546 ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b") 1547 (setq icol (+ icol fortran-if-indent))) 1548 ((looking-at "where[ \t]*(.*)[ \t]*\n") 1549 (setq icol (+ icol fortran-if-indent))) 1550 ((looking-at "do\\b") 1551 (setq icol (+ icol fortran-do-indent))) 1552 ((looking-at 1553 "\\(structure\\|union\\|map\\|interface\\)\ 1554\\b[ \t]*[^ \t=(a-z]") 1555 (setq icol (+ icol fortran-structure-indent))) 1556 ((and (looking-at fortran-end-prog-re1) 1557 (fortran-check-end-prog-re)) 1558 ;; Previous END resets indent to minimum. 1559 (setq icol fortran-minimum-statement-indent))))) 1560 (save-excursion 1561 (beginning-of-line) 1562 (cond ((looking-at "[ \t]*$")) 1563 ;; Check for directive before comment, so as not to indent. 1564 ((looking-at fortran-directive-re) 1565 (setq fortran-minimum-statement-indent 0 icol 0)) 1566 ((looking-at fortran-comment-line-start-skip) 1567 (cond ((eq fortran-comment-indent-style 'relative) 1568 (setq icol (+ icol fortran-comment-line-extra-indent))) 1569 ((eq fortran-comment-indent-style 'fixed) 1570 (setq icol (+ fortran-minimum-statement-indent 1571 fortran-comment-line-extra-indent)))) 1572 (setq fortran-minimum-statement-indent 0)) 1573 ((or (looking-at (concat "[ \t]*" 1574 (regexp-quote 1575 fortran-continuation-string))) 1576 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")) 1577 (skip-chars-forward " \t") 1578 ;; Do not introduce extra whitespace into a broken string. 1579 (setq icol 1580 (if (fortran-is-in-string-p (point)) 1581 6 1582 (+ icol fortran-continuation-indent)))) 1583 (first-statement) 1584 ((and fortran-check-all-num-for-matching-do 1585 (looking-at "[ \t]*[0-9]+") 1586 (fortran-check-for-matching-do)) 1587 (setq icol (- icol fortran-do-indent))) 1588 (t 1589 (skip-chars-forward " \t0-9") 1590 (cond ((looking-at "end[ \t]*\\(if\\|select\\|where\\)\\b") 1591 (setq icol (- icol fortran-if-indent))) 1592 ((looking-at "else\\(if\\)?\\b") 1593 (setq icol (- icol fortran-if-indent))) 1594 ((looking-at "case[ \t]*\\((.*)\\|default\\>\\)") 1595 (setq icol (- icol fortran-if-indent))) 1596 ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b") 1597 (setq icol (- icol fortran-if-indent))) 1598 ((and (looking-at "continue\\b") 1599 (fortran-check-for-matching-do)) 1600 (setq icol (- icol fortran-do-indent))) 1601 ((looking-at "end[ \t]*do\\b") 1602 (setq icol (- icol fortran-do-indent))) 1603 ((looking-at "end[ \t]*\ 1604\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]") 1605 (setq icol (- icol fortran-structure-indent))) 1606 ((and (looking-at fortran-end-prog-re1) 1607 (fortran-check-end-prog-re) 1608 (not (= icol fortran-minimum-statement-indent))) 1609 (message "Warning: `end' not in column %d. Probably\ 1610 an unclosed block." fortran-minimum-statement-indent)))))) 1611 (max fortran-minimum-statement-indent icol))) 1612 1613 1614(defun fortran-current-line-indentation () 1615 "Indentation of current line, ignoring Fortran line number or continuation. 1616This is the column position of the first non-whitespace character 1617aside from the line number and/or column 5/8 line-continuation character. 1618For comment lines, returns indentation of the first 1619non-indentation text within the comment." 1620 (save-excursion 1621 (beginning-of-line) 1622 (cond ((looking-at fortran-comment-line-start-skip) 1623 (goto-char (match-end 0)) 1624 (skip-chars-forward 1625 (if (stringp fortran-comment-indent-char) 1626 fortran-comment-indent-char 1627 (char-to-string fortran-comment-indent-char)))) 1628 ((or (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")) 1629 (goto-char (match-end 0))) 1630 (t 1631 ;; Move past line number. 1632 (skip-chars-forward "[ \t0-9]"))) 1633 ;; Move past whitespace. 1634 (skip-chars-forward " \t") 1635 (current-column))) 1636 1637(defun fortran-indent-to-column (col) 1638 "Indent current line to column COL. 1639notes: 1) A non-zero/non-blank character in column 5 indicates a continuation 1640 line, and this continuation character is retained on indentation; 1641 2) If `fortran-continuation-string' is the first non-whitespace 1642 character, this is a continuation line; 1643 3) A non-continuation line which has a number as the first 1644 non-whitespace character is a numbered line. 1645 4) A TAB followed by a digit indicates a continuation line." 1646 (save-excursion 1647 (beginning-of-line) 1648 (if (looking-at fortran-comment-line-start-skip) 1649 (if fortran-comment-indent-style 1650 (let* ((char (if (stringp fortran-comment-indent-char) 1651 (aref fortran-comment-indent-char 0) 1652 fortran-comment-indent-char)) 1653 (chars (string ?\s ?\t char))) 1654 (goto-char (match-end 0)) 1655 (skip-chars-backward chars) 1656 (delete-region (point) (progn (skip-chars-forward chars) 1657 (point))) 1658 (insert-char char (- col (current-column))))) 1659 (if (looking-at "\t[1-9]") 1660 (if indent-tabs-mode 1661 (goto-char (match-end 0)) 1662 (delete-char 2) 1663 (insert-char ?\s 5) 1664 (insert fortran-continuation-string)) 1665 (if (looking-at " \\{5\\}[^ 0\n]") 1666 (if indent-tabs-mode 1667 (progn (delete-char 6) 1668 (insert ?\t (fortran-numerical-continuation-char) 1)) 1669 (forward-char 6)) 1670 (delete-horizontal-space) 1671 ;; Put line number in columns 0-4, or 1672 ;; continuation character in column 5. 1673 (cond ((eobp)) 1674 ((looking-at (regexp-quote fortran-continuation-string)) 1675 (if indent-tabs-mode 1676 (progn 1677 (indent-to 1678 (if indent-tabs-mode 1679 fortran-minimum-statement-indent-tab 1680 fortran-minimum-statement-indent-fixed)) 1681 (delete-char 1) 1682 (insert-char (fortran-numerical-continuation-char) 1)) 1683 (indent-to 5) 1684 (forward-char 1))) 1685 ((looking-at "[0-9]+") 1686 (let ((extra-space (- 5 (- (match-end 0) (point))))) 1687 (if (< extra-space 0) 1688 (message "Warning: line number exceeds 5-digit limit.") 1689 (indent-to (min fortran-line-number-indent extra-space)))) 1690 (skip-chars-forward "0-9"))))) 1691 ;; Point is now after any continuation character or line number. 1692 ;; Put body of statement where specified. 1693 (delete-horizontal-space) 1694 (indent-to col) 1695 ;; Indent any comment following code on the same line. 1696 (when (fortran-find-comment-start-skip) 1697 (goto-char (match-beginning 0)) 1698 (unless (= (current-column) (fortran-comment-indent)) 1699 (delete-horizontal-space) 1700 (indent-to (fortran-comment-indent))))))) 1701 1702(defun fortran-line-number-indented-correctly-p () 1703 "Return t if current line's line number is correctly indented. 1704Do not call if there is no line number." 1705 (save-excursion 1706 (beginning-of-line) 1707 (skip-chars-forward " \t") 1708 (and (<= (current-column) fortran-line-number-indent) 1709 (or (= (current-column) fortran-line-number-indent) 1710 (progn (skip-chars-forward "0-9") 1711 (= (current-column) 5)))))) 1712 1713(defun fortran-check-for-matching-do () 1714 "When called from a numbered statement, return t if matching DO is found. 1715Otherwise return nil." 1716 (let ((case-fold-search t) 1717 charnum) 1718 (save-excursion 1719 (beginning-of-line) 1720 (when (looking-at "[ \t]*[0-9]+") 1721 (skip-chars-forward " \t") 1722 (skip-chars-forward "0") ; skip past leading zeros 1723 (setq charnum 1724 (buffer-substring (point) (progn 1725 (skip-chars-forward "0-9") 1726 (point)))) 1727 (beginning-of-line) 1728 (save-restriction 1729 (save-excursion 1730 (narrow-to-defun) 1731 (and (re-search-backward 1732 (concat 1733 "\\(^[ \t0-9]*do[ \t]*0*" 1734 charnum "\\b\\)\\|" "\\(^[ \t]*0*" 1735 charnum "\\b\\)") 1736 nil t) 1737 (looking-at 1738 (concat "^[ \t0-9]*do[ \t]*0*" 1739 charnum))))))))) 1740 1741(defun fortran-find-comment-start-skip (&optional all) 1742 "Move to past `comment-start-skip' found on current line. 1743Return non-nil if `comment-start-skip' found, nil if not. 1744If ALL is nil, only match comments that start in column > 0." 1745 ;; Hopefully at some point we can just use the line below! -stef 1746 ;; (comment-search-forward (line-end-position) t)) 1747 (when (or all comment-start-skip) 1748 (let ((pos (point)) 1749 (css (if comment-start-skip 1750 (concat fortran-comment-line-start-skip 1751 "\\|" comment-start-skip) 1752 fortran-comment-line-start-skip))) 1753 (when (re-search-forward css (line-end-position) t) 1754 (if (and (or all (> (match-beginning 0) (line-beginning-position))) 1755 (or (save-match-data 1756 (not (fortran-is-in-string-p (match-beginning 0)))) 1757 ;; Recurse for rest of line. 1758 (fortran-find-comment-start-skip all))) 1759 (point) 1760 (goto-char pos) 1761 nil))))) 1762 1763;; From: ralf@up3aud1.gwdg.de (Ralf Fassel) 1764;; Test if TAB format continuation lines work. 1765(defun fortran-is-in-string-p (where) 1766 "Return non-nil iff WHERE (a buffer position) is inside a Fortran string." 1767 (save-excursion 1768 (goto-char where) 1769 (cond 1770 ((bolp) nil) ; bol is never inside a string 1771 ((save-excursion ; comment lines too 1772 (beginning-of-line) 1773 (looking-at fortran-comment-line-start-skip)) nil) 1774 (t (let ((parse-state '(0 nil nil nil nil nil 0)) 1775 (quoted-comment-start (if comment-start 1776 (regexp-quote comment-start))) 1777 (not-done t) 1778 parse-limit end-of-line) 1779 ;; Move to start of current statement. 1780 (fortran-next-statement) 1781 (fortran-previous-statement) 1782 ;; Now parse up to WHERE. 1783 (while not-done 1784 (if (or ;; Skip to next line if: 1785 ;; - comment line? 1786 (looking-at fortran-comment-line-start-skip) 1787 ;; - at end of line? 1788 (eolp) 1789 ;; - not in a string and after comment-start? 1790 (and (not (nth 3 parse-state)) 1791 comment-start 1792 (equal comment-start 1793 (char-to-string (preceding-char))))) 1794 (if (> (forward-line) 0) 1795 (setq not-done nil)) 1796 ;; else: 1797 ;; If we are at beginning of code line, skip any 1798 ;; whitespace, labels and tab continuation markers. 1799 (if (bolp) (skip-chars-forward " \t0-9")) 1800 ;; If we are in column <= 5 now, check for continuation char. 1801 (cond ((= 5 (current-column)) (forward-char 1)) 1802 ((and (< (current-column) 5) 1803 (equal fortran-continuation-string 1804 (char-to-string (following-char))) 1805 (forward-char 1)))) 1806 ;; Find out parse-limit from here. 1807 (setq end-of-line (line-end-position)) 1808 (setq parse-limit (min where end-of-line)) 1809 ;; Parse max up to comment-start, if non-nil and in current line. 1810 (if comment-start 1811 (save-excursion 1812 (if (re-search-forward quoted-comment-start end-of-line t) 1813 (setq parse-limit (min (point) parse-limit))))) 1814 ;; Now parse if still in limits. 1815 (if (< (point) where) 1816 (setq parse-state (parse-partial-sexp 1817 (point) parse-limit nil nil parse-state)) 1818 (setq not-done nil)))) 1819 ;; Result. 1820 (nth 3 parse-state)))))) 1821 1822;; From old version. 1823(defalias 'fortran-auto-fill-mode 'auto-fill-mode) 1824 1825(defun fortran-fill () 1826 "Fill the current line at an appropriate point(s)." 1827 (let* ((auto-fill-function #'fortran-auto-fill) 1828 (opoint (point)) 1829 (bol (line-beginning-position)) 1830 (eol (line-end-position)) 1831 (bos (min eol (+ bol (fortran-current-line-indentation)))) 1832 ;; If in a string at fill-column, break it either before the 1833 ;; initial quote, or at fill-col (if string is too long). 1834 (quote 1835 (save-excursion 1836 (goto-char bol) 1837 ;; OK to break quotes on comment lines. 1838 (unless (looking-at fortran-comment-line-start-skip) 1839 (let (fcpoint start) 1840 (move-to-column fill-column) 1841 (when (fortran-is-in-string-p (setq fcpoint (point))) 1842 (save-excursion 1843 (re-search-backward "\\S\"\\s\"\\S\"?" bol t) 1844 (setq start 1845 (if fortran-break-before-delimiters 1846 (point) 1847 (1+ (point))))) 1848 (if (re-search-forward "\\S\"\\s\"\\S\"" eol t) 1849 (backward-char 2)) 1850 ;; If the current string is longer than (fill-column 1851 ;; - 6) chars, break it at the fill column (else 1852 ;; infinite loop). 1853 (if (> (- (point) start) 1854 (- fill-column 6 fortran-continuation-indent)) 1855 fcpoint 1856 start)))))) 1857 ;; Decide where to split the line. If a position for a quoted 1858 ;; string was found above then use that, else break the line 1859 ;; before/after the last delimiter. 1860 (fill-point 1861 (or quote 1862 (save-excursion 1863 ;; If f-b-b-d is t, have an extra column to play with, 1864 ;; since delimiter gets shifted to new line. 1865 (move-to-column (if fortran-break-before-delimiters 1866 (1+ fill-column) 1867 fill-column)) 1868 (let ((repeat t)) 1869 (while repeat 1870 (setq repeat nil) 1871 ;; Adapted from f90-find-breakpoint. 1872 (re-search-backward fortran-break-delimiters-re bol) 1873 (if (not fortran-break-before-delimiters) 1874 (if (looking-at fortran-no-break-re) 1875 ;; Deal with cases such as "**" split over 1876 ;; fill-col. Simpler alternative would be 1877 ;; to start from (1- fill-column) above. 1878 (if (> (+ 2 (current-column)) fill-column) 1879 (setq repeat t) 1880 (forward-char 2)) 1881 (forward-char 1)) 1882 (backward-char) 1883 (or (looking-at fortran-no-break-re) 1884 (forward-char))))) 1885 ;; Line indented beyond fill-column? 1886 (when (<= (point) bos) 1887 (move-to-column (1+ fill-column)) 1888 ;; What is this doing??? 1889 (or (re-search-forward "[\t\n,'+-/*)=]" eol t) 1890 (goto-char bol))) 1891 (if (bolp) 1892 (re-search-forward "[ \t]" opoint t)) 1893 (point))))) 1894 ;; If we are in an in-line comment, don't break unless the 1895 ;; line of code is longer than it should be. Otherwise 1896 ;; break the line at the column computed above. 1897 ;; 1898 ;; Need to use fortran-find-comment-start-skip to make sure that 1899 ;; quoted !'s don't prevent a break. 1900 (when (and (save-excursion 1901 (beginning-of-line) 1902 (if (not (fortran-find-comment-start-skip)) 1903 t 1904 (goto-char (match-beginning 0)) 1905 (>= (point) fill-point))) 1906 (save-excursion 1907 (goto-char fill-point) 1908 (not (bolp))) 1909 (> (save-excursion 1910 (goto-char opoint) 1911 (current-column)) 1912 (min (1+ fill-column) 1913 (+ (fortran-calculate-indent) 1914 fortran-continuation-indent)))) 1915 (goto-char fill-point) 1916 (fortran-break-line) 1917 (end-of-line)))) 1918 1919(defun fortran-break-line () 1920 "Call `fortran-split-line'. Joins continuation lines first, then refills." 1921 (let ((bol (line-beginning-position)) 1922 (comment-string 1923 (save-excursion 1924 (if (fortran-find-comment-start-skip) 1925 (delete-and-extract-region 1926 (match-beginning 0) (line-end-position)))))) 1927 ;; Forward line 1 really needs to go to next non white line. 1928 (if (save-excursion (forward-line) 1929 (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")) 1930 (progn 1931 (end-of-line) 1932 (delete-region (point) (match-end 0)) 1933 (delete-horizontal-space) 1934 (fortran-fill)) 1935 (fortran-split-line)) 1936 (if comment-string 1937 (save-excursion 1938 (goto-char bol) 1939 (end-of-line) 1940 (delete-horizontal-space) 1941 (indent-to (fortran-comment-indent)) 1942 (insert comment-string))))) 1943 1944(defun fortran-analyze-file-format () 1945 "Return nil if fixed format is used, t if TAB formatting is used. 1946Use `fortran-tab-mode-default' if no non-comment statements are found 1947before the end or in the first `fortran-analyze-depth' lines." 1948 (let ((i 0)) 1949 (save-excursion 1950 (goto-char (point-min)) 1951 (while (not (or 1952 (eobp) 1953 (eq (char-after) ?\t) 1954 (looking-at " \\{6\\}") 1955 (> i fortran-analyze-depth))) 1956 (forward-line) 1957 (setq i (1+ i))) 1958 (cond 1959 ((eq (char-after) ?\t) t) 1960 ((looking-at " \\{6\\}") nil) 1961 (t fortran-tab-mode-default))))) 1962 1963(defun fortran-fill-paragraph (&optional justify) 1964 "Fill surrounding comment block as paragraphs, else fill statement. 1965Intended as the value of `fill-paragraph-function'. 1966A comment block is filled by calling `fill-comment-paragraph' with 1967argument JUSTIFY, otherwise `fortran-fill-statement' is called. 1968Always returns non-nil (to prevent `fill-paragraph' being called)." 1969 (interactive "*P") 1970 (or (fill-comment-paragraph justify) 1971 (fortran-fill-statement) 1972 t)) 1973 1974(defun fortran-fill-statement () 1975 "Fill a Fortran statement up to `fill-column'." 1976 (interactive "*") 1977 (let ((auto-fill-function #'fortran-auto-fill)) 1978 (unless (save-excursion 1979 (beginning-of-line) 1980 (or (looking-at "[ \t]*$") 1981 (looking-at fortran-comment-line-start-skip) 1982 (and comment-start-skip 1983 (looking-at (concat "[ \t]*" comment-start-skip))))) 1984 (save-excursion 1985 ;; Find beginning of statement. 1986 (fortran-next-statement) 1987 (fortran-previous-statement) 1988 ;; Re-indent initially. 1989 (fortran-indent-line) 1990 ;; Replace newline plus continuation field plus indentation with 1991 ;; single space. 1992 (while (progn 1993 (forward-line) 1994 (fortran-remove-continuation))) 1995 (fortran-previous-statement))) 1996 (fortran-indent-line))) 1997 1998(defun fortran-strip-sequence-nos (&optional do-space) 1999 "Delete all text in column 72 and up (assumed to be sequence numbers). 2000Normally also deletes trailing whitespace after stripping such text. 2001Supplying prefix arg DO-SPACE prevents stripping the whitespace." 2002 (interactive "*p") 2003 (save-excursion 2004 (goto-char (point-min)) 2005 (while (re-search-forward "^.\\{72\\}\\(.*\\)" nil t) 2006 (replace-match "" nil nil nil 1) 2007 (unless do-space (delete-horizontal-space))))) 2008 2009;; This code used to live in add-log.el, but this is a better place 2010;; for it. 2011(defun fortran-current-defun () 2012 "Function to use for `add-log-current-defun-function' in Fortran mode." 2013 (save-excursion 2014 ;; We must be inside function body for this to work. 2015 (fortran-beginning-of-subprogram) 2016 (let ((case-fold-search t)) ; case-insensitive 2017 ;; Search for fortran subprogram start. 2018 (if (re-search-forward 2019 (concat "^[ \t]*\\(program\\|subroutine\\|function" 2020 "\\|[ \ta-z0-9*()]*[ \t]+function\\|" 2021 "\\(block[ \t]*data\\)\\)") 2022 (save-excursion (fortran-end-of-subprogram) 2023 (point)) 2024 t) 2025 (or (match-string-no-properties 2) 2026 (progn 2027 ;; Move to EOL or before first left paren. 2028 (if (re-search-forward "[(\n]" nil t) 2029 (progn (backward-char) 2030 (skip-chars-backward " \t")) 2031 (end-of-line)) 2032 ;; Use the name preceding that. 2033 (buffer-substring-no-properties (point) (progn (backward-sexp) 2034 (point))))) 2035 "main")))) 2036 2037(provide 'fortran) 2038 2039;; arch-tag: 74935096-21c4-4cab-8ee5-6ef16090dc04 2040;;; fortran.el ends here 2041