+ (progn
+ (idlwave-require-online-help)
+ (idlwave-online-help nil name type class keyword))
+ (idlwave-rinfo-insert-keyword keyword buf shift))))))
+
+(defun idlwave-rinfo-insert-keyword (keyword buffer &optional shift)
+ "Insert KEYWORD in BUFFER. Make sure buffer is displayed in a window."
+ (let ((bwin (get-buffer-window buffer)))
+ (if idlwave-complete-empty-string-as-lower-case
+ (setq keyword (downcase keyword)))
+ (if bwin
+ (select-window bwin)
+ (pop-to-buffer buffer)
+ (setq bwin (get-buffer-window buffer)))
+ (if (eq (preceding-char) ?/)
+ (insert keyword)
+ (unless (save-excursion
+ (re-search-backward
+ "[(,][ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\)?[ \t]*\\="
+ (min (- (point) 100) (point-min)) t))
+ (insert ", "))
+ (if shift (insert "/"))
+ (insert keyword)
+ (if (and (not shift)
+ idlwave-keyword-completion-adds-equal)
+ (insert "=")))))
+
+(defun idlwave-list-buffer-load-path-shadows (&optional arg)
+ "List the load path shadows of all routines defined in current buffer."
+ (interactive "P")
+ (idlwave-routines)
+ (if (eq major-mode 'idlwave-mode)
+ (idlwave-list-load-path-shadows
+ nil (idlwave-update-current-buffer-info 'save-buffer)
+ "in current buffer")
+ (error "Current buffer is not in idlwave-mode")))
+
+(defun idlwave-list-shell-load-path-shadows (&optional arg)
+ "List the load path shadows of all routines compiled under the shell.
+This is very useful for checking an IDL application. Just compile the
+application, do RESOLVE_ALL, and `C-c C-i' to compile all referenced
+routines and update IDLWAVE internal info. Then check for shadowing
+with this command."
+ (interactive "P")
+ (cond
+ ((or (not (fboundp 'idlwave-shell-is-running))
+ (not (idlwave-shell-is-running)))
+ (error "Shell is not running"))
+ ((null idlwave-compiled-routines)
+ (error "No compiled routines. Maybe you need to update with `C-c C-i'"))
+ (t
+ (idlwave-list-load-path-shadows nil idlwave-compiled-routines
+ "in the shell"))))
+
+(defun idlwave-list-all-load-path-shadows (&optional arg)
+ "List the load path shadows of all routines known to IDLWAVE."
+ (interactive "P")
+ (idlwave-list-load-path-shadows nil nil "globally"))
+
+(defun idlwave-list-load-path-shadows (arg &optional special-routines loc)
+ "List the routines which are defined multiple times.
+Search the information IDLWAVE has about IDL routines for multiple
+definitions.
+When SPECIAL-ROUTINES in non-nil, only look for shadows of these routines.
+
+When IDL hits a routine call which is not defined, it will search on
+the load path in order to find a definition. The output of this
+command can be used to detect possible name clashes during this process."
+ (idlwave-routines) ; Make sure everything is loaded.
+ (unless idlwave-library-routines
+ (or (y-or-n-p
+ "You don't have a library catalog. Continue anyway? ")
+ (error "Abort")))
+ (let* ((routines (append idlwave-system-routines
+ idlwave-compiled-routines
+ idlwave-library-routines
+ idlwave-buffer-routines
+ nil))
+ (km-prop (if (featurep 'xemacs) 'keymap 'local-map))
+ (keymap (make-sparse-keymap))
+ (props (list 'mouse-face 'highlight
+ km-prop keymap
+ 'help-echo "Mouse2: Find source"))
+ (nroutines (length (or special-routines routines)))
+ (step (/ nroutines 99))
+ (n 0)
+ (next-perc 1)
+ (cnt 0)
+ (idlwave-sort-prefer-buffer-info nil)
+ routine twins dtwins twin done props1 lroutines)
+
+ (if special-routines
+ ;; Just looking for shadows of a few special routines
+ (setq lroutines routines
+ routines special-routines))
+
+ (message "Sorting routines...")
+ (setq routines (sort routines
+ (lambda (a b)
+ (string< (downcase (idlwave-make-full-name
+ (nth 2 a) (car a)))
+ (downcase (idlwave-make-full-name
+ (nth 2 b) (car b)))))))
+ (message "Sorting routines...done")
+
+ (define-key keymap (if (featurep 'xemacs) [(button2)] [(mouse-2)])
+ (lambda (ev)
+ (interactive "e")
+ (mouse-set-point ev)
+ (apply 'idlwave-do-find-module
+ (get-text-property (point) 'find-args))))
+ (define-key keymap [(return)]
+ (lambda ()
+ (interactive)
+ (apply 'idlwave-do-find-module
+ (get-text-property (point) 'find-args))))
+ (message "Compiling list...( 0%%)")
+ (save-excursion
+ (set-buffer (get-buffer-create "*Shadows*"))
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (while (setq routine (pop routines))
+ (setq n (1+ n))
+ (if (= (* next-perc step) n)
+ (progn
+ (message "Compiling list...(%2d%%)" next-perc)
+ (setq next-perc (1+ next-perc))))
+ ;; Get a list of all twins
+ (setq twins (idlwave-routine-twins routine (or lroutines routines)))
+ (if (memq routine done)
+ (setq dtwins nil)
+ (setq dtwins (idlwave-study-twins twins)))
+ ;; Mark all twins as delt with
+ (setq done (append twins done))
+ (when (or (> (length dtwins) 1)
+ (> (idlwave-count-eq 'lib (nth 2 (car dtwins))) 1)
+ (> (idlwave-count-eq 'buffer (nth 2 (car dtwins))) 1))
+ (incf cnt)
+ (insert (format "\n%s%s"
+ (idlwave-make-full-name (nth 2 routine) (car routine))
+ (if (eq (nth 1 routine) 'fun) "()" "")))
+ (while (setq twin (pop dtwins))
+ (setq props1 (append (list 'find-args
+ (list (nth 0 routine)
+ (nth 1 routine)
+ (nth 2 routine)
+ (cons 'lib (nth 1 twin))))
+ props))
+ (idlwave-insert-source-location "\n - " twin props1))))
+ (goto-char (point-min))
+ (setq buffer-read-only t))
+ (setq loc (or loc ""))
+ (if (> cnt 0)
+ (progn
+ (display-buffer (get-buffer "*Shadows*"))
+ (message "%d case%s of shadowing found %s"
+ cnt (if (= cnt 1) "" "s") loc))
+ (message "No shadowing conflicts found %s" loc))))
+
+(defun idlwave-print-source (routine)
+ (let* ((source (nth 3 routine))
+ (stype (car source))
+ (sfile (cdr source)))
+ (if (and (eq stype 'lib) sfile)
+ (progn
+ (setq sfile (idlwave-expand-lib-file-name sfile))
+ (if (idlwave-syslib-p sfile) (setq stype 'syslib))))
+ (if (and (eq stype 'compiled)
+ (or (not (stringp sfile))
+ (not (string-match "\\S-" sfile))))
+ (setq stype 'unresolved))
+ (princ (format " %-10s %s\n"
+ stype
+ (if sfile sfile "No source code available")))))
+
+(defun idlwave-routine-twins (entry &optional list)
+ "Return all twin entries of ENTRY in LIST.
+LIST defaults to `idlwave-routines'.
+Twin entries are those which have the same name, type, and class.
+ENTRY will also be returned, as the first item of this list."
+ (let* ((name (car entry))
+ (type (nth 1 entry))
+ (class (nth 2 entry))
+ (candidates (idlwave-all-assq name (or list (idlwave-routines))))
+ twins candidate)
+ (while (setq candidate (pop candidates))
+ (if (and (not (eq candidate entry))
+ (eq type (nth 1 candidate))
+ (eq class (nth 2 candidate)))
+ (push candidate twins)))
+ (if (setq candidate (idlwave-rinfo-assq name type class
+ idlwave-unresolved-routines))
+ (push candidate twins))
+ (cons entry (nreverse twins))))
+
+(defun idlwave-study-twins (entries)
+ "Return dangerous twins of first entry in TWINS.
+Dangerous twins are routines with same name, but in different files
+on the load path.
+If a file is in the system library and has an entry in the
+`idlwave-system-routines' list, we omit the latter because many IDL
+routines are implemented as library routines."
+ (let* ((entry (car entries))
+ (name (car entry)) ;
+ (type (nth 1 entry)) ; Must be bound for
+ (class (nth 2 entry)) ; idlwave-routine-twin-compare
+ (cnt 0)
+ source type file thefile alist syslibp key)
+ (while (setq entry (pop entries))
+ (incf cnt)
+ (setq source (nth 3 entry)
+ type (car source)
+ file (cdr source))
+ (if (eq type 'lib)
+ (setq file (idlwave-expand-lib-file-name file)))
+ ;; Make KEY to index entry properly
+ (setq key (cond ((eq type 'system) type)
+ (file (file-truename file))
+ (t 'unresolved)))
+ (if (and file
+ (not syslibp)
+ (idlwave-syslib-p file))
+ ;; We do have an entry in the system library
+ (setq syslibp t))
+
+ (setq thefile (or thefile file))
+ (if (setq entry (assoc key alist))
+ (push type (nth 2 entry))
+ (push (list key file (list type)) alist)))
+
+ (setq alist (nreverse alist))
+
+ (when syslibp
+ ;; File is system *library* - remove any system entry
+ (setq alist (delq (assoc 'system alist) alist)))
+
+ (when (and (idlwave-syslib-scanned-p)
+ (setq entry (assoc 'system alist)))
+ (setcar entry 'builtin))
+ (sort alist 'idlwave-routine-twin-compare)))
+
+(defvar name)
+(defvar type)
+(defvar class)
+(defvar idlwave-sort-prefer-buffer-info t
+ "Internal variable used to influence `idlwave-routine-twin-compare'.")
+
+(defmacro idlwave-xor (a b)
+ `(and (or ,a ,b)
+ (not (and ,a ,b))))
+
+(defun idlwave-routine-entry-compare (a b)
+ "Compare two routine info entries for sortiung. This is the general case.
+It first compates class, names, and type. If it turns out that A and B
+are twins (same name, class, and type), calls another routine which
+compares twins on the basis of their file names and path locations."
+ (let ((name (car a)) (type (nth 1 a)) (class (nth 2 a)))
+ (cond
+ ((not (equal (idlwave-downcase-safe class)
+ (idlwave-downcase-safe (nth 2 b))))
+ ;; Class decides
+ (cond ((null (nth 2 b)) nil)
+ ((null class) t)
+ (t (string< (downcase class) (downcase (nth 2 b))))))
+ ((not (equal (downcase name) (downcase (car b))))
+ ;; Name decides
+ (string< (downcase name) (downcase (car b))))
+ ((not (eq type (nth 1 b)))
+ ;; Type decides
+ (< (if (eq type 'fun) 1 0) (if (eq (nth 1 b) 'fun) 1 0)))
+ (t
+ ;; A and B are twins - so the decision is more complicated.
+ ;; Call twin-compare with the proper arguments.
+ (idlwave-routine-entry-compare-twins a b)))))
+
+(defun idlwave-routine-entry-compare-twins (a b)
+ "Compare two routine entries, under the assumption that they are twins.
+This basically calles `idlwave-routine-twin-compare' with the correct args."
+ (let ((name (car a)) (type (nth 1 a)) (class (nth 2 a)) ; needed outside
+ (atype (car (nth 3 a)))
+ (btype (car (nth 3 b)))
+ (afile (cdr (nth 3 a)))
+ (bfile (cdr (nth 3 b))))
+ (if (eq atype 'lib)
+ (setq afile (idlwave-expand-lib-file-name afile)))
+ (if (eq btype 'lib)
+ (setq bfile (idlwave-expand-lib-file-name bfile)))
+ (idlwave-routine-twin-compare
+ (if (stringp afile)
+ (list (file-truename afile) afile (list atype))
+ (list atype afile (list atype)))
+ (if (stringp bfile)
+ (list (file-truename bfile) bfile (list btype))
+ (list btype bfile (list btype))))
+ ))
+
+(defun idlwave-routine-twin-compare (a b)
+ "Compare two routine twin entries for sorting.
+In here, A and B are not normal routine info entries, but special
+lists (KEY FILENAME (TYPES...)).
+This expects NAME TYPE CLASS to be bound to the right values."
+ (let* (;; Dis-assemble entries
+ (akey (car a)) (bkey (car b))
+ (afile (nth 1 a)) (bfile (nth 1 b))
+ (atypes (nth 2 a)) (btypes (nth 2 b))
+ ;; System routines?
+ (asysp (memq akey '(builtin system)))
+ (bsysp (memq bkey '(builtin system)))
+ ;; Compiled routines?
+ (acompp (memq 'compiled atypes))
+ (bcompp (memq 'compiled btypes))
+ ;; Unresolved?
+ (aunresp (or (eq akey 'unresolved)
+ (and acompp (not afile))))
+ (bunresp (or (eq bkey 'unresolved)
+ (and bcompp (not bfile))))
+ ;; Buffer info available?
+ (abufp (memq 'buffer atypes))
+ (bbufp (memq 'buffer btypes))
+ ;; On search path?
+ (tpath-alist (idlwave-true-path-alist))
+ (apathp (assoc akey tpath-alist))
+ (bpathp (assoc bkey tpath-alist))
+ ;; How early on search path? High number means early since we
+ ;; measure the tail of the path list
+ (anpath (length (memq apathp tpath-alist)))
+ (bnpath (length (memq bpathp tpath-alist)))
+ ;; Look at file names
+ (aname (if (stringp afile) (downcase (file-name-nondirectory afile)) ""))
+ (bname (if (stringp bfile) (downcase (file-name-nondirectory bfile)) ""))
+ (fname-re (if class (format "\\`%s__\\(%s\\|define\\)\\.pro\\'"
+ (regexp-quote (downcase class))
+ (regexp-quote (downcase name)))
+ (format "\\`%s\\.pro" (regexp-quote (downcase name)))))
+ ;; Is file name derived from the routine name?
+ ;; Method file or class definition file?
+ (anamep (string-match fname-re aname))
+ (adefp (and class anamep (string= "define" (match-string 1 aname))))
+ (bnamep (string-match fname-re bname))
+ (bdefp (and class bnamep (string= "define" (match-string 1 bname)))))
+
+ ;; Now: follow JD's ideas about sorting. Looks really simple now,
+ ;; doesn't it? The difficult stuff is hidden above...
+ (cond
+ ((idlwave-xor asysp bsysp) asysp) ; System entries first
+ ((idlwave-xor aunresp bunresp) bunresp) ; Unresolved last
+ ((and idlwave-sort-prefer-buffer-info
+ (idlwave-xor abufp bbufp)) abufp) ; Buffers before non-buffers
+ ((idlwave-xor acompp bcompp) acompp) ; Compiled entries
+ ((idlwave-xor apathp bpathp) apathp) ; Library before non-library
+ ((idlwave-xor anamep bnamep) anamep) ; Correct file names first
+ ((and class anamep bnamep ; both file names match ->
+ (idlwave-xor adefp bdefp)) bdefp) ; __define after __method
+ ((> anpath bnpath) t) ; Who is first on path?
+ (t nil)))) ; Default
+
+(defun idlwave-downcase-safe (string)
+ "Donwcase if string, else return unchanged."
+ (if (stringp string)
+ (downcase string)
+ string))
+
+(defun idlwave-count-eq (elt list)
+ "How often is ELT in LIST?"
+ (length (delq nil (mapcar (lambda (x) (eq x elt)) list))))
+
+(defun idlwave-syslib-p (file)
+ "Non-nil of FILE is in the system library."
+ (let* ((true-syslib (file-name-as-directory
+ (file-truename
+ (expand-file-name "lib" (idlwave-sys-dir)))))
+ (true-file (file-truename file)))
+ (string-match (concat "^" (regexp-quote true-syslib)) true-file)))
+
+(defun idlwave-lib-p (file)
+ "Non-nil if file is in the library"
+ (let ((true-dir (file-name-directory (file-truename file))))
+ (assoc true-dir (idlwave-true-path-alist))))
+
+(defun idlwave-true-path-alist ()
+ "Return `idlwave-path-alist' alist with true-names.
+Info is cached, but relies on the functons setting `idlwave-path-alist'
+to reset the variable `idlwave-true-path-alist' to nil."
+ (or idlwave-true-path-alist
+ (setq idlwave-true-path-alist
+ (mapcar (lambda(x) (cons
+ (file-name-as-directory
+ (file-truename
+ (directory-file-name
+ (car x))))
+ (cdr x)))
+ idlwave-path-alist))))
+
+(defun idlwave-syslib-scanned-p ()
+ "Non-nil if the system lib file !DIR/lib has been scanned."
+ (let* ((true-syslib (file-name-as-directory
+ (file-truename
+ (expand-file-name "lib" (idlwave-sys-dir))))))
+ (cdr (assoc true-syslib (idlwave-true-path-alist)))))
+
+;; ----------------------------------------------------------------------------
+;;
+;; Online Help display
+