X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a7113309baf28c4740475c713490083c62872ebe..de4c2de7611201b1debf700a8d4bd50701651bad:/lisp/progmodes/fortran.el diff --git a/lisp/progmodes/fortran.el b/lisp/progmodes/fortran.el index e158304b41..88d41650c0 100644 --- a/lisp/progmodes/fortran.el +++ b/lisp/progmodes/fortran.el @@ -1,6 +1,6 @@ ;;; fortran.el --- Fortran mode for GNU Emacs -;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 2001 +;; Copyright (c) 1986, 93, 94, 95, 97, 98, 99, 2000, 01, 03, 04 ;; Free Software Foundation, Inc. ;; Author: Michael D. Prange @@ -54,6 +54,7 @@ ;; * Support any other extensions to f77 grokked by GNU Fortran I've missed. (eval-when-compile ; silence compiler + (defvar dabbrev-case-fold-search) (defvar imenu-case-fold-search) (defvar imenu-syntax-alist)) @@ -236,10 +237,25 @@ See the variable `fortran-column-ruler-fixed' for fixed format mode." (defcustom fortran-break-before-delimiters t "*Non-nil causes filling to break lines before delimiters. -Delimiters are whitespace, commas, quotes, and operators." +Delimiters are characters matching the regexp `fortran-break-delimiters-re'." :type 'boolean :group 'fortran) +(defconst fortran-break-delimiters-re "[-+*/><=, \t]" + "Regexp matching delimiter characters at which lines may be broken. +There are certain tokens comprised entirely of characters +matching this regexp that should not be split, and these are +specified by the constant `fortran-no-break-re'.") + +;; The ">=", etc F77 extensions are supported by g77. +(defconst fortran-no-break-re + (regexp-opt '("**" "//" "=>" ">=" "<=" "==" "/=") 'paren) + "Regexp specifying where not to break lines when filling. +This regexp matches certain tokens comprised entirely of +characters matching the regexp `fortran-break-delimiters-re' that should +not be split by filling. Each element is assumed to be two +characters long.") + (defcustom fortran-mode-hook nil "Hook run when entering Fortran mode." :type 'hook @@ -418,6 +434,12 @@ These get fixed-format comments fontified.") table) "Syntax table used in Fortran mode.") +(defvar fortran-gud-syntax-table + (let ((st (make-syntax-table fortran-mode-syntax-table))) + (modify-syntax-entry ?\n "." st) + st) + "Syntax table used to parse Fortran expressions for printing in GUD.") + (defvar fortran-mode-map (let ((map (make-sparse-keymap))) (define-key map ";" 'fortran-abbrev-start) @@ -690,9 +712,15 @@ with no args, if that value is non-nil." (set (make-local-variable 'add-log-current-defun-function) #'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) (run-hooks 'fortran-mode-hook)) +(defun fortran-gud-find-expr () + ;; Consider \n as punctuation (end of expression). + (with-syntax-table fortran-gud-syntax-table + (gud-find-c-expr))) + (defsubst fortran-comment-indent () "Return the indentation appropriate for the current comment line. This is 0 for a line matching `fortran-comment-line-start-skip', else @@ -700,8 +728,7 @@ the value of `comment-column' (leaving at least one space after code)." (if (looking-at fortran-comment-line-start-skip) 0 (save-excursion (skip-chars-backward " \t") - (max (1+ (current-column)) - comment-column)))) + (max (1+ (current-column)) comment-column)))) (defun fortran-indent-comment () "Align or create comment on current line. @@ -754,14 +781,14 @@ With non-nil ARG, uncomments the region." (goto-char beg-region) (beginning-of-line) (if arg - (let ((com (regexp-quote fortran-comment-region))) ;uncomment region + (let ((com (regexp-quote fortran-comment-region))) ; uncomment (if (looking-at com) (delete-region (point) (match-end 0))) (while (and (zerop (forward-line 1)) (< (point) end-region-mark)) (if (looking-at com) (delete-region (point) (match-end 0))))) - (insert fortran-comment-region) ;comment the region + (insert fortran-comment-region) ; comment (while (and (zerop (forward-line 1)) (< (point) end-region-mark)) (insert fortran-comment-region))) @@ -774,13 +801,17 @@ With non-nil ARG, uncomments the region." "Typing ;\\[help-command] or ;? lists all the Fortran abbrevs. Any other key combination is executed normally." (interactive "*") - (let (c) - (insert last-command-char) - (if (and abbrev-mode - (or (eq (setq c (read-event)) ??) ;insert char if not equal to `?' - (eq c help-char))) + (insert last-command-char) + (let (char event) + (if (fboundp 'next-command-event) ; XEmacs + (setq event (next-command-event) + char (event-to-character event)) + (setq event (read-event) + char event)) + ;; Insert char if not equal to `?', or if abbrev-mode is off. + (if (and abbrev-mode (or (eq char ??) (eq char help-char))) (fortran-abbrev-help) - (setq unread-command-events (list c))))) + (setq unread-command-events (list event))))) (defun fortran-abbrev-help () "List the currently defined abbrevs in Fortran mode." @@ -802,9 +833,9 @@ Any other key combination is executed normally." (defun fortran-column-ruler () "Insert a column ruler momentarily above current line, till next keystroke. -The ruler is defined by the value of `fortran-column-ruler-fixed' when in fixed -format mode, and `fortran-column-ruler-tab' when in TAB format mode. -The key typed is executed unless it is SPC." +The ruler is defined by the value of `fortran-column-ruler-fixed' in fixed +format mode, and `fortran-column-ruler-tab' in TAB format mode. +The next key typed is executed unless it is SPC." (interactive) (momentary-string-display (if indent-tabs-mode @@ -865,8 +896,8 @@ See also `fortran-window-create'." (insert ?\n (match-string 0)) (if indent-tabs-mode (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 *. + (insert "\n " fortran-continuation-string))) ; space after \n important + (fortran-indent-line)) ; when cont string is C, c or * (defun fortran-remove-continuation () "Delete any Fortran continuation characters at point. @@ -936,7 +967,6 @@ Auto-indent does not happen if a numeric ARG is used." (fortran-indent-line)))) - (defun fortran-check-end-prog-re () "Check a preliminary match against `fortran-end-prog-re'." ;; Having got a possible match for the subprogram end, we need a @@ -1093,7 +1123,7 @@ Return point or nil." (let ((count 1)) (while (and (not (zerop count)) (not (eq (fortran-next-statement) 'last-statement)) - ;; Keep local to subprogram + ;; Keep local to subprogram. (not (and (looking-at fortran-end-prog-re) (fortran-check-end-prog-re)))) (skip-chars-forward " \t0-9") @@ -1122,7 +1152,7 @@ Return point or nil. Ignores labelled DO loops (ie DO 10 ... 10 CONTINUE)." (let ((count 1)) (while (and (not (zerop count)) (not (eq (fortran-previous-statement) 'first-statement)) - ;; Keep local to subprogram + ;; Keep local to subprogram. (not (and (looking-at fortran-end-prog-re) (fortran-check-end-prog-re)))) (skip-chars-forward " \t0-9") @@ -1173,7 +1203,7 @@ Return point or nil." (save-excursion (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") - (let (then-test) ; Multi-line if-then. + (let (then-test) ; multi-line if-then (while (and (zerop (forward-line 1)) @@ -1232,7 +1262,7 @@ Return point or nil." (save-excursion (if (or (looking-at ".*)[ \t]*then\\b[ \t]*[^ \t(=a-z0-9]") - (let (then-test) ; Multi-line if-then. + (let (then-test) ; multi-line if-then (while (and (zerop (forward-line 1)) @@ -1327,9 +1357,9 @@ Return point or nil." (skip-chars-forward " \t0-9") (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 + (let (then-test) ; multi-line if-then (while (and (zerop (forward-line 1)) - ;;search forward for then + ;; Search forward for then. (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]") (not (setq then-test (looking-at @@ -1357,7 +1387,7 @@ Return point or nil." (setq icol (+ icol fortran-structure-indent))) ((and (looking-at fortran-end-prog-re1) (fortran-check-end-prog-re)) - ;; Previous END resets indent to minimum + ;; Previous END resets indent to minimum. (setq icol fortran-minimum-statement-indent))))) (save-excursion (beginning-of-line) @@ -1470,8 +1500,8 @@ notes: 1) A non-zero/non-blank character in column 5 indicates a continuation (insert ?\t (fortran-numerical-continuation-char) 1)) (forward-char 6)) (delete-horizontal-space) - ;; Put line number in columns 0-4 - ;; or put continuation character in column 5. + ;; Put line number in columns 0-4, or + ;; continuation character in column 5. (cond ((eobp)) ((looking-at (regexp-quote fortran-continuation-string)) (if indent-tabs-mode @@ -1521,7 +1551,7 @@ Otherwise return nil." (beginning-of-line) (when (looking-at "[ \t]*[0-9]+") (skip-chars-forward " \t") - (skip-chars-forward "0") ;skip past leading zeros + (skip-chars-forward "0") ; skip past leading zeros (setq charnum (buffer-substring (point) (progn (skip-chars-forward "0-9") @@ -1573,18 +1603,17 @@ If ALL is nil, only match comments that start in column > 0." ((save-excursion ; comment lines too (beginning-of-line) (looking-at fortran-comment-line-start-skip)) nil) - (t (let (;; ok, serious now. Init some local vars: - (parse-state '(0 nil nil nil nil nil 0)) + (t (let ((parse-state '(0 nil nil nil nil nil 0)) (quoted-comment-start (if comment-start (regexp-quote comment-start))) (not-done t) parse-limit end-of-line) - ;; move to start of current statement + ;; Move to start of current statement. (fortran-next-statement) (fortran-previous-statement) - ;; now parse up to WHERE + ;; Now parse up to WHERE. (while not-done - (if (or ;; skip to next line if: + (if (or ;; Skip to next line if: ;; - comment line? (looking-at fortran-comment-line-start-skip) ;; - at end of line? @@ -1597,29 +1626,29 @@ If ALL is nil, only match comments that start in column > 0." (if (> (forward-line) 0) (setq not-done nil)) ;; else: - ;; if we are at beginning of code line, skip any + ;; If we are at beginning of code line, skip any ;; whitespace, labels and tab continuation markers. (if (bolp) (skip-chars-forward " \t0-9")) - ;; if we are in column <= 5 now, check for continuation char + ;; If we are in column <= 5 now, check for continuation char. (cond ((= 5 (current-column)) (forward-char 1)) ((and (< (current-column) 5) (equal fortran-continuation-string (char-to-string (following-char))) (forward-char 1)))) - ;; find out parse-limit from here + ;; Find out parse-limit from here. (setq end-of-line (line-end-position)) (setq parse-limit (min where end-of-line)) - ;; parse max up to comment-start, if non-nil and in current line + ;; Parse max up to comment-start, if non-nil and in current line. (if comment-start (save-excursion (if (re-search-forward quoted-comment-start end-of-line t) (setq parse-limit (min (point) parse-limit))))) - ;; now parse if still in limits + ;; Now parse if still in limits. (if (< (point) where) (setq parse-state (parse-partial-sexp (point) parse-limit nil nil parse-state)) (setq not-done nil)))) - ;; result is + ;; Result. (nth 3 parse-state)))))) ;; From old version. @@ -1632,62 +1661,73 @@ If ALL is nil, only match comments that start in column > 0." (bol (line-beginning-position)) (eol (line-end-position)) (bos (min eol (+ bol (fortran-current-line-indentation)))) + ;; If in a string at fill-column, break it either before the + ;; initial quote, or at fill-col (if string is too long). (quote (save-excursion (goto-char bol) ;; OK to break quotes on comment lines. (unless (looking-at fortran-comment-line-start-skip) (let (fcpoint start) - (move-to-column fill-column) - (when (fortran-is-in-string-p (setq fcpoint (point))) - (save-excursion - (re-search-backward "\\S\"\\s\"\\S\"" bol t) - (setq start - (if fortran-break-before-delimiters - (point) - (1+ (point))))) - (if (re-search-forward "\\S\"\\s\"\\S\"" eol t) - (backward-char 2)) - ;; If the current string is longer than 72 - 6 chars, - ;; break it at the fill column (else infinite loop). - (if (> (- (point) start) - (- fill-column 6 fortran-continuation-indent)) - fcpoint - start)))))) + (move-to-column fill-column) + (when (fortran-is-in-string-p (setq fcpoint (point))) + (save-excursion + (re-search-backward "\\S\"\\s\"\\S\"?" bol t) + (setq start + (if fortran-break-before-delimiters + (point) + (1+ (point))))) + (if (re-search-forward "\\S\"\\s\"\\S\"" eol t) + (backward-char 2)) + ;; If the current string is longer than 72 - 6 chars, + ;; break it at the fill column (else infinite loop). + (if (> (- (point) start) + (- fill-column 6 fortran-continuation-indent)) + fcpoint + start)))))) ;; 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. + ;; before/after the last delimiter. (fill-point (or quote (save-excursion - (move-to-column (1+ fill-column)) - ;; GM Make this a defcustom as in f90-mode? Add ", (? - (skip-chars-backward "^ \t\n,'+-/*=)" -;;; (if fortran-break-before-delimiters -;;; "^ \t\n,'+-/*=" "^ \t\n,'+-/*=)") - ) - (when (<= (point) (1+ bos)) + ;; If f-b-b-d is t, have an extra column to play with, + ;; since delimiter gets shifted to new line. + (move-to-column (if fortran-break-before-delimiters + (1+ fill-column) + fill-column)) + (let ((repeat t)) + (while repeat + (setq repeat nil) + ;; Adapted from f90-find-breakpoint. + (re-search-backward fortran-break-delimiters-re bol) + (if (not fortran-break-before-delimiters) + (if (looking-at fortran-no-break-re) + ;; Deal with cases such as "**" split over + ;; fill-col. Simpler alternative would be + ;; to start from (1- fill-column) above. + (if (> (+ 2 (current-column)) fill-column) + (setq repeat t) + (forward-char 2)) + (forward-char 1)) + (backward-char) + (or (looking-at fortran-no-break-re) + (forward-char))))) + ;; Line indented beyond fill-column? + (when (<= (point) bos) (move-to-column (1+ fill-column)) - ;;what is this doing??? + ;; What is this doing??? (or (re-search-forward "[\t\n,'+-/*)=]" eol t) (goto-char bol))) (if (bolp) - (re-search-forward "[ \t]" opoint t) - (backward-char) - (if (looking-at "\\s\"") - (forward-char) - (skip-chars-backward " \t\*"))) - (if fortran-break-before-delimiters - (point) - (1+ (point))))))) - ;; if we are in an in-line comment, don't break unless the + (re-search-forward "[ \t]" opoint t)) + (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. ;; - ;; Need to use fortran-find-comment-start-skip to make sure that quoted !'s - ;; don't prevent a break. + ;; Need to use fortran-find-comment-start-skip to make sure that + ;; quoted !'s don't prevent a break. (when (and (save-excursion (beginning-of-line) (if (not (fortran-find-comment-start-skip)) @@ -1716,7 +1756,7 @@ If ALL is nil, only match comments that start in column > 0." (if (fortran-find-comment-start-skip) (delete-and-extract-region (match-beginning 0) (line-end-position)))))) - ;; Forward line 1 really needs to go to next non white line + ;; Forward line 1 really needs to go to next non white line. (if (save-excursion (forward-line) (looking-at " \\{5\\}[^ 0\n]\\|\t[1-9]")) (progn @@ -1806,7 +1846,7 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace." ;; We must be inside function body for this to work. (fortran-beginning-of-subprogram) (let ((case-fold-search t)) ; case-insensitive - ;; search for fortran subprogram start + ;; Search for fortran subprogram start. (if (re-search-forward (concat "^[ \t]*\\(program\\|subroutine\\|function" "\\|[ \ta-z0-9*()]*[ \t]+function\\|" @@ -1816,7 +1856,7 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace." t) (or (match-string-no-properties 2) (progn - ;; move to EOL or before first left paren + ;; Move to EOL or before first left paren. (if (re-search-forward "[(\n]" nil t) (progn (backward-char) (skip-chars-backward " \t")) @@ -1828,4 +1868,5 @@ Supplying prefix arg DO-SPACE prevents stripping the whitespace." (provide 'fortran) +;;; arch-tag: 74935096-21c4-4cab-8ee5-6ef16090dc04 ;;; fortran.el ends here