Mercurial > emacs
changeset 21410:d68f866455c6
Use regexp-opt and eval-and-compile to
build font-lock patterns.
(fortran-mode): Define indent-region-function,
indent-line-function.
(fortran-tab-mode-string): Make buffer-local.
(fortran-comment-indent-style): Custom tweak.
(fortran-comment-region, fortran-electric-line-number,
fortran-analyze-depth, fortran-break-before-delimiters,
fortran-mode): Doc fix.
(fortran-startup-message, bug-fortran-mode): Variables
deleted.
(fortran-font-lock-keywords-1): Add "select", "case"; allow
double-quoted strings.
(fortran-mode-map): Add fill-paragraph menu item. Don't
define \t.
(fortran-mode): Make `fill-column' buffer-local; set
`fill-paragraph-function', `indent-region-function',
`indent-line-function'.
(calculate-fortran-indent): Renamed to:
(fortran-calculate-indent):
(fortran-split-line): Simplify.
(fortran-remove-continuation): New function.
(fortran-join-line): Use it.
(fortran-end-prog-re1, fortran-end-prog-re): New variables.
(beginning-of-fortran-subprogram, end-of-fortran-subprogram):
Use them.
(fortran-blink-matching-if, fortran-blink-matching-do,
fortran-indent-new-line): Bind case-fold-search.
(fortran-end-do, fortran-beginning-do, fortran-end-if,
fortran-beginning-if): Bind case-fold-search. Allow labelled
blocks. Use fortran-end-prog-re.
(fortran-if-start-re): New variable.
(fortran-calculate-indent): Allow labelled blocks. Simplify the
conds. Make select case indentation work.
(fortran-is-in-string-p): Ignore Emacs 18 bug kluge.
(fortran-fill): Allow double quotes in check for string.
(fortran-fill-paragraph): New function.
(fortran-fill-statement): New function.
author | Dave Love <fx@gnu.org> |
---|---|
date | Tue, 07 Apr 1998 18:59:44 +0000 |
parents | 3e8b7782f4f5 |
children | 6fcc2c9a1857 |
files | lisp/progmodes/fortran.el |
diffstat | 1 files changed, 398 insertions(+), 329 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/progmodes/fortran.el Tue Apr 07 18:22:28 1998 +0000 +++ b/lisp/progmodes/fortran.el Tue Apr 07 18:59:44 1998 +0000 @@ -42,6 +42,13 @@ ;;; Code: +;; Todo: + +;; * Implement insertion and removal of statement continuations in +;; mixed f77/f90 style, with the first `&' past column 72 and the +;; second in column 6. +;; * Support other f90-style stuff grokked by GNU Fortran. + (require 'easymenu) (defgroup fortran nil @@ -73,6 +80,7 @@ "String to appear in mode line when TAB format mode is on." :type '(choice (const nil) string) :group 'fortran-indent) +(make-variable-buffer-local 'fortran-tab-mode-string) (defcustom fortran-do-indent 3 "*Extra indentation applied to DO blocks." @@ -102,7 +110,7 @@ `indent-tabs-mode' of nil) or `fortran-minimum-statement-indent-tab' (for `indent-tabs-mode' of t), and 'relative indents to current Fortran indentation plus `fortran-comment-line-extra-indent'." - :type '(radio (const nil) (const fixed) (const relative)) + :type '(radio (const :tag "Untouched" nil) (const fixed) (const relative)) :group 'fortran-indent) (defcustom fortran-comment-line-extra-indent 0 @@ -168,19 +176,14 @@ :group 'fortran) (defcustom fortran-comment-region "c$$$" - "*String inserted by \\[fortran-comment-region]\ -at start of each line in region." + "*String inserted by \\[fortran-comment-region] at start of each \ +line in region." :type 'string :group 'fortran-comment) (defcustom fortran-electric-line-number t - "*Non-nil causes line number digits to be moved to the correct column as\ -typed." - :type 'boolean - :group 'fortran) - -(defcustom fortran-startup-message t - "*Non-nil displays a startup message when Fortran mode is first called." + "*Non-nil causes line number digits to be moved to the correct \ +column as typed." :type 'boolean :group 'fortran) @@ -204,11 +207,11 @@ "Syntax table in use in Fortran mode buffers.") (defvar fortran-analyze-depth 100 - "Number of lines to scan to determine whether to use fixed or TAB format\ -style.") + "Number of lines to scan to determine whether to use fixed or TAB \ +format style.") (defcustom fortran-break-before-delimiters t - "*Non-nil causes `fortran-fill' to break lines before delimiters." + "*Non-nil causes filling to break lines before delimiters." :type 'boolean :group 'fortran) @@ -252,115 +255,109 @@ (defconst fortran-font-lock-keywords-3 nil "Gaudy level highlighting for Fortran mode.") -(let ((comment-chars "c!*") - (fortran-type-types -; (make-regexp -; (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))) - (concat "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")) - (fortran-keywords -; ("continue" "format" "end" "enddo" "if" "then" "else" "endif" -; "elseif" "while" "inquire" "stop" "return" "include" "open" -; "close" "read" "write" "format" "print") - (concat "c\\(lose\\|ontinue\\)\\|" - "e\\(lse\\(\\|if\\)\\|nd\\(\\|do\\|if\\)\\)\\|format\\|" - "i\\(f\\|n\\(clude\\|quire\\)\\)\\|open\\|print\\|" - "re\\(ad\\|turn\\)\\|stop\\|then\\|w\\(hile\\|rite\\)")) +(eval-and-compile + (let ((comment-chars "c!*") + (fortran-type-types + (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)))) + (fortran-keywords + (regexp-opt '("continue" "format" "end" "enddo" "if" "then" + "else" "endif" "elseif" "while" "inquire" "stop" + "return" "include" "open" "close" "read" "write" + "format" "print" "select" "case"))) (fortran-logicals -; ("and" "or" "not" "lt" "le" "eq" "ge" "gt" "ne" "true" "false") - "and\\|eq\\|false\\|g[et]\\|l[et]\\|n\\(e\\|ot\\)\\|or\\|true")) + (regexp-opt '("and" "or" "not" "lt" "le" "eq" "ge" "gt" "ne" + "true" "false")))) - (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)) - '("'[^'\n]*'?" . font-lock-string-face) - ;; - ;; Program, subroutine and function declarations, plus calls. - (list (concat "\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|" - "program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?") - '(1 font-lock-keyword-face) - '(2 font-lock-function-name-face nil t)))) + (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\"\\)\"[^\n]*\\1?" . font-lock-string-face) + ;; + ;; Program, subroutine and function declarations, plus calls. + (list (concat "\\<\\(block[ \t]*data\\|call\\|entry\\|function\\|" + "program\\|subroutine\\)\\>[ \t]*\\(\\sw+\\)?") + '(1 font-lock-keyword-face) + '(2 font-lock-function-name-face nil t)))) - (setq fortran-font-lock-keywords-2 - (append fortran-font-lock-keywords-1 - (list - ;; - ;; Fontify all type specifiers (must be first; see below). - (cons (concat "\\<\\(" fortran-type-types "\\)\\>") 'font-lock-type-face) - ;; - ;; Fontify all builtin keywords (except logical, do and goto; see below). - (concat "\\<\\(" fortran-keywords "\\)\\>") - ;; - ;; Fontify all builtin operators. - (concat "\\.\\(" fortran-logicals "\\)\\.") - ;; - ;; Fontify do/goto keywords and targets, and goto tags. - (list "\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?" - '(1 font-lock-keyword-face) - '(2 font-lock-constant-face nil t)) - (cons "^ *\\([0-9]+\\)" 'font-lock-constant-face)))) + (setq fortran-font-lock-keywords-2 + (append fortran-font-lock-keywords-1 + (list + ;; + ;; Fontify all type specifiers (must be first; see below). + (cons (concat "\\<\\(" fortran-type-types "\\)\\>") + 'font-lock-type-face) + ;; + ;; Fontify all builtin keywords (except logical, do + ;; and goto; see below). + (concat "\\<\\(" fortran-keywords "\\)\\>") + ;; + ;; Fontify all builtin operators. + (concat "\\.\\(" fortran-logicals "\\)\\.") + ;; + ;; Fontify do/goto keywords and targets, and goto tags. + (list "\\<\\(do\\|go *to\\)\\>[ \t]*\\([0-9]+\\)?" + '(1 font-lock-keyword-face) + '(2 font-lock-constant-face nil t)) + (cons "^ *\\([0-9]+\\)" 'font-lock-constant-face)))) - (setq fortran-font-lock-keywords-3 - (append - ;; - ;; The list `fortran-font-lock-keywords-1'. - fortran-font-lock-keywords-1 - ;; - ;; Fontify all type specifiers plus their declared items. - (list - (list (concat "\\<\\(" fortran-type-types "\\)\\>[ \t(/]*\\(*\\)?") - ;; 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 - ;; Start after any *(...) expression. - (and (match-beginning 15) (forward-sexp 1)) - ;; No need to clean up. - nil - ;; Fontify as a variable name, functions are fontified elsewhere. - (1 font-lock-variable-name-face nil t)))) - ;; - ;; Things extra to `fortran-font-lock-keywords-3' (must be done first). - (list - ;; - ;; Fontify goto-like `err=label'/`end=label' in read/write statements. - '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?" - (1 font-lock-keyword-face) (4 font-lock-constant-face nil t)) - ;; - ;; Highlight standard continuation character and in a TAB-formatted line. - '("^ \\([^ 0]\\)" 1 font-lock-string-face) - '("^\t\\([1-9]\\)" 1 font-lock-string-face)) - ;; - ;; The list `fortran-font-lock-keywords-2' less that for types (see above). - (cdr (nthcdr (length fortran-font-lock-keywords-1) - fortran-font-lock-keywords-2)))) - ) + (setq fortran-font-lock-keywords-3 + (append + ;; + ;; The list `fortran-font-lock-keywords-1'. + fortran-font-lock-keywords-1 + ;; + ;; Fontify all type specifiers plus their declared items. + (list + (list (concat "\\<\\(" fortran-type-types "\\)\\>[ \t(/]*\\(*\\)?") + ;; 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 + ;; Start after any *(...) expression. + (and (match-beginning 15) (forward-sexp)) + ;; No need to clean up. + nil + ;; Fontify as a variable name, functions are + ;; fontified elsewhere. + (1 font-lock-variable-name-face nil t)))) + ;; + ;; Things extra to `fortran-font-lock-keywords-3' + ;; (must be done first). + (list + ;; + ;; Fontify goto-like `err=label'/`end=label' in read/write + ;; statements. + '(", *\\(e\\(nd\\|rr\\)\\)\\> *\\(= *\\([0-9]+\\)\\)?" + (1 font-lock-keyword-face) (4 font-lock-constant-face nil t)) + ;; + ;; Highlight standard continuation character and in a + ;; TAB-formatted line. + '("^ \\([^ 0]\\)" 1 font-lock-string-face) + '("^\t\\([1-9]\\)" 1 font-lock-string-face)) + ;; + ;; The list `fortran-font-lock-keywords-2' less that for types + ;; (see above). + (cdr (nthcdr (length fortran-font-lock-keywords-1) + fortran-font-lock-keywords-2)))))) (defvar fortran-font-lock-keywords fortran-font-lock-keywords-1 "Default expressions to highlight in Fortran mode.") @@ -378,8 +375,9 @@ ;; index. [This will be fooled by `end function' allowed by G77. ;; Also, it assumes sensible whitespace is employed.] (concat "^\\s-+\\(\ -\\(\\sw\\|\\s-\\|[*()+]\\)*\\<function\\|\ -subroutine\\|entry\\|block\\s-*data\\|program\\)[ \t" fortran-continuation-string "]+\ +\\(\\sw\\|\\s-\\|[*()+]\\)*\ +\\<function\\|subroutine\\|entry\\|block\\s-*data\\|program\\)\ +[ \t" fortran-continuation-string "]+\ \\(\\sw+\\)") 3) ;; Un-named block data @@ -406,7 +404,7 @@ (define-key fortran-mode-map "\C-c\C-n" 'fortran-next-statement) (define-key fortran-mode-map "\C-c\C-d" 'fortran-join-line) (define-key fortran-mode-map "\C-xnd" 'fortran-narrow-to-subprogram) - (define-key fortran-mode-map "\t" 'fortran-indent-line) + ;(define-key fortran-mode-map "\t" 'fortran-indent-line) (define-key fortran-mode-map "0" 'fortran-electric-line-number) (define-key fortran-mode-map "1" 'fortran-electric-line-number) (define-key fortran-mode-map "2" 'fortran-electric-line-number) @@ -452,6 +450,7 @@ "----" ["Break Line at Point" fortran-split-line t] ["Join Continuation Line" fortran-join-line t] + ["Fill Statement/Comment" fill-paragraph t] "----" ["Add imenu menu" (progn (imenu-add-to-menubar "Index") @@ -524,7 +523,9 @@ (define-abbrev fortran-mode-abbrev-table ";wh" "where" nil) (setq abbrevs-changed ac))) -(eval-when-compile (defvar imenu-syntax-alist nil)) ; silence compiler +(eval-when-compile ; silence compiler + (defvar imenu-case-fold-search) + (defvar imenu-syntax-alist)) ;;;###autoload (defun fortran-mode () @@ -532,8 +533,8 @@ \\[fortran-indent-line] indents the current Fortran line correctly. DO statements must not share a common CONTINUE. -Type ;? or ;\\[help-command] to display a list of built-in\ - abbrevs for Fortran keywords. +Type ;? or ;\\[help-command] to display a list of built-in abbrevs for +Fortran keywords. Key definitions: \\{fortran-mode-map} @@ -591,7 +592,7 @@ Non-nil causes line number digits to be moved to the correct column as typed. (default t) fortran-break-before-delimiters - Non-nil causes `fortran-fill' breaks lines before delimiters. + Non-nil causes `fortran-fill' to break lines before delimiters. (default t) Turning on Fortran mode calls the value of the variable `fortran-mode-hook' @@ -629,23 +630,28 @@ (make-local-variable 'indent-tabs-mode) (setq indent-tabs-mode nil) ;;;(setq abbrev-mode t) ; ?? (abbrev-mode 1) instead?? - (setq fill-column 72) ; Already local? + (set (make-local-variable 'fill-column) 72) (use-local-map fortran-mode-map) (setq mode-name "Fortran") (setq major-mode 'fortran-mode) -;;;(make-local-variable 'fortran-tab-mode) (make-local-variable 'fortran-comment-line-extra-indent) (make-local-variable 'fortran-minimum-statement-indent-fixed) (make-local-variable 'fortran-minimum-statement-indent-tab) (make-local-variable 'fortran-column-ruler-fixed) - (make-local-variable 'fortran-column-ruler-tab) - (make-local-variable 'fortran-tab-mode-string) + (make-local-variable 'fortran-column-ruler-tab) (setq fortran-tab-mode-string " TAB-format") (setq indent-tabs-mode (fortran-analyze-file-format)) (setq imenu-case-fold-search t) (make-local-variable 'imenu-generic-expression) (setq imenu-generic-expression fortran-imenu-generic-expression) (setq imenu-syntax-alist '(("_$" . "w"))) + (set (make-local-variable 'fill-paragraph-function) 'fortran-fill-paragraph) + (set (make-local-variable 'indent-line-function) 'fortran-indent-line) + (set (make-local-variable 'indent-region-function) + (lambda (start end) + (let (fortran-blink-matching-if ; avoid blinking delay + indent-region-function) + (indent-region start end nil)))) (run-hooks 'fortran-mode-hook)) (defun fortran-comment-hook () @@ -693,7 +699,7 @@ (insert-char (if (stringp fortran-comment-indent-char) (aref fortran-comment-indent-char 0) fortran-comment-indent-char) - (- (calculate-fortran-indent) (current-column)))))) + (- (fortran-calculate-indent) (current-column)))))) (defun fortran-comment-region (beg-region end-region arg) "Comments every line in the region. @@ -806,26 +812,23 @@ (if (save-excursion (beginning-of-line) (looking-at comment-line-start-skip)) (insert "\n" comment-line-start " ") (if indent-tabs-mode - (progn - (insert "\n\t") - (insert-char (fortran-numerical-continuation-char) 1)) - (insert "\n " fortran-continuation-string)));Space after \n important - (fortran-indent-line)) ;when the cont string is C, c or *. + (insert "\n\t" (fortran-numerical-continuation-char)) + (insert "\n " fortran-continuation-string))) ; Space after \n important + (fortran-indent-line)) ; when the cont string is C, c or *. + +(defun fortran-remove-continuation () + (if (looking-at "\\( [^ 0\n]\\|\t[1-9]\\|&\\)") + (progn (replace-match "") + (delete-indentation) + t))) (defun fortran-join-line () "Join a continuation line to the previous one and re-indent." (interactive) (save-excursion (beginning-of-line) - (cond ((looking-at " \\S-") - (delete-region (1- (point)) (+ (point) 7))) - ((looking-at "&") - (delete-region (1- (point)) (1+ (point)))) - ((looking-at " *\t[1-9]") - (apply 'delete-region (match-data)) - (delete-backward-char 1)) - (t (error "This isn't a continuation line"))) - (just-one-space) + (if (not (fortran-remove-continuation)) + (error "Not a continuation line")) (fortran-indent-line))) (defun fortran-numerical-continuation-char () @@ -859,8 +862,8 @@ (beginning-of-line) (looking-at " ")));In col 5 with only spaces to left. (and (= (if indent-tabs-mode - fortran-minimum-statement-indent-tab - fortran-minimum-statement-indent-fixed) (current-column)) + fortran-minimum-statement-indent-tab + fortran-minimum-statement-indent-fixed) (current-column)) (save-excursion (beginning-of-line) (looking-at "\t"));In col 8 with a single tab to the left. @@ -872,31 +875,34 @@ (save-excursion (beginning-of-line) (point)) - t)) ;not a line number - (looking-at "[0-9]") ;within a line number - ) + t)) ;not a line number + (looking-at "[0-9]")) ;within a line number (self-insert-command (prefix-numeric-value arg)) (skip-chars-backward " \t") (insert last-command-char) (fortran-indent-line)))) +(defvar fortran-end-prog-re1 + "end\\b[ \t]*\\(\\(program\\|subroutine\\|function\\)[ \t]*\\)?[^ \t=\(a-z]") +(defvar fortran-end-prog-re + (concat "^[ \t0-9]*" fortran-end-prog-re1)) + (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) - (re-search-backward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move) - (if (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]") - (forward-line 1)))) + (if (re-search-backward fortran-end-prog-re nil 'move) + (forward-line)))) (defun end-of-fortran-subprogram () "Moves point to the end of the current Fortran subprogram." (interactive) (let ((case-fold-search t)) (beginning-of-line 2) - (re-search-forward "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]" nil 'move) + (re-search-forward fortran-end-prog-re nil 'move) (goto-char (match-beginning 0)) - (forward-line 1))) + (forward-line))) (defun mark-fortran-subprogram () "Put mark at end of Fortran subprogram, point at beginning. @@ -963,8 +969,11 @@ (defun fortran-blink-matching-if () ;; From a Fortran ENDIF statement, blink the matching IF statement. - (let ((top-of-window (window-start)) matching-if - (endif-point (point)) message) + (let ((top-of-window (window-start)) + (endif-point (point)) + (case-fold-search t) + matching-if + message) (if (save-excursion (beginning-of-line) (skip-chars-forward " \t0-9") (looking-at "end[ \t]*if\\b")) @@ -988,8 +997,11 @@ (defun fortran-blink-matching-do () ;; From a Fortran ENDDO statement, blink on the matching DO or DO WHILE ;; statement. This is basically copied from fortran-blink-matching-if. - (let ((top-of-window (window-start)) matching-do - (enddo-point (point)) message) + (let ((top-of-window (window-start)) + (enddo-point (point)) + (case-fold-search t) + matching-do + message) (if (save-excursion (beginning-of-line) (skip-chars-forward " \t0-9") (looking-at "end[ \t]*do\\b")) @@ -1025,52 +1037,54 @@ (defun fortran-end-do () ;; Search forward for first unmatched ENDDO. Return point or nil. - (if (save-excursion (beginning-of-line) - (skip-chars-forward " \t0-9") - (looking-at "end[ \t]*do\\b")) - ;; Sitting on one. - (match-beginning 0) - ;; Search for one. - (save-excursion - (let ((count 1)) + (let ((case-fold-search t)) + (if (save-excursion (beginning-of-line) + (skip-chars-forward " \t0-9") + (looking-at "end[ \t]*do\\b")) + ;; Sitting on one. + (match-beginning 0) + ;; Search for one. + (save-excursion + (let ((count 1)) (while (and (not (= count 0)) - (not (eq (fortran-next-statement) 'last-statement)) - ;; Keep local to subprogram - (not (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]"))) + (not (eq (fortran-next-statement) 'last-statement)) + ;; Keep local to subprogram + (not (looking-at fortran-end-prog-re))) - (skip-chars-forward " \t0-9") - (cond ((looking-at "end[ \t]*do\\b") - (setq count (- count 1))) - ((looking-at "do[ \t]+[^0-9]") + (skip-chars-forward " \t0-9") + (cond ((looking-at "end[ \t]*do\\b") + (setq count (1- count))) + ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]") (setq count (+ count 1))))) (and (= count 0) - ;; All pairs accounted for. - (point)))))) + ;; All pairs accounted for. + (point))))))) (defun fortran-beginning-do () ;; Search backwards for first unmatched DO [WHILE]. Return point or nil. - (if (save-excursion (beginning-of-line) - (skip-chars-forward " \t0-9") - (looking-at "do[ \t]+")) - ;; Sitting on one. - (match-beginning 0) - ;; Search for one. - (save-excursion - (let ((count 1)) + (let ((case-fold-search t)) + (if (save-excursion (beginning-of-line) + (skip-chars-forward " \t0-9") + (looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+")) + ;; Sitting on one. + (match-beginning 0) + ;; Search for one. + (save-excursion + (let ((count 1)) (while (and (not (= count 0)) - (not (eq (fortran-previous-statement) 'first-statement)) - ;; Keep local to subprogram - (not (looking-at "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]"))) + (not (eq (fortran-previous-statement) 'first-statement)) + ;; Keep local to subprogram + (not (looking-at fortran-end-prog-re))) - (skip-chars-forward " \t0-9") - (cond ((looking-at "do[ \t]+[^0-9]") - (setq count (- count 1))) - ((looking-at "end[ \t]*do\\b") - (setq count (+ count 1))))) + (skip-chars-forward " \t0-9") + (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?do[ \t]+[^0-9]") + (setq count (1- count))) + ((looking-at "end[ \t]*do\\b") + (setq count (1+ count))))) (and (= count 0) - ;; All pairs accounted for. - (point)))))) + ;; All pairs accounted for. + (point))))))) (defun fortran-mark-if () "Put mark at end of Fortran IF-ENDIF construct, point at beginning. @@ -1085,113 +1099,115 @@ (push-mark) (goto-char if-point))))) +(defvar fortran-if-start-re "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(") + (defun fortran-end-if () ;; Search forwards for first unmatched ENDIF. Return point or nil. - (if (save-excursion (beginning-of-line) - (skip-chars-forward " \t0-9") - (looking-at "end[ \t]*if\\b")) - ;; Sitting on one. - (match-beginning 0) - ;; Search for one. The point has been already been moved to first - ;; letter on line but this should not cause troubles. - (save-excursion - (let ((count 1)) + (let ((case-fold-search t)) + (if (save-excursion (beginning-of-line) + (skip-chars-forward " \t0-9") + (looking-at "end[ \t]*if\\b")) + ;; Sitting on one. + (match-beginning 0) + ;; Search for one. The point has been already been moved to first + ;; letter on line but this should not cause troubles. + (save-excursion + (let ((count 1)) (while (and (not (= count 0)) - (not (eq (fortran-next-statement) 'last-statement)) - ;; Keep local to subprogram. - (not (looking-at - "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]"))) + (not (eq (fortran-next-statement) 'last-statement)) + ;; Keep local to subprogram. + (not (looking-at fortran-end-prog-re))) - (skip-chars-forward " \t0-9") - (cond ((looking-at "end[ \t]*if\\b") + (skip-chars-forward " \t0-9") + (cond ((looking-at "end[ \t]*if\\b") (setq count (- count 1))) - ((looking-at "if[ \t]*(") - (save-excursion - (if (or - (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") - (let (then-test) ; Multi-line if-then. - (while + ((looking-at fortran-if-start-re) + (save-excursion + (if (or + (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") + (let (then-test) ; Multi-line if-then. + (while (and (= (forward-line 1) 0) - ;; Search forward for then. - (or (looking-at " [^ 0\n]") - (looking-at "\t[1-9]")) - (not - (setq then-test - (looking-at - ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) - then-test)) + ;; Search forward for then. + (or (looking-at " [^ 0\n]") + (looking-at "\t[1-9]")) + (not + (setq then-test + (looking-at + ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) + then-test)) (setq count (+ count 1))))))) (and (= count 0) - ;; All pairs accounted for. - (point)))))) + ;; All pairs accounted for. + (point))))))) (defun fortran-beginning-if () ;; Search backwards for first unmatched IF-THEN. Return point or nil. - (if (save-excursion - ;; May be sitting on multi-line if-then statement, first move to - ;; beginning of current statement. Note: `fortran-previous-statement' - ;; moves to previous statement *unless* current statement is first - ;; one. Only move forward if not first-statement. - (if (not (eq (fortran-previous-statement) 'first-statement)) - (fortran-next-statement)) - (skip-chars-forward " \t0-9") - (and - (looking-at "if[ \t]*(") - (save-match-data - (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") - ;; Multi-line if-then. - (let (then-test) - (while + (let ((case-fold-search t)) + (if (save-excursion + ;; May be sitting on multi-line if-then statement, first move to + ;; beginning of current statement. Note: `fortran-previous-statement' + ;; moves to previous statement *unless* current statement is first + ;; one. Only move forward if not first-statement. + (if (not (eq (fortran-previous-statement) 'first-statement)) + (fortran-next-statement)) + (skip-chars-forward " \t0-9") + (and + (looking-at fortran-if-start-re) + (save-match-data + (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") + ;; Multi-line if-then. + (let (then-test) + (while (and (= (forward-line 1) 0) - ;; Search forward for then. - (or (looking-at " [^ 0\n]") - (looking-at "\t[1-9]")) - (not - (setq then-test - (looking-at - ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) - then-test))))) - ;; Sitting on one. - (match-beginning 0) - ;; Search for one. - (save-excursion - (let ((count 1)) + ;; Search forward for then. + (or (looking-at " [^ 0\n]") + (looking-at "\t[1-9]")) + (not + (setq then-test + (looking-at + ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) + then-test))))) + ;; Sitting on one. + (match-beginning 0) + ;; Search for one. + (save-excursion + (let ((count 1)) (while (and (not (= count 0)) - (not (eq (fortran-previous-statement) 'first-statement)) - ;; Keep local to subprogram. - (not (looking-at - "^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]"))) + (not (eq (fortran-previous-statement) 'first-statement)) + ;; Keep local to subprogram. + (not (looking-at fortran-end-prog-re))) - (skip-chars-forward " \t0-9") - (cond ((looking-at "if[ \t]*(") - (save-excursion - (if (or - (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") - (let (then-test) ; Multi-line if-then. - (while + (skip-chars-forward " \t0-9") + (cond ((looking-at fortran-if-start-re) + (save-excursion + (if (or + (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") + (let (then-test) ; Multi-line if-then. + (while (and (= (forward-line 1) 0) - ;; Search forward for then. - (or (looking-at " [^ 0\n]") - (looking-at "\t[1-9]")) - (not - (setq then-test - (looking-at - ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) - then-test)) + ;; Search forward for then. + (or (looking-at " [^ 0\n]") + (looking-at "\t[1-9]")) + (not + (setq then-test + (looking-at + ".*then\\b[ \t]*[^ \t(=a-z0-9]"))))) + then-test)) (setq count (- count 1))))) - ((looking-at "end[ \t]*if\\b") + ((looking-at "end[ \t]*if\\b") (setq count (+ count 1))))) (and (= count 0) - ;; All pairs accounted for. - (point)))))) + ;; All pairs accounted for. + (point))))))) (defun fortran-indent-line () "Indent current Fortran line based on its contents and on previous lines." (interactive) - (let ((cfi (calculate-fortran-indent))) + (let ((cfi (fortran-calculate-indent))) (save-excursion (beginning-of-line) (if (or (not (= cfi (fortran-current-line-indentation))) @@ -1223,11 +1239,12 @@ (save-excursion (beginning-of-line) (skip-chars-forward " \t") - (if (or (looking-at "[0-9]") ;Reindent only where it is most - (looking-at "end") ;likely to be necessary - (looking-at "else") - (looking-at (regexp-quote fortran-continuation-string))) - (fortran-indent-line))) + (let ((case-fold-search t)) + (if (or (looking-at "[0-9]") ;Reindent only where it is most + (looking-at "end") ;likely to be necessary + (looking-at "else") + (looking-at (regexp-quote fortran-continuation-string))) + (fortran-indent-line)))) (newline) (fortran-indent-line)) @@ -1240,7 +1257,7 @@ (indent-region (point) (mark) nil)) (message "Indenting subprogram...done.")) -(defun calculate-fortran-indent () +(defun fortran-calculate-indent () "Calculates the Fortran indent column based on previous lines." (let (icol first-statement (case-fold-search t) (fortran-minimum-statement-indent @@ -1256,7 +1273,7 @@ (setq icol fortran-minimum-statement-indent) (setq icol (fortran-current-line-indentation))) (skip-chars-forward " \t0-9") - (cond ((looking-at "if[ \t]*(") + (cond ((looking-at "\\(\\(\\sw\\|\\s_\\)+:[ \t]*\\)?if[ \t]*(") (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t_$(=a-z0-9]") (let (then-test) ;multi-line if-then (while (and (= (forward-line 1) 0) @@ -1268,11 +1285,11 @@ *[^ \t_$(=a-z0-9]"))))) then-test)) (setq icol (+ icol fortran-if-indent)))) - ((looking-at "\\(else\\|elseif\\)\\b") + ((looking-at "else\\(if\\)?\\b") (setq icol (+ icol fortran-if-indent))) - ((looking-at "select[ \t]*case[ \t](.*)\\b") + ((looking-at "select[ \t]*case[ \t](.*)") (setq icol (+ icol fortran-if-indent))) - ((looking-at "case[ \t]*(.*)[ \t]*\n") + ((looking-at "case[ \t]*(.*)") (setq icol (+ icol fortran-if-indent))) ((looking-at "case[ \t]*default\\b") (setq icol (+ icol fortran-if-indent))) @@ -1285,7 +1302,7 @@ ((looking-at "\\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]") (setq icol (+ icol fortran-structure-indent))) - ((looking-at "end\\b[ \t]*[^ \t=(a-z]") + ((looking-at fortran-end-prog-re1) ;; Previous END resets indent to minimum (setq icol fortran-minimum-statement-indent)))))) (save-excursion @@ -1313,31 +1330,23 @@ (setq icol (- icol fortran-do-indent))) (t (skip-chars-forward " \t0-9") - (cond ((looking-at "end[ \t]*if\\b") - (setq icol (- icol fortran-if-indent))) - ((looking-at "\\(else\\|elseif\\)\\b") + (cond ((looking-at "end[ \t]*\\(if\\|select\\|where\\)\\b") (setq icol (- icol fortran-if-indent))) - ((looking-at "case[ \t]*(.*)[ \t]*\n") + ((looking-at "else\\(if\\)?\\b") (setq icol (- icol fortran-if-indent))) - ((looking-at "case[ \t]*default\\b") + ((looking-at "case[ \t]*\\((.*)\\|default\\>\\)") (setq icol (- icol fortran-if-indent))) ((looking-at "\\(otherwise\\|else[ \t]*where\\)\\b") (setq icol (- icol fortran-if-indent))) - ((looking-at "end[ \t]*where\\b") - (setq icol (- icol fortran-if-indent))) ((and (looking-at "continue\\b") (fortran-check-for-matching-do)) (setq icol (- icol fortran-do-indent))) ((looking-at "end[ \t]*do\\b") (setq icol (- icol fortran-do-indent))) - ((looking-at - "end[ \t]*\ + ((looking-at "end[ \t]*\ \\(structure\\|union\\|map\\|interface\\)\\b[ \t]*[^ \t=(a-z]") (setq icol (- icol fortran-structure-indent))) - ((looking-at - "end[ \t]*select\\b[ \t]*[^ \t=(a-z]") - (setq icol (- icol fortran-if-indent))) - ((and (looking-at "end\\b[ \t]*[^ \t=(a-z]") + ((and (looking-at fortran-end-prog-re1) (not (= icol fortran-minimum-statement-indent))) (message "Warning: `end' not in column %d. Probably\ an unclosed block." fortran-minimum-statement-indent)))))) @@ -1459,7 +1468,7 @@ (point)))) (beginning-of-line) (and (re-search-backward - (concat "\\(^[ \t0-9]*end\\b[ \t]*[^ \t=(a-z]\\)\\|" + (concat "\\(" fortran-end-prog-re "\\)\\|" "\\(^[ \t0-9]*do[ \t]*0*" charnum "\\b\\)\\|" "\\(^[ \t]*0*" charnum "\\b\\)") nil t) @@ -1468,10 +1477,10 @@ (defun fortran-find-comment-start-skip () "Move to past `comment-start-skip' found on current line. Return t if `comment-start-skip' found, nil if not." -;;; In order to move point only if comment-start-skip is found, -;;; this one uses a lot of save-excursions. Note that re-search-forward -;;; moves point even if comment-start-skip is inside a string-constant. -;;; Some code expects certain values for match-beginning and end + ;; In order to move point only if comment-start-skip is found, this + ;; one uses a lot of save-excursions. Note that re-search-forward + ;; moves point even if comment-start-skip is inside a string-constant. + ;; Some code expects certain values for match-beginning and end (interactive) (if (save-excursion (re-search-forward comment-start-skip @@ -1489,8 +1498,8 @@ t)) nil)) -;;;From: simon@gnu (Simon Marshall) -;;; Find the next ! not in a string. +;;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)) @@ -1509,8 +1518,8 @@ ;; (fortran-is-in-string-p (match-beginning 0)))) ;; found)) -;;;From: ralf@up3aud1.gwdg.de (Ralf Fassel) -;;; Test if TAB format continuation lines work. +;;From: ralf@up3aud1.gwdg.de (Ralf Fassel) +;; Test if TAB format continuation lines work. (defun fortran-is-in-string-p (where) "Return non-nil iff WHERE (a buffer position) is inside a Fortran string." (save-excursion @@ -1518,7 +1527,8 @@ (cond ((bolp) nil) ; bol is never inside a string ((save-excursion ; comment lines too - (beginning-of-line)(looking-at comment-line-start-skip)) nil) + (beginning-of-line) + (looking-at comment-line-start-skip)) nil) (t (let (;; ok, serious now. Init some local vars: (parse-state '(0 nil nil nil nil nil 0)) (quoted-comment-start (if comment-start @@ -1542,8 +1552,7 @@ comment-start (equal comment-start (char-to-string (preceding-char))))) - ;; get around a bug in forward-line in versions <= 18.57 - (if (or (> (forward-line 1) 0) (eobp)) + (if (> (forward-line) 0) (setq not-done nil)) ;; else: ;; if we are at beginning of code line, skip any @@ -1582,7 +1591,7 @@ (if (if (null arg) (not auto-fill-function) (> (prefix-numeric-value arg) 0)) - 'fortran-do-auto-fill + #'fortran-do-auto-fill nil)) (force-mode-line-update))) @@ -1602,19 +1611,16 @@ (if (looking-at comment-line-start-skip) nil ; OK to break quotes on comment lines. (move-to-column fill-column) - (cond ((fortran-is-in-string-p (point)) - (save-excursion (re-search-backward "[^']'[^']" bol t) - (if fortran-break-before-delimiters - (point) - (1+ (point))))) - (t nil))))) - ;; + (if (fortran-is-in-string-p (point)) + (save-excursion (re-search-backward "\\S\"\\s\"\\S\"" bol t) + (if fortran-break-before-delimiters + (point) + (1+ (point)))))))) ;; decide where to split the line. If a position for a quoted ;; string was found above then use that, else break the line ;; before the last delimiter. ;; Delimiters are whitespace, commas, and operators. ;; Will break before a pair of *'s. - ;; (fill-point (or quote (save-excursion @@ -1626,19 +1632,18 @@ (if (<= (point) (1+ bos)) (progn (move-to-column (1+ fill-column)) -;;;what is this doing??? + ;;what is this doing??? (if (not (re-search-forward "[\t\n,'+-/*)=]" eol t)) (goto-char bol)))) (if (bolp) (re-search-forward "[ \t]" opoint t) - (forward-char -1) - (if (looking-at "'") - (forward-char 1) + (backward-char) + (if (looking-at "\\s\"") + (forward-char) (skip-chars-backward " \t\*"))) (if fortran-break-before-delimiters (point) - (1+ (point)))))) - ) + (1+ (point))))))) ;; if we are in an in-line comment, don't break unless the ;; line of code is longer than it should be. Otherwise ;; break the line at the column computed above. @@ -1663,7 +1668,7 @@ (if (> (save-excursion (goto-char fill-point) (current-column)) - (+ (calculate-fortran-indent) fortran-continuation-indent)) + (+ (fortran-calculate-indent) fortran-continuation-indent)) (progn (goto-char fill-point) (fortran-break-line)))))) @@ -1680,8 +1685,8 @@ (re-search-backward comment-start-skip bol t) (setq comment-string (buffer-substring (point) eol)) (delete-region (point) eol)))) -;;; Forward line 1 really needs to go to next non white line - (if (save-excursion (forward-line 1) + ;; Forward line 1 really needs to go to next non white line + (if (save-excursion (forward-line) (or (looking-at " [^ 0\n]") (looking-at "\t[1-9]"))) (progn @@ -1725,6 +1730,70 @@ (indent-tabs-mode fortran-tab-mode-string)) minor-mode-alist))) +(defun fortran-fill-paragraph (&optional justify) + "Fill surrounding comment block as paragraphs, else fill statement. + +Intended as the value of `fill-paragraph-function'." + (interactive "P") + (save-excursion + (beginning-of-line) + (if (not (looking-at "[Cc*]")) + (fortran-fill-statement) + ;; We're in a comment block. Find the start and end of a + ;; paragraph, delimited either by non-comment lines or empty + ;; comments. (Get positions as markers, since the + ;; `indent-region' below can shift the block's end). + (let* ((non-empty-comment (concat "\\(" comment-line-start-skip + "\\)" "[^ \t\n]")) + (start (save-excursion + ;; Find (start of) first line. + (while (and (zerop (forward-line -1)) + (looking-at non-empty-comment))) + (or (looking-at non-empty-comment) + (forward-line)) ; overshot + (point-marker))) + (end (save-excursion + ;; Find start of first line past region to fill. + (while (progn (forward-line) + (looking-at non-empty-comment))) + (point-marker)))) + ;; Indent the block, find the string comprising the effective + ;; comment start skip and use that as a fill-prefix for + ;; filling the region. + (indent-region start end nil) + (let ((paragraph-ignore-fill-prefix nil) + (fill-prefix (progn (beginning-of-line) + (looking-at comment-line-start-skip) + (match-string 0)))) + (let (fill-paragraph-function) + (fill-region start end justify))) ; with normal `fill-paragraph' + (set-marker start nil) + (set-marker end nil))))) + +(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) + t) ; must return t for fill-paragraph + (provide 'fortran) ;;; fortran.el ends here