;;; fortran.el --- Fortran mode for GNU Emacs
;; Copyright (C) 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
-;; 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+;; 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
;; Free Software Foundation, Inc.
;; Author: Michael D. Prange <prange@erl.mit.edu>
A value of nil specifies that continuation lines are marked
with a character in column 6."
:type 'boolean
+ :safe 'booleanp
:group 'fortran-indent)
-(put 'fortran-tab-mode-default 'safe-local-variable 'booleanp)
;; TODO add more detail of what tab mode is to doc string.
(defcustom fortran-tab-mode-string
"String to appear in mode line in TAB format buffers.
See Info node `(emacs)ForIndent Cont'."
:type 'string
+ :risky t
:group 'fortran-indent)
-(put 'fortran-tab-mode-string 'risky-local-variable t)
(defcustom fortran-do-indent 3
"Extra indentation applied to DO blocks."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-do-indent 'safe-local-variable 'integerp)
(defcustom fortran-if-indent 3
"Extra indentation applied to IF, SELECT CASE and WHERE blocks."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-if-indent 'safe-local-variable 'integerp)
(defcustom fortran-structure-indent 3
"Extra indentation applied to STRUCTURE, UNION, MAP and INTERFACE blocks."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-structure-indent 'safe-local-variable 'integerp)
(defcustom fortran-continuation-indent 5
"Extra indentation applied to continuation lines."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-continuation-indent 'safe-local-variable 'integerp)
(defcustom fortran-comment-indent-style 'fixed
"How to indent comments.
`relative' indents to current Fortran indentation plus
`fortran-comment-line-extra-indent'."
:type '(radio (const :tag "Untouched" nil) (const fixed) (const relative))
+ :safe (lambda (value) (memq value '(nil fixed relative)))
:group 'fortran-indent)
-(put 'fortran-comment-indent 'safe-local-variable
- (lambda (value) (memq value '(nil fixed relative))))
(defcustom fortran-comment-line-extra-indent 0
"Amount of extra indentation for text within full-line comments."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent
:group 'fortran-comment)
-(put 'fortran-comment-line-extra-indent 'safe-local-variable 'integerp)
(defcustom fortran-comment-line-start "C"
"Delimiter inserted to start new full-line comment.
allow trailing comments on a line."
:version "21.1"
:type 'string
+ :safe 'stringp
:group 'fortran-comment)
-(put 'fortran-comment-line-start 'safe-local-variable 'stringp)
;; This used to match preprocessor lines too, but that messes up
;; filling and doesn't seem to be necessary.
"Regexp to match the start of a full-line comment."
:version "21.1"
:type 'regexp
+ :safe 'stringp
:group 'fortran-comment)
-(put 'fortran-comment-line-start-skip 'safe-local-variable 'stringp)
(defcustom fortran-directive-re
"^[ \t]*#.*"
The matching line will be given zero indentation."
:version "22.1"
:type 'regexp
+ :safe 'stringp
:group 'fortran-indent)
-(put 'fortran-directive-re 'safe-local-variable 'stringp)
(defcustom fortran-minimum-statement-indent-fixed 6
"Minimum statement indentation for fixed format continuation style."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-minimum-statement-indent-fixed 'safe-local-variable 'integerp)
(defcustom fortran-minimum-statement-indent-tab (max tab-width 6)
"Minimum statement indentation for TAB format continuation style."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-minimum-statement-indent-tab 'safe-local-variable 'integerp)
;; Note that this is documented in the v18 manuals as being a string
;; of length one rather than a single character.
"Single-character string inserted for Fortran comment indentation.
Normally a space."
:type 'string
+ :safe (lambda (value) (or (characterp value)
+ (and (stringp value) (= (length value) 1))))
:group 'fortran-comment)
-(put 'fortran-comment-indent-char 'safe-local-variable
- (lambda (value) (or (characterp value)
- (and (stringp value)
- (= (length value) 1)))))
(defcustom fortran-line-number-indent 1
"Maximum indentation for Fortran line numbers.
5 means right-justify them within their five-column field."
:type 'integer
+ :safe 'integerp
:group 'fortran-indent)
-(put 'fortran-line-number-indent 'safe-local-variable 'integerp)
(defcustom fortran-check-all-num-for-matching-do nil
"Non-nil causes all numbered lines to be treated as possible DO loop ends."
:type 'boolean
+ :safe 'booleanp
:group 'fortran)
-(put 'fortran-check-all-num-for-matching-do 'safe-local-variable 'booleanp)
(defcustom fortran-blink-matching-if nil
"Non-nil causes \\[fortran-indent-line] on ENDIF to blink on matching IF.
Also, from an ENDDO statement blink on matching DO [WHILE] statement."
:type 'boolean
+ :safe 'booleanp
:group 'fortran)
-(put 'fortran-blink-matching-if 'safe-local-variable 'booleanp)
(defcustom fortran-continuation-string "$"
"Single-character string used for Fortran continuation lines.
line, it will convert the line into a continuation line of the
appropriate style. Normally \"$\"."
:type 'string
+ :safe (lambda (value) (and (stringp value) (= (length value) 1)))
:group 'fortran)
-(put 'fortran-continuation-string 'safe-local-variable
- (lambda (value) (and (stringp value)
- (= (length value) 1))))
(defcustom fortran-comment-region "c$$$"
"String inserted by \\[fortran-comment-region] at start of each \
line in region."
:type 'string
+ :safe 'stringp
:group 'fortran-comment)
-(put 'fortran-comment-region 'safe-local-variable 'stringp)
(defcustom fortran-electric-line-number t
"Non-nil causes line numbers to be moved to the correct column as typed."
:type 'boolean
+ :safe 'booleanp
:group 'fortran)
-(put 'fortran-electric-line-number 'safe-local-variable 'booleanp)
;; TODO use fortran-line-length, somehow.
(defcustom fortran-column-ruler-fixed
This variable is used in fixed format mode.
See the variable `fortran-column-ruler-tab' for TAB format mode."
:type 'string
+ :safe 'stringp
:group 'fortran)
-(put 'fortran-column-ruler-fixed 'safe-local-variable 'stringp)
;; TODO use fortran-line-length, somehow.
(defcustom fortran-column-ruler-tab
This variable is used in TAB format mode.
See the variable `fortran-column-ruler-fixed' for fixed format mode."
:type 'string
+ :safe 'stringp
:group 'fortran)
-(put 'fortran-column-ruler-tab 'safe-local-variable 'stringp)
(defcustom fortran-analyze-depth 100
"Number of lines to scan to identify fixed or TAB format style."
:type 'integer
+ :safe 'integerp
:group 'fortran)
-(put 'fortran-analyze-depth 'safe-local-variable 'integerp)
(defcustom fortran-break-before-delimiters t
"Non-nil causes filling to break lines before delimiters.
Delimiters are characters matching the regexp `fortran-break-delimiters-re'."
:type 'boolean
+ :safe 'booleanp
:group 'fortran)
-(put 'fortran-break-before-delimiters 'safe-local-variable 'booleanp)
;; TODO 0 as no-limit, as per g77.
(defcustom fortran-line-length 72
buffer). This corresponds to the g77 compiler option
`-ffixed-line-length-N'."
:type 'integer
+ :safe 'integerp
:initialize 'custom-initialize-default
:set (lambda (symbol value)
;; Do all fortran buffers, and the default.
:version "23.1"
:group 'fortran)
-(put 'fortran-line-length 'safe-local-variable 'integerp)
(make-variable-buffer-local 'fortran-line-length)
(defcustom fortran-mode-hook nil
'("^ *\\([0-9]+\\)" . font-lock-constant-face)))
"Medium level highlighting for Fortran mode.")
+;; See bug#1385. Never really looked into _why_ this matters...
+(defun fortran-match-and-skip-declaration (limit)
+ "Like `font-lock-match-c-style-declaration-item-and-skip-to-next'.
+The only difference is, it returns t in a case when the default returns nil."
+ (when (looking-at "[ \n\t*]*\\(\\sw+\\)[ \t\n]*\\(((?\\)?")
+ (when (and (match-end 2) (> (- (match-end 2) (match-beginning 2)) 1))
+ (let ((pos (point)))
+ (skip-chars-backward " \t\n")
+ (skip-syntax-backward "w")
+ (unless (looking-at "\\(\\sw+\\)[ \t\n]*\\sw+[ \t\n]*\\(((?\\)?")
+ (goto-char pos)
+ (looking-at "[ \n\t*]*\\(\\sw+\\)[ \t\n]*\\(((?\\)?"))))
+ (save-match-data
+ (condition-case nil
+ (save-restriction
+ (narrow-to-region (point-min) limit)
+ (goto-char (match-end 1))
+ (while (not (looking-at "[ \t\n]*\\(\\(,\\)\\|;\\|\\'\\)"))
+ (goto-char (or (scan-sexps (point) 1) (point-max))))
+ (goto-char (match-end 2)))
+ (error t)))))
+
(defvar fortran-font-lock-keywords-3
(append
fortran-font-lock-keywords-1
;; Type specifier.
'(1 font-lock-type-face)
;; Declaration item (or just /.../ block name).
- `(font-lock-match-c-style-declaration-item-and-skip-to-next
+ `(fortran-match-and-skip-declaration
;; Start after any *(...) expression.
(condition-case nil
(and (match-beginning ,(1+ (regexp-opt-depth
\f
;;;###autoload
-(defun fortran-mode ()
+(define-derived-mode fortran-mode prog-mode "Fortran"
"Major mode for editing Fortran code in fixed format.
For free format code, use `f90-mode'.
Turning on Fortran mode calls the value of the variable `fortran-mode-hook'
with no args, if that value is non-nil."
- (interactive)
- (kill-all-local-variables)
- (setq major-mode 'fortran-mode
- mode-name "Fortran"
- local-abbrev-table fortran-mode-abbrev-table)
- (set-syntax-table fortran-mode-syntax-table)
- (use-local-map fortran-mode-map)
+ :group 'fortran
+ :syntax-table fortran-mode-syntax-table
+ :abbrev-table fortran-mode-abbrev-table
(set (make-local-variable 'indent-line-function) 'fortran-indent-line)
(set (make-local-variable 'indent-region-function)
(lambda (start end)
#'fortran-current-defun)
(set (make-local-variable 'dabbrev-case-fold-search) 'case-fold-search)
(set (make-local-variable 'gud-find-expr-function) 'fortran-gud-find-expr)
- (add-hook 'hack-local-variables-hook 'fortran-hack-local-variables nil t)
- (run-mode-hooks 'fortran-mode-hook))
+ (add-hook 'hack-local-variables-hook 'fortran-hack-local-variables nil t))
\f
(defun fortran-line-length (nchars &optional global)
not check for consistency of block types. Interactively, pushes
mark before moving point."
(interactive "p")
- (if (interactive-p) (push-mark (point) t))
+ (if (called-interactively-p 'any) (push-mark (point) t))
(and num (< num 0) (fortran-beginning-of-block (- num)))
(let ((case-fold-search t)
(count (or num 1)))
Does not check for consistency of block types. Interactively,
pushes mark before moving point."
(interactive "p")
- (if (interactive-p) (push-mark (point) t))
+ (if (called-interactively-p 'any) (push-mark (point) t))
(and num (< num 0) (fortran-end-of-block (- num)))
(let ((case-fold-search t)
(count (or num 1)))