;;; fortran.el --- Fortran mode for GNU Emacs
-;; Copyright (c) 1986, 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
+;; Copyright (c) 1986, 93, 94, 95, 97, 98, 1999 Free Software Foundation, Inc.
;; Author: Michael D. Prange <prange@erl.mit.edu>
;; Maintainer: Dave Love <fx@gnu.org>
(defgroup fortran nil
"Fortran mode for Emacs"
+ :link '(custom-manual "(emacs)Fortran")
:group 'languages)
(defgroup fortran-indent nil
(modify-syntax-entry ?/ "." fortran-mode-syntax-table)
(modify-syntax-entry ?\' "\"" fortran-mode-syntax-table)
(modify-syntax-entry ?\" "\"" fortran-mode-syntax-table)
- (modify-syntax-entry ?\\ "/" fortran-mode-syntax-table)
+ (modify-syntax-entry ?\\ "\\" fortran-mode-syntax-table)
;; This might be better as punctuation, as for C, but this way you
;; can treat floating-point numbers as symbols.
(modify-syntax-entry ?. "_" fortran-mode-syntax-table) ; e.g. `a.ne.b'
(modify-syntax-entry ?\! "<" fortran-mode-syntax-table)
(modify-syntax-entry ?\n ">" fortran-mode-syntax-table))
-;; Comments are real pain in Fortran because there is no way to represent the
-;; standard comment syntax in an Emacs syntax table (we can for VAX-style).
-;; Therefore an unmatched quote in a standard comment will throw fontification
-;; off on the wrong track. So we do syntactic fontification with regexps.
+;; Comments are real pain in Fortran because there is no way to
+;; represent the standard comment syntax in an Emacs syntax table.
+;; (We can do so for F90-style). Therefore an unmatched quote in a
+;; standard comment will throw fontification off on the wrong track.
+;; So we do syntactic fontification with regexps.
\f
;; Regexps done by simon@gnu with help from Ulrik Dickow <dickow@nbi.dk> and
;; probably others Si's forgotten about (sorry).
(defconst fortran-font-lock-keywords-3 nil
"Gaudy level highlighting for Fortran mode.")
-(defun fortran-fontify-string (limit)
- (let ((match (match-string 1)))
- (cond ((string= "'" match)
- (re-search-forward "\\([^'\n]*'?\\)" limit))
- ((string= "\"" match)
- (re-search-forward "\\([^\"\n]*\"?\\)" limit)))))
+(defconst fortran-font-lock-syntactic-keywords nil
+ "`font-lock-syntactic-keywords' for Fortran.
+These get fixed-format comments fontified.")
-(let ((comment-chars "c!*d") ; `d' for `debugging' comments
+(let ((comment-chars "cd") ; `d' for `debugging' comments
(fortran-type-types
-; (eval-when-compile
-; (regexp-opt
-; (let ((simple-types '("character" "byte" "integer" "logical"
-; "none" "real" "complex"
-; "double[ \t]*precision" "double[ \t]*complex"))
-; (structured-types '("structure" "union" "map"))
-; (other-types '("record" "dimension" "parameter" "common" "save"
-; "external" "intrinsic" "data" "equivalence")))
-; (append
-; (mapcar (lambda (x) (concat "implicit[ \t]*" x)) simple-types)
-; simple-types
-; (mapcar (lambda (x) (concat "end[ \t]*" x)) structured-types)
-; structured-types
-; other-types))))
- ;; Fixme:
- ;; Derived from the above, changing the escaped `[ \t]*'s back.
- ;; Should be done with a `replace all in string' function at compile time...
- "byte\\|c\\(haracter\\|om\\(mon\\|plex\\)\\)\\|d\\(ata\\|imension\\|ouble[ \t]*\\(complex\\|precision\\)\\)\\|e\\(nd[ \t]*\\(map\\|structure\\|union\\)\\|quivalence\\|xternal\\)\\|i\\(mplicit[ \t]*\\(byte\\|c\\(haracter\\|omplex\\)\\|double[ \t]*\\(complex\\|precision\\)\\|integer\\|logical\\|none\\|real\\)\\|nt\\(eger\\|rinsic\\)\\)\\|logical\\|map\\|none\\|parameter\\|re\\(al\\|cord\\)\\|s\\(ave\\|tructure\\)\\|union")
+ (eval-when-compile
+ (let ((re (regexp-opt
+ (let ((simple-types
+ '("character" "byte" "integer" "logical"
+ "none" "real" "complex"
+ "double precision" "double complex"))
+ (structured-types '("structure" "union" "map"))
+ (other-types '("record" "dimension"
+ "parameter" "common" "save"
+ "external" "intrinsic" "data"
+ "equivalence")))
+ (append
+ (mapcar (lambda (x) (concat "implicit " x))
+ simple-types)
+ simple-types
+ (mapcar (lambda (x) (concat "end " x))
+ structured-types)
+ structured-types
+ other-types)))))
+ ;; In the optimized regexp above, replace spaces by regexp
+ ;; for optional whitespace, which regexp-opt would have
+ ;; escaped.
+ (mapconcat #'identity (split-string re) "[ \t]*"))))
(fortran-keywords
(eval-when-compile
(regexp-opt '("continue" "format" "end" "enddo" "if" "then"
(regexp-opt '("and" "or" "not" "lt" "le" "eq" "ge" "gt" "ne"
"true" "false")))))
+ (setq fortran-font-lock-syntactic-keywords
+ ;; Fixed format comments. (!-style handled normally.)
+ (list
+ (list (concat "^[" comment-chars "]") 0 '(11))
+ (list (concat "^[^" comment-chars "\t\n]" (make-string 71 ?.)
+ "\\([^\n]+\\)")
+ 1 '(11))))
+
(setq fortran-font-lock-keywords-1
(list
;;
- ;; Fontify syntactically (assuming strings cannot be quoted
- ;; or span lines).
- (cons (concat "^[" comment-chars "].*") 'font-lock-comment-face)
- '(fortran-match-!-comment . font-lock-comment-face)
- (list (concat "^[^" comment-chars "\t\n]" (make-string 71 ?.)
- "\\(.*\\)")
- '(1 font-lock-comment-face))
- '("\\(\\s\"\\)" ; single- or double-quoted string
- (1 font-lock-string-face)
- (fortran-fontify-string nil nil (1 font-lock-string-face)))
- ;;
;; Program, subroutine and function declarations, plus calls.
(list (concat "\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|"
"program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?")
;; Fontify the type specifier.
'(1 font-lock-type-face)
;; Fontify each declaration item (or just the /.../ block name).
- '(font-lock-match-c-style-declaration-item-and-skip-to-next
+ `(font-lock-match-c-style-declaration-item-and-skip-to-next
;; Start after any *(...) expression.
- (and (match-beginning 15)
- (condition-case nil
- (forward-sexp)
- (error nil)))
+ (condition-case nil
+ (and (and (match-beginning ,(+ 2 (regexp-opt-depth
+ fortran-type-types)))
+ (forward-sexp))
+ (forward-sexp))
+ (error nil))
;; No need to clean up.
nil
;; Fontify as a variable name, functions are
fortran-font-lock-keywords-1
fortran-font-lock-keywords-2
fortran-font-lock-keywords-3)
- t t ((?/ . "$/") ("_$" . "w"))))
+ nil t ((?/ . "$/") ("_$" . "w"))
+ beginning-of-fortran-subprogram))
+ (set (make-local-variable 'font-lock-syntactic-keywords)
+ fortran-font-lock-syntactic-keywords)
(make-local-variable 'fortran-break-before-delimiters)
(setq fortran-break-before-delimiters t)
(make-local-variable 'indent-line-function)
(if (< (window-width) (frame-width))
(enlarge-window-horizontally (- (frame-width)
(window-width) 1)))
- (split-window-horizontally 73)
+ (let* ((window-edges (window-edges))
+ (scroll-bar-width (- (nth 2 window-edges)
+ (car window-edges)
+ (window-width))))
+ (split-window-horizontally (+ 72 scroll-bar-width)))
(other-window 1)
(switch-to-buffer " fortran-window-extra" t)
(select-window (previous-window))))
(defun beginning-of-fortran-subprogram ()
"Moves point to the beginning of the current Fortran subprogram."
(interactive)
- (let ((case-fold-search t))
- (beginning-of-line -1)
- (if (catch 'ok
- (while (re-search-backward fortran-end-prog-re nil 'move)
- (if (fortran-check-end-prog-re)
- (throw 'ok t))))
- (forward-line))))
+ (save-match-data
+ (let ((case-fold-search t))
+ (beginning-of-line -1)
+ (if (catch 'ok
+ (while (re-search-backward fortran-end-prog-re nil 'move)
+ (if (fortran-check-end-prog-re)
+ (throw 'ok t))))
+ (forward-line)))))
(defun end-of-fortran-subprogram ()
"Moves point to the end of the current Fortran subprogram."
(interactive)
- (let ((case-fold-search t))
- (if (save-excursion ; on END
- (beginning-of-line)
- (and (looking-at fortran-end-prog-re)
- (fortran-check-end-prog-re)))
- (forward-line)
- (beginning-of-line 2)
- (catch 'ok
- (while (re-search-forward fortran-end-prog-re nil 'move)
- (if (fortran-check-end-prog-re)
- (throw 'ok t))))
- (goto-char (match-beginning 0))
- (forward-line))))
+ (save-match-data
+ (let ((case-fold-search t))
+ (if (save-excursion ; on END
+ (beginning-of-line)
+ (and (looking-at fortran-end-prog-re)
+ (fortran-check-end-prog-re)))
+ (forward-line)
+ (beginning-of-line 2)
+ (catch 'ok
+ (while (re-search-forward fortran-end-prog-re nil 'move)
+ (if (fortran-check-end-prog-re)
+ (throw 'ok t))))
+ (goto-char (match-beginning 0))
+ (forward-line)))))
(defun mark-fortran-subprogram ()
"Put mark at end of Fortran subprogram, point at beginning.
The marks are pushed."
(interactive)
(end-of-fortran-subprogram)
- (push-mark (point))
+ (push-mark (point) nil t)
(beginning-of-fortran-subprogram))
(defun fortran-previous-statement ()
"Make text outside the current subprogram invisible.
The subprogram visible is the one that contains or follows point."
(interactive)
- (save-excursion
- (mark-fortran-subprogram)
- (narrow-to-region (region-beginning)
- (region-end))))
+ (save-excursion
+ (mark-fortran-subprogram)
+ (narrow-to-region (point) (mark))))
(defmacro fortran-with-subprogram-narrowing (&rest forms)
"Execute FORMS with buffer temporarily narrowed to current subprogram.
message)
(if (save-excursion (beginning-of-line)
(skip-chars-forward " \t0-9")
- (looking-at "end[ \t]*if\\b"))
+ (looking-at "e\\(nd[ \t]*if\\|lse\\([ \t]*if\\)?\\)\\b"))
(progn
(if (not (setq matching-if (fortran-beginning-if)))
(setq message "No matching if.")
t))
nil))
-;;From: simon@gnu (Simon Marshall)
-;; Find the next ! not in a string.
-(defun fortran-match-!-comment (limit)
- (let (found)
- (while (and (setq found (search-forward "!" limit t))
- (fortran-is-in-string-p (point))))
- (if (not found)
- nil
- ;; Cheaper than `looking-at' "!.*".
- (set-match-data
- (list (1- (point)) (progn (end-of-line) (min (point) limit))))
- t)))
-
-;; The above function is about 10% faster than the below...
-;;(defun fortran-match-!-comment (limit)
-;; (let (found)
-;; (while (and (setq found (re-search-forward "!.*" limit t))
-;; (fortran-is-in-string-p (match-beginning 0))))
-;; found))
-
;;From: ralf@up3aud1.gwdg.de (Ralf Fassel)
;; Test if TAB format continuation lines work.
(defun fortran-is-in-string-p (where)
(defun fortran-fill ()
(interactive)
- (let* ((opoint (point))
+ (let* ((auto-fill-function #'fortran-do-auto-fill)
+ (opoint (point))
(bol (save-excursion (beginning-of-line) (point)))
(eol (save-excursion (end-of-line) (point)))
(bos (min eol (+ bol (fortran-current-line-indentation))))
(defun fortran-fill-statement ()
"Fill a fortran statement up to `fill-column'."
(interactive)
- (if (not (save-excursion
- (beginning-of-line)
- (or (looking-at "[ \t]*$")
- (looking-at comment-line-start-skip)
- (and comment-start-skip
- (looking-at (concat "[ \t]*" comment-start-skip))))))
- (save-excursion
- ;; Find beginning of statement.
- (fortran-next-statement)
- (fortran-previous-statement)
- ;; Re-indent initially.
- (fortran-indent-line)
- ;; Replace newline plus continuation field plus indentation with
- ;; single space.
- (while (progn
- (forward-line)
- (fortran-remove-continuation)))
- (fortran-previous-statement)))
- (fortran-indent-line))
+ (let ((auto-fill-function #'fortran-do-auto-fill))
+ (if (not (save-excursion
+ (beginning-of-line)
+ (or (looking-at "[ \t]*$")
+ (looking-at comment-line-start-skip)
+ (and comment-start-skip
+ (looking-at (concat "[ \t]*" comment-start-skip))))))
+ (save-excursion
+ ;; Find beginning of statement.
+ (fortran-next-statement)
+ (fortran-previous-statement)
+ ;; Re-indent initially.
+ (fortran-indent-line)
+ ;; Replace newline plus continuation field plus indentation with
+ ;; single space.
+ (while (progn
+ (forward-line)
+ (fortran-remove-continuation)))
+ (fortran-previous-statement)))
+ (fortran-indent-line)))
(provide 'fortran)