;;; f90-interface-browser.el --- Parse and browse f90 interfaces
-;; Copyright (C) 2011, 2012 Free Software Foundation, Inc
+;; Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc
;; Author: Lawrence Mitchell <wence@gmx.li>
;; Created: 2011-07-06
-;; Available-from: http://github.com/wence-/f90-iface/
-;; Version: 1.0
+;; URL: http://github.com/wence-/f90-iface/
+;; Version: 1.1
+;; Package-Type: simple
;; COPYRIGHT NOTICE
;; so that you can use it on the M-. keybinding and it will fall back
;; to completing tag names if you don't want to look for an interface
;; definition.
+;; In addition, if you're in a large procedure and want the list of
+;; the variables in scope (perhaps you want to define a new loop
+;; variable), you can use `f90-list-in-scope-vars' to pop up a buffer
+;; giving a reasonable guess. Note this doesn't give you module
+;; variables, or the variables of parent procedures if the current
+;; subroutine is contained within another.
;; Derived types are also parsed, so that slot types of derived types
;; are given the correct type (rather than a UNION-TYPE) when arglist
;;; Code:
;;; Preamble
-(eval-when-compile
- (require 'cl))
+(eval-when-compile (require 'cl))
(require 'thingatpt)
(require 'f90)
(require 'etags)
(when fn
(funcall fn (f90-get-type type)))))
-(defun f90-lazy-completion-table ()
- "Lazily produce a completion table of all interfaces and tag names."
- (lexical-let ((buf (current-buffer)))
- (lambda (string pred action)
- (with-current-buffer buf
- (save-excursion
- ;; If we need to ask for the tag table, allow that.
- (let ((enable-recursive-minibuffers t))
- (visit-tags-table-buffer))
- (complete-with-action action (f90-merge-into-tags-completion-table f90-all-interfaces) string pred))))))
-
-
(defsubst f90-merge-into-tags-completion-table (ctable)
"Merge completions in CTABLE into the tags completion table."
(if (or tags-file-name tags-table-list)
table)
ctable))
+(defun f90-lazy-completion-table ()
+ "Lazily produce a completion table of all interfaces and tag names."
+ (lexical-let ((buf (current-buffer)))
+ (lambda (string pred action)
+ (with-current-buffer buf
+ (save-excursion
+ ;; If we need to ask for the tag table, allow that.
+ (let ((enable-recursive-minibuffers t))
+ (visit-tags-table-buffer))
+ (complete-with-action action (f90-merge-into-tags-completion-table f90-all-interfaces) string pred))))))
+
(defsubst f90-extract-type-name (name)
"Return the typename from NAME.
(<= n-passed-args n-spec-args)))
(loop for arg in arglist
for spec-arg in spec-arglist
- with match = nil
unless (or (null arg)
(string= (f90-get-parsed-type-typename arg)
(f90-get-parsed-type-typename spec-arg)))
(goto-char (point-min))
(f90-arg-types names))))))
+(defun f90-list-in-scope-vars ()
+ "Pop up a buffer showing all variables in scope in the procedure at `point'"
+ (interactive)
+ (let* ((e (save-excursion (f90-end-of-subprogram) (point)))
+ (b (save-excursion (f90-beginning-of-subprogram) (point)))
+ (str (buffer-substring-no-properties b e))
+ types)
+ (with-temp-buffer
+ (with-syntax-table f90-mode-syntax-table
+ (insert str)
+ (goto-char (point-min))
+ (f90-clean-comments)
+ (f90-clean-continuation-lines)
+ (forward-line 1) ; skip procedure name
+ (let ((not-done t)
+ type)
+ (while (and not-done (not (eobp)))
+ ;; skip "implicit none" which may appear at top of procedure
+ (when (looking-at "\\s-*implicit\\s-+none")
+ (forward-line 1))
+ (when (not (looking-at "^\\s-*$"))
+ (setq type (ignore-errors (f90-parse-single-type-declaration)))
+ ;; If we were on a line with text and failed to parse a
+ ;; type, we must have reached the end of the type
+ ;; definitions, so don't push it on and finish.
+ (if type
+ (push type types)
+ (setq not-done nil)))
+ (forward-line 1)))))
+ (with-current-buffer (get-buffer-create "*Variables in scope*")
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (f90-mode)
+ ;; Show types of the same type together
+ (setq types (sort types (lambda (x y)
+ (string< (cadar x) (cadar y)))))
+ (loop for (type name) in types
+ do
+ (insert (format "%s :: %s\n"
+ (f90-format-parsed-slot-type type)
+ (f90-get-parsed-type-varname type))))
+ (pop-to-buffer (current-buffer))
+ (goto-char (point-min))
+ (setq buffer-read-only t))))
+
(defun f90-arg-types (names)
"Given NAMES of arguments return their types.
(setcdr (assoc "dimension" dec)
(1+ (f90-count-commas
(match-string 2 name))))
- (add-to-list 'dec
- (cons "dimension"
- (1+ (f90-count-commas
- (match-string 2 name))))
- t))
+ (push (cons "dimension"
+ (1+ (f90-count-commas
+ (match-string 2 name))))
+ dec))
(setq name (match-string 1 name)))
- collect (cons name dec)))))
+ collect (cons name (nreverse dec))))))
(defun f90-split-declaration (dec)
"Split and parse a type declaration DEC.