changeset 26958:35105166b1c9

Shell mode for interaction with the idl program (idl = Interactive Data Language)
author Carsten Dominik <dominik@science.uva.nl>
date Mon, 20 Dec 1999 11:12:17 +0000
parents 3abce8d1097b
children 40d1a10917b8
files lisp/progmodes/idlwave-shell.el
diffstat 1 files changed, 2454 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/idlwave-shell.el	Mon Dec 20 11:12:17 1999 +0000
@@ -0,0 +1,2454 @@
+;;; idlwave-shell.el --- Run IDL or WAVE as an inferior process of Emacs.
+;; Copyright (c) 1994-1996 Chris Chase
+;; Copyright (c) 1999 Carsten Dominik
+;; Copyright (c) 1999 Free Software Foundation
+
+;; Author: Chris Chase <chase@att.com>
+;; Maintainer: Carsten Dominik <dominik@strw.leidenuniv.nl>
+;; Version: 3.11
+;; Date: $Date: 1999/12/06 08:13:16 $
+;; Keywords: processes
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This mode is for IDL version 4 or later.  It should work on Emacs
+;; or XEmacs version 19 or later.
+
+;; Runs IDL as an inferior process of Emacs, much like the emacs
+;; `shell' or `telnet' commands.  Provides command history and
+;; searching.  Provides debugging commands available in buffers
+;; visiting IDL procedure files, e.g., breakpoint setting, stepping,
+;; execution until a certain line, printing expressions under point,
+;; visual line pointer for current execution line, etc.
+;;
+;; Documentation should be available online with `M-x idlwave-info'.
+
+;; INSTALLATION:
+;; =============
+;; 
+;; Follow the instructions in the INSTALL file of the distribution.
+;; In short, put this file on your load path and add the following
+;; lines to your .emacs file:
+;;
+;; (autoload 'idlwave-shell "idlwave-shell" "IDLWAVE Shell" t)
+;;
+;;
+;; SOURCE
+;; ======
+;;
+;;   The newest version of this file can be found on the maintainers
+;;   web site.
+;; 
+;;     http://www.strw.leidenuniv.el/~dominik/Tools/idlwave
+;; 
+;; DOCUMENTATION
+;; =============
+;;
+;; IDLWAVE is documented online in info format.
+;; A printable version of the documentation is available from the
+;; maintainers webpage (see under SOURCE)
+;;
+;;
+;; KNOWN PROBLEMS
+;; ==============
+;;
+;; The idlwave-shell buffer seems to occasionally lose output from the IDL
+;; process.  I have not been able to consistently observe this.  I
+;; do not know if it is a problem with idlwave-shell, comint, or Emacs
+;; handling of subprocesses.
+;; 
+;; I don't plan on implementing directory tracking by watching the IDL
+;; commands entered at the prompt, since too often an IDL procedure
+;; will change the current directory. If you want the the idl process
+;; buffer to match the IDL current working just execute `M-x
+;; idlwave-shell-resync-dirs' (bound to "\C-c\C-d\C-w" by default.)
+;;
+;; The stack motion commands `idlwave-shell-stack-up' and
+;; `idlwave-shell-stack-down' only display the calling frame but
+;; cannot show the values of variables in higher frames correctly.  I
+;; just don't know how to get these values from IDL.  Anyone knows the 
+;; magic word to do this?
+;; Also, the stack pointer stays at the level where is was and is not
+;; reset correctly when you type executive commands in the shell buffer
+;; yourself.  However, using the executive commands bound to key sequences
+;; does the reset correctly.  As a workaround, just jump down when needed.
+;; 
+;; Under XEmacs the Debug menu in the shell does not display the
+;; keybindings in the prefix map.  There bindings are available anyway - so
+;; it is a bug in XEmacs.
+;; The Debug menu in source buffers does display the bindings correctly.
+;;
+;; 
+;; CUSTOMIZATION VARIABLES
+;; =======================
+;;
+;; IDLWAVE has customize support - so if you want to learn about
+;; the variables which control the behavior of the mode, use
+;; `M-x idlwave-customize'.
+;;
+;;--------------------------------------------------------------------------
+;;
+;;
+
+;;; Code:
+
+(require 'comint)
+(require 'idlwave)
+
+(eval-when-compile (require 'cl))
+
+(defvar idlwave-shell-have-new-custom nil)
+(eval-and-compile
+  ;; Kludge to allow `defcustom' for Emacs 19.
+  (condition-case () (require 'custom) (error nil))
+  (if (and (featurep 'custom)
+	   (fboundp 'custom-declare-variable)
+	   (fboundp 'defface))	   
+      ;; We've got what we needed
+      (setq idlwave-shell-have-new-custom t)
+    ;; We have the old or no custom-library, hack around it!
+    (defmacro defgroup (&rest args) nil)
+    (defmacro defcustom (var value doc &rest args) 
+      (` (defvar (, var) (, value) (, doc))))))
+
+;;; Customizations: idlwave-shell group
+
+(defgroup idlwave-shell-general-setup nil
+  "Indentation options for IDL/WAVE mode."
+  :prefix "idlwave"
+  :group 'idlwave)
+
+(defcustom idlwave-shell-prompt-pattern "^ ?IDL> "
+  "*Regexp to match IDL prompt at beginning of a line. 
+For example, \"^IDL> \" or \"^WAVE> \". 
+The \"^\" means beginning of line.
+This variable is used to initialise `comint-prompt-regexp' in the 
+process buffer.
+
+This is a fine thing to set in your `.emacs' file."
+  :group 'idlwave-shell-general-setup
+  :type 'regexp)
+
+(defcustom idlwave-shell-process-name "idl"
+  "*Name to be associated with the IDL process.  The buffer for the
+process output is made by surrounding this name with `*'s."
+  :group 'idlwave-shell-general-setup
+  :type 'string)
+
+(defcustom idlwave-shell-automatic-start nil
+  "*If non-nil attempt invoke idlwave-shell if not already running.
+This is checked when an attempt to send a command to an
+IDL process is made."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean)
+
+(defcustom idlwave-shell-initial-commands "!more=0"
+  "Initial commands, separated by newlines, to send to IDL.
+This string is sent to the IDL process by `idlwave-shell-mode' which is
+invoked by `idlwave-shell'."
+  :group 'idlwave-shell-initial-commands
+  :type 'string)
+
+(defcustom idlwave-shell-use-dedicated-frame nil
+  "*Non-nil means, IDLWAVE should use a special frame to display shell buffer."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean)
+
+(defcustom idlwave-shell-frame-parameters
+  '((height . 30) (unsplittable . nil))
+  "The frame parameters for a dedicated idlwave-shell frame.
+See also `idlwave-shell-use-dedicated-frame'.
+The default makes the frame splittable, so that completion works correctly."
+  :group 'idlwave-shell-general-setup
+  :type '(repeat
+	  (cons symbol sexp)))
+
+(defcustom idlwave-shell-use-toolbar t
+  "Non-nil means, use the debugging toolbar in all IDL related buffers.
+Available on XEmacs and on Emacs 21.x or later.
+Needs to be set at load-time, so don't try to do this in the hook."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean)
+
+(defcustom idlwave-shell-temp-pro-prefix "/tmp/idltemp"
+  "*The prefix for temporary IDL files used when compiling regions.
+It should be an absolute pathname.
+The full temporary file name is obtained by to using `make-temp-name'
+so that the name will be unique among multiple Emacs processes."
+  :group 'idlwave-shell-general-setup
+  :type 'string)
+
+(defvar idlwave-shell-fix-inserted-breaks nil
+  "*OBSOLETE VARIABLE, is no longer used.
+
+The documentation of this variable used to be:
+If non-nil then run `idlwave-shell-remove-breaks' to clean up IDL messages.")
+
+(defcustom idlwave-shell-prefix-key "\C-c\C-d"
+  "*The prefix key for the debugging map `idlwave-shell-mode-prefix-map'.
+This variable must already be set when idlwave-shell.el is loaded.
+Seting it in the mode-hook is too late."
+  :group 'idlwave-shell-general-setup
+  :type 'string)
+
+(defcustom idlwave-shell-activate-prefix-keybindings t
+  "Non-nil means, the debug commands will be bound to the prefix key.
+The prefix key itself is given in the option `idlwave-shell-prefix-key'.
+So by default setting a breakpoint will be on C-c C-d C-b."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean)
+
+(defcustom idlwave-shell-activate-alt-keybindings nil
+  "Non-nil means, the debug commands will be bound to alternate keys.
+So for example setting a breakpoint will be on A-b."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean)
+
+(defcustom idlwave-shell-use-truename nil
+  "*Non-nil means, use use `file-truename' when looking for buffers.
+If this variable is non-nil, Emacs will use the function `file-truename' to
+resolve symbolic links in the file paths printed by e.g., STOP commands.
+This means, unvisited files will be loaded under their truename.
+However, when a file is already visited under a deffernet name, IDLWAVE will
+reuse that buffer.
+This option was once introduced in order to avoid multiple buffers visiting
+the same file.  However, IDLWAVE no longer makes this mistake, so it is safe
+to set this option to nil."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean)
+
+(defcustom idlwave-shell-file-name-chars "~/A-Za-z0-9+@:_.$#%={}-"
+  "The characters allowed in file names, as a string.
+Used for file name completion. Must not contain `'', `,' and `\"'
+because these are used as separators by IDL."
+  :group 'idlwave-shell-general-setup
+  :type 'string)
+
+(defcustom idlwave-shell-mode-hook '()
+  "*Hook for customising `idlwave-shell-mode'."
+  :group 'idlwave-shell-general-setup
+  :type 'hook)
+
+;;; Breakpoint Overlays etc
+
+(defgroup idlwave-shell-highlighting-and-faces nil
+  "Indentation options for IDL/WAVE mode."
+  :prefix "idlwave"
+  :group 'idlwave)
+
+(defcustom idlwave-shell-mark-stop-line t
+  "*Non-nil means, mark the source code line where IDL is currently stopped.
+Value decides about the method which is used to mark the line.  Legal values
+are:
+
+nil       Do not mark the line
+'arrow    Use the overlay arrow
+'face     Use `idlwave-shell-stop-line-face' to highlight the line.
+t         Use what IDLWAVE things is best.  Will be a face where possible,
+          otherwise the overlay arrow.
+The overlay-arrow has the disadvantage to hide the first chars of a line.
+Since many people do not have the main block of IDL programs indented,
+a face highlighting may be better.
+On Emacs 21, the overlay arrow is displayed in a special area and never
+hides any code, so setting this to 'arrow on Emacs 21 sounds like a good idea."
+  :group 'idlwave-shell-highlighting-and-faces
+  :type '(choice
+	  (const :tag "No marking" nil)
+	  (const :tag "Use overlay arrow" arrow)
+	  (const :tag "Highlight with face" face)
+	  (const :tag "Face or arrow." t)))
+
+(defcustom idlwave-shell-overlay-arrow ">"
+  "*The overlay arrow to display at source lines where execution halts.
+We use a single character by default, since the main block of IDL procedures
+often has no indentation.  Where possible, IDLWAVE will use overlays to
+display the stop-lines.  The arrow is only used on character-based terminals.
+See also `idlwave-shell-use-overlay-arrow'."
+  :group 'idlwave-shell-highlighting-and-faces
+  :type 'string)
+
+(defcustom idlwave-shell-stop-line-face 'highlight
+  "*The face for `idlwave-shell-stop-line-overlay'.
+Allows you to choose the font, color and other properties for
+line where IDL is stopped.  See also `idlwave-shell-mark-stop-line'."
+  :group 'idlwave-shell-highlighting-and-faces
+  :type 'symbol)
+
+(defcustom idlwave-shell-expression-face 'secondary-selection
+  "*The face for `idlwave-shell-expression-overlay'.
+Allows you to choose the font, color and other properties for
+the expression printed by IDL."
+  :group 'idlwave-shell-highlighting-and-faces
+  :type 'symbol)
+
+(defcustom idlwave-shell-mark-breakpoints t
+  "*Non-nil means, mark breakpoints in the source files.
+Legal values are:
+nil        Do not mark breakpoints.
+'face      Highlight line with `idlwave-shell-breakpoint-face'.
+'glyph     Red dot at the beginning of line.  If the display does not
+           support glyphs, will use 'face instead.
+t          Glyph when possible, otherwise face (same effect as 'glyph)."
+  :group 'idlwave-shell-highlighting-and-faces
+  :type '(choice
+	  (const :tag "No marking" nil)
+	  (const :tag "Highlight with face" face)
+	  (const :tag "Display glyph (red dot)" glyph)
+	  (const :tag "Glyph or face." t)))
+
+(defvar idlwave-shell-use-breakpoint-glyph t
+  "Obsolete variable.   See `idlwave-shell-mark-breakpoints.")
+
+(defcustom idlwave-shell-breakpoint-face 'idlwave-shell-bp-face
+  "*The face for breakpoint lines in the source code.
+Allows you to choose the font, color and other properties for
+lines which have a breakpoint.  See also `idlwave-shell-mark-breakpoints'."
+  :group 'idlwave-shell-highlighting-and-faces
+  :type 'symbol)
+
+(if idlwave-shell-have-new-custom
+    ;; We have the new customize - use it to define a customizable face
+    (defface idlwave-shell-bp-face
+      '((((class color)) (:foreground "Black" :background "Pink"))
+	(t (:underline t)))
+      "Face for highlighting lines-with-breakpoints."
+      :group 'idlwave-shell-highlighting-and-faces)
+  ;; Just copy the underline face to be on the safe side.
+  (copy-face 'underline 'idlwave-shell-bp-face))
+
+;;; End user customization variables
+
+;;; External variables
+(defvar comint-last-input-start)
+(defvar comint-last-input-end)
+
+;; Other variables
+
+(defvar idlwave-shell-temp-pro-file nil
+  "Absolute pathname for temporary IDL file for compiling regions")
+
+(defvar idlwave-shell-dirstack-query "printd"
+  "Command used by `idlwave-shell-resync-dirs' to query IDL for 
+the directory stack.")
+
+(defvar idlwave-shell-default-directory nil
+  "The default directory in the idlwave-shell buffer, of outside use.")
+
+(defvar idlwave-shell-last-save-and-action-file nil
+  "The last file which was compiled with `idlwave-shell-save-and-...'.")
+
+;; Highlighting uses overlays.  When necessary, require the emulation.
+(if (not (fboundp 'make-overlay))
+    (condition-case nil
+	(require 'overlay)
+      (error nil)))
+
+(defvar idlwave-shell-stop-line-overlay nil
+  "The overlay for where IDL is currently stopped.")
+(defvar idlwave-shell-expression-overlay nil
+  "The overlay for where IDL is currently stopped.")
+;; If these were already overlays, delete them.  This probably means that we
+;; are reloading this file.
+(if (overlayp idlwave-shell-stop-line-overlay)
+    (delete-overlay idlwave-shell-stop-line-overlay))
+(if (overlayp idlwave-shell-expression-overlay)
+    (delete-overlay idlwave-shell-expression-overlay))
+;; Set to nil initially
+(setq idlwave-shell-stop-line-overlay nil
+      idlwave-shell-expression-overlay nil)
+
+;; Define the shell stop overlay.  When left nil, the arrow will be used.
+(cond
+ ((or (null idlwave-shell-mark-stop-line)
+      (eq idlwave-shell-mark-stop-line 'arrow))
+  ;; Leave the overlay nil
+  nil)
+
+ ((eq idlwave-shell-mark-stop-line 'face)
+  ;; Try to use a face.  If not possible, arrow will be used anyway
+  ;; So who can display faces?
+  (when (or (featurep 'xemacs)            ; XEmacs can do also ttys
+	    (fboundp 'tty-defined-colors) ; Emacs 21 as well
+	    window-system)                ; Window systems always
+    (progn
+      (setq idlwave-shell-stop-line-overlay (make-overlay 1 1))
+      (overlay-put idlwave-shell-stop-line-overlay 
+		   'face idlwave-shell-stop-line-face))))
+
+ (t
+  ;; IDLWAVE may decide.  Will use a face on window systems, arrow elsewhere
+  (if window-system
+      (progn
+	(setq idlwave-shell-stop-line-overlay (make-overlay 1 1))
+	(overlay-put idlwave-shell-stop-line-overlay 
+		     'face idlwave-shell-stop-line-face)))))
+
+;; Now the expression overlay
+(setq idlwave-shell-expression-overlay (make-overlay 1 1))
+(overlay-put idlwave-shell-expression-overlay
+	     'face idlwave-shell-expression-face)
+
+(defvar idlwave-shell-bp-query "help,/breakpoints"
+  "Command to obtain list of breakpoints")
+
+(defvar idlwave-shell-command-output nil
+  "String for accumulating current command output.")
+
+(defvar idlwave-shell-post-command-hook nil
+  "Lisp list expression or function to run when an IDL command is finished.
+The current command is finished when the IDL prompt is displayed.
+This is evaluated if it is a list or called with funcall.")
+
+(defvar idlwave-shell-hide-output nil
+  "If non-nil the process output is not inserted into the output
+  buffer.")
+
+(defvar idlwave-shell-accumulation nil
+  "Accumulate last line of output.")
+
+(defvar idlwave-shell-command-line-to-execute nil)
+(defvar idlwave-shell-cleanup-hook nil
+  "List of functions to do cleanup when the shell exits.")
+
+(defvar idlwave-shell-pending-commands nil
+  "List of commands to be sent to IDL.
+Each element of the list is list of \(CMD PCMD HIDE\), where CMD is a
+string to be sent to IDL and PCMD is a post-command to be placed on
+`idlwave-shell-post-command-hook'. If HIDE is non-nil, hide the output
+from command CMD. PCMD and HIDE are optional.")
+
+(defun idlwave-shell-buffer ()
+  "Name of buffer associated with IDL process.
+The name of the buffer is made by surrounding `idlwave-shell-process-name
+with `*'s."
+  (concat "*" idlwave-shell-process-name "*"))
+
+(defvar idlwave-shell-ready nil
+  "If non-nil can send next command to IDL process.")
+
+;;; The following are the types of messages we attempt to catch to
+;;; resync our idea of where IDL execution currently is.
+;;; 
+
+(defvar idlwave-shell-halt-frame nil
+  "The frame associated with halt/breakpoint messages.")
+
+(defvar idlwave-shell-step-frame nil
+  "The frame associated with step messages.")
+
+(defvar idlwave-shell-trace-frame nil
+  "The frame associated with trace messages.")
+
+(defconst idlwave-shell-halt-messages
+  '("^% Execution halted at"
+    "^% Interrupted at:"
+    "^% Stepped to:"
+    "^% At "
+    "^% Stop encountered:"
+    )
+  "*A list of regular expressions matching IDL messages.
+These are the messages containing file and line information where
+IDL is currently stopped.")
+
+(defconst idlwave-shell-halt-messages-re
+  (mapconcat 'identity idlwave-shell-halt-messages "\\|")
+  "The regular expression computed from idlwave-shell-halt-messages")
+
+(defconst idlwave-shell-trace-messages
+  '("^% At "    ;; First line of a trace message
+    )
+  "*A list of regular expressions matching IDL trace messages.
+These are the messages containing file and line information where
+IDL will begin looking for the next statement to execute.")
+
+(defconst idlwave-shell-step-messages
+  '("^% Stepped to:"
+    )
+  "*A list of regular expressions matching stepped execution messages.
+These are IDL messages containing file and line information where
+IDL has currently stepped.")
+
+(defvar idlwave-shell-break-message "^% Breakpoint at:"
+  "*Regular expression matching an IDL breakpoint message line.")
+
+
+(defvar idlwave-shell-bp-alist)
+;(defvar idlwave-shell-post-command-output)
+(defvar idlwave-shell-sources-alist)
+(defvar idlwave-shell-menu-def)
+(defvar idlwave-shell-mode-menu)
+(defvar idlwave-shell-initial-commands)
+(defvar idlwave-shell-syntax-error)
+(defvar idlwave-shell-other-error)
+(defvar idlwave-shell-error-buffer)
+(defvar idlwave-shell-error-last)
+(defvar idlwave-shell-bp-buffer)
+(defvar idlwave-shell-sources-query)
+(defvar idlwave-shell-mode-map)
+
+(defun idlwave-shell-mode ()
+  "Major mode for interacting with an inferior IDL process.
+
+1. Shell Interaction
+   -----------------
+   RET after the end of the process' output sends the text from the
+   end of process to the end of the current line.  RET before end of
+   process output copies the current line (except for the prompt) to the
+   end of the buffer.
+
+   Command history, searching of previous commands, command line
+   editing are available via the comint-mode key bindings, by default
+   mostly on the key `C-c'.
+
+2. Completion
+   ----------
+
+   TAB and M-TAB do completion of IDL routines and keywords - similar
+   to M-TAB in `idlwave-mode'.  In executive commands and strings,
+   it completes file names.
+
+3. Routine Info
+   ------------
+   `\\[idlwave-routine-info]' displays information about an IDL routine near point,
+   just like in `idlwave-mode'.  The module used is the one at point or
+   the one whose argument list is being edited.
+   To update IDLWAVE's knowledge about compiled or edited modules, use 
+   \\[idlwave-update-routine-info].
+   \\[idlwave-find-module] find the source of a module.
+   \\[idlwave-resolve] tells IDL to compile an unresolved module.
+
+4. Debugging
+   ---------
+   A complete set of commands for compiling and debugging IDL programs
+   is available from the menu.  Also keybindings starting with a 
+   `C-c C-d' prefix are available for most commands in the *idl* buffer
+   and also in source buffers.  The best place to learn about the
+   keybindings is again the menu.
+
+   On Emacs versions where this is possible, a debugging toolbar is
+   installed.
+
+   When IDL is halted in the middle of a procedure, the corresponding
+   line of that procedure file is displayed with an overlay in another
+   window.  Breakpoints are also highlighted in the source.
+
+   \\[idlwave-shell-resync-dirs] queries IDL in order to change Emacs current directory
+   to correspond to the IDL process current directory.
+
+5. Hooks
+   -----
+   Turning on `idlwave-shell-mode' runs `comint-mode-hook' and
+   `idlwave-shell-mode-hook' (in that order).
+
+6. Documentation and Customization
+   -------------------------------
+   Info documentation for this package is available.  Use \\[idlwave-info]
+   to display (complain to your sysadmin if that does not work).
+   For Postscript and HTML versions of the documentation, check IDLWAVE's
+   homepage at `http://www.strw.leidenuniv.nl/~dominik/Tools/idlwave'.
+   IDLWAVE has customize support - see the group `idlwave'.
+
+7. Keybindings
+   -----------
+\\{idlwave-shell-mode-map}"
+
+  (interactive)
+  (setq comint-prompt-regexp idlwave-shell-prompt-pattern)
+  (setq comint-process-echoes t)
+  ;; Can not use history expansion because "!" is used for system variables.
+  (setq comint-input-autoexpand nil)
+  (setq comint-input-ring-size 64)
+  (make-local-variable 'comint-completion-addsuffix)
+  (set (make-local-variable 'completion-ignore-case) t)
+  (setq comint-completion-addsuffix '("/" . ""))
+  (setq comint-input-ignoredups t)
+  (setq major-mode 'idlwave-shell-mode)
+  (setq mode-name "IDL-Shell")
+  ;; (make-local-variable 'idlwave-shell-bp-alist)
+  (setq idlwave-shell-halt-frame nil
+        idlwave-shell-trace-frame nil
+        idlwave-shell-command-output nil
+        idlwave-shell-step-frame nil)
+  (idlwave-shell-display-line nil)
+  ;; Make sure comint-last-input-end does not go to beginning of
+  ;; buffer (in case there were other processes already in this buffer).
+  (set-marker comint-last-input-end (point))
+  (setq idlwave-shell-ready nil)
+  (setq idlwave-shell-bp-alist nil)
+  (idlwave-shell-update-bp-overlays) ; Throw away old overlays
+  (setq idlwave-shell-sources-alist nil)
+  (setq idlwave-shell-default-directory default-directory)
+  ;; (make-local-variable 'idlwave-shell-temp-pro-file)
+  (setq idlwave-shell-hide-output nil
+        idlwave-shell-temp-pro-file
+        (concat (make-temp-name idlwave-shell-temp-pro-prefix) ".pro"))
+  (make-local-hook 'kill-buffer-hook)
+  (add-hook 'kill-buffer-hook 'idlwave-shell-kill-shell-buffer-confirm
+	    nil 'local)
+  (use-local-map idlwave-shell-mode-map)
+  (easy-menu-add idlwave-shell-mode-menu idlwave-shell-mode-map)
+  (run-hooks 'idlwave-shell-mode-hook)
+  (idlwave-shell-send-command idlwave-shell-initial-commands nil 'hide)
+  )
+
+(if (not (fboundp 'idl-shell))
+    (fset 'idl-shell 'idlwave-shell))
+
+(defvar idlwave-shell-idl-wframe nil
+  "Frame for displaying the idl shell window.")
+(defvar idlwave-shell-display-wframe nil
+  "Frame for displaying the idl source files.")
+
+(defvar idlwave-shell-last-calling-stack nil
+  "Caches the last calling stack, so that we can compare.")
+(defvar idlwave-shell-calling-stack-index 0)
+
+(defun idlwave-shell-source-frame ()
+  "Return the frame to be used for source display."
+  (if idlwave-shell-use-dedicated-frame
+      ;; We want separate frames for source and shell
+      (if (frame-live-p idlwave-shell-display-wframe)
+	  ;; The frame exists, so we use it.
+	  idlwave-shell-display-wframe
+	;; The frame does not exist.  We use the current frame.
+	;; However, if the current is the shell frame, we make a new frame.
+	(setq idlwave-shell-display-wframe
+	      (if (eq (selected-frame) idlwave-shell-idl-wframe)
+		  (make-frame)
+		(selected-frame))))))
+
+(defun idlwave-shell-shell-frame ()
+  "Return the frame to be used for the shell buffer."
+  (if idlwave-shell-use-dedicated-frame
+      ;; We want a dedicated frame
+      (if (frame-live-p idlwave-shell-idl-wframe)
+	  ;; It does exist, so we use it.
+	  idlwave-shell-idl-wframe
+	;; It does not exist.  Check if we have a source frame.
+	(if (not (frame-live-p idlwave-shell-display-wframe))
+	    ;; We do not have a source frame, so we use this one.
+	    (setq idlwave-shell-display-wframe (selected-frame)))
+	;; Return a new frame
+	(setq idlwave-shell-idl-wframe 
+	      (make-frame idlwave-shell-frame-parameters)))))
+  
+;;;###autoload
+(defun idlwave-shell (&optional arg)
+  "Run an inferior IDL, with I/O through buffer `(idlwave-shell-buffer)'.
+If buffer exists but shell process is not running, start new IDL.
+If buffer exists and shell process is running, just switch to the buffer.
+
+When called with a prefix ARG, or when `idlwave-shell-use-dedicated-frame'
+is non-nil, the shell buffer and the source buffers will be in
+separate frames.
+
+The command to run comes from variable `idlwave-shell-explicit-file-name'.
+
+The buffer is put in `idlwave-shell-mode', providing commands for sending
+input and controlling the IDL job.  See help on `idlwave-shell-mode'.
+See also the variable `idlwave-shell-prompt-pattern'.
+
+\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
+  (interactive "P")
+
+  ;; A non-nil arg means, we want a dedicated frame.  This will last
+  ;; for the current editing session.
+  (if arg (setq idlwave-shell-use-dedicated-frame t))
+  (if (equal arg '(16)) (setq idlwave-shell-use-dedicated-frame nil))
+
+  ;; Check if the process still exists.  If not, create it.
+  (unless (comint-check-proc (idlwave-shell-buffer))
+    (let* ((prg (or idlwave-shell-explicit-file-name "idl"))
+	   (buf (apply 'make-comint
+		       idlwave-shell-process-name prg nil
+		       idlwave-shell-command-line-options))
+	   ;; FIXME: the next line can go?
+	   ;(buf (make-comint idlwave-shell-process-name prg))
+	   (process (get-buffer-process buf)))
+      (set-process-filter process 'idlwave-shell-filter)
+      (set-process-sentinel process 'idlwave-shell-sentinel)
+      (set-buffer buf)
+      (idlwave-shell-mode)))
+  (let ((window (idlwave-display-buffer (idlwave-shell-buffer) nil
+					(idlwave-shell-shell-frame)))
+	(current-window (selected-window)))
+    (select-window window)
+    (goto-char (point-max))
+    (select-window current-window)    
+    (raise-frame (window-frame window))
+    (if (eq (selected-frame) (window-frame window))
+	(select-window window))
+    ))
+
+(defun idlwave-shell-recenter-shell-window (&optional arg)
+  "Run `idlwave-shell', but make sure the current window stays selected."
+  (interactive "P")
+  (let ((window (selected-window)))
+    (idlwave-shell arg)
+    (select-window window)))
+
+(defun idlwave-shell-send-command (&optional cmd pcmd hide preempt)
+  "Send a command to IDL process.
+
+\(CMD PCMD HIDE\) are placed at the end of `idlwave-shell-pending-commands'.
+If IDL is ready the first command, CMD, in
+`idlwave-shell-pending-commands' is sent to the IDL process.  If optional
+second argument PCMD is non-nil it will be placed on
+`idlwave-shell-post-command-hook' when CMD is executed.  If the optional
+third argument HIDE is non-nil, then hide output from CMD.
+If optional fourth argument PREEMPT is non-nil CMD is put at front of
+`idlwave-shell-pending-commands'.
+
+IDL is considered ready if the prompt is present
+and if `idlwave-shell-ready' is non-nil."
+
+  ;(setq hide nil)  ;  FIXME: turn this on for debugging only
+  (let (buf proc)
+    ;; Get or make the buffer and its process
+    (if (or (not (setq buf (get-buffer (idlwave-shell-buffer))))
+	    (not (setq proc (get-buffer-process buf))))
+	(if (not idlwave-shell-automatic-start)
+	    (error
+	     (substitute-command-keys
+	      "You need to first start an IDL shell with \\[idlwave-shell]"))
+	  (idlwave-shell-recenter-shell-window)
+	  (setq buf (get-buffer (idlwave-shell-buffer)))
+	  (if (or (not (setq buf (get-buffer (idlwave-shell-buffer))))
+		  (not (setq proc (get-buffer-process buf))))
+	      ;; Still nothing
+	      (error "Problem with autostarting IDL shell"))))
+
+    (save-excursion
+      (set-buffer buf)
+      (goto-char (process-mark proc))
+      ;; To make this easy, always push CMD onto pending commands
+      (if cmd
+          (setq idlwave-shell-pending-commands
+                (if preempt
+                    ;; Put at front.
+                    (append (list (list cmd pcmd hide))
+                            idlwave-shell-pending-commands)
+                  ;; Put at end.
+                  (append idlwave-shell-pending-commands 
+                          (list (list cmd pcmd hide))))))
+      ;; Check if IDL ready
+      (if (and idlwave-shell-ready
+               ;; Check for IDL prompt
+               (save-excursion
+                 (beginning-of-line)
+                 (looking-at idlwave-shell-prompt-pattern)))
+          ;; IDL ready for command
+          (if idlwave-shell-pending-commands
+              ;; execute command
+              (let* ((lcmd (car idlwave-shell-pending-commands))
+		     (cmd (car lcmd))
+                     (pcmd (nth 1 lcmd))
+                     (hide (nth 2 lcmd)))
+		;; If this is an executive command, reset the stack pointer
+		(if (eq (string-to-char cmd) ?.)
+		    (setq idlwave-shell-calling-stack-index 0))
+                ;; Set post-command
+                (setq idlwave-shell-post-command-hook pcmd)
+                ;; Output hiding
+;;; Debug code          
+;;;             (setq idlwave-shell-hide-output nil)
+                (setq idlwave-shell-hide-output hide)
+                ;; Pop command
+                (setq idlwave-shell-pending-commands
+                      (cdr idlwave-shell-pending-commands))
+                ;; Send command for execution
+                (set-marker comint-last-input-start (point))
+                (set-marker comint-last-input-end (point))
+                (comint-simple-send proc cmd)
+                (setq idlwave-shell-ready nil)))))))
+
+;; There was a report that a newer version of comint.el changed the
+;; name of comint-filter to comint-output-filter.  Unfortunately, we
+;; have yet to upgrade.
+
+(defun idlwave-shell-comint-filter (process string) nil)
+(if (fboundp 'comint-output-filter)
+    (fset 'idlwave-shell-comint-filter (symbol-function 'comint-output-filter))
+  (fset 'idlwave-shell-comint-filter (symbol-function 'comint-filter)))
+
+(defun idlwave-shell-is-running ()
+  "Return t if the shell process is running."
+  (eq (process-status idlwave-shell-process-name) 'run))
+
+(defun idlwave-shell-filter (proc string)
+  "Replace Carriage returns in output. Watch for prompt.
+When the IDL prompt is received executes `idlwave-shell-post-command-hook'
+and then calls `idlwave-shell-send-command' for any pending commands."
+  ;; We no longer do the cleanup here - this is done by the process sentinel
+  (when (eq (process-status idlwave-shell-process-name) 'run)
+    ;; OK, process is still running, so we can use it.
+    (let ((data (match-data)))
+      (unwind-protect
+          (progn
+            ;; May change the original match data.
+            (let (p)
+              (while (setq p (string-match "\C-M" string))
+                (aset string p ?  )))
+;;; Test/Debug code
+;;          (save-excursion (set-buffer (get-buffer-create "*test*"))
+;;                          (goto-char (point-max))
+;;                          (insert "%%%" string))
+            ;;
+            ;; Keep output
+
+; Should not keep output because the concat is costly.  If hidden put
+; the output in a hide-buffer.  Then when the output is needed in post
+; processing can access either the hide buffer or the idlwave-shell
+; buffer.  Then watching for the prompt is easier.  Furthermore, if it
+; is hidden and there is no post command, could throw away output.
+;           (setq idlwave-shell-command-output
+;                 (concat idlwave-shell-command-output string))
+            ;; Insert the string. Do this before getting the
+            ;; state. 
+            (if idlwave-shell-hide-output
+                (save-excursion
+                  (set-buffer
+                   (get-buffer-create "*idlwave-shell-hidden-output*"))
+                  (goto-char (point-max))
+                  (insert string))
+              (idlwave-shell-comint-filter proc string))
+            ;; Watch for prompt - need to accumulate the current line
+            ;; since it may not be sent all at once.
+            (if (string-match "\n" string)
+                (setq idlwave-shell-accumulation
+                      (substring string 
+                                 (progn (string-match "\\(.*\n\\)*" string)
+                                        (match-end 0))))
+              (setq idlwave-shell-accumulation
+                    (concat idlwave-shell-accumulation string)))
+            ;; Check for prompt in current line 
+            (if (setq idlwave-shell-ready
+                      (string-match idlwave-shell-prompt-pattern
+                                    idlwave-shell-accumulation))
+                (progn
+                  (if idlwave-shell-hide-output
+                      (save-excursion
+                        (set-buffer "*idlwave-shell-hidden-output*")
+                        (goto-char (point-min))
+                        (re-search-forward idlwave-shell-prompt-pattern nil t)
+                        (setq idlwave-shell-command-output
+                              (buffer-substring (point-min) (point)))
+                        (delete-region (point-min) (point)))
+                    (setq idlwave-shell-command-output
+                          (save-excursion
+                            (set-buffer
+                             (process-buffer proc))
+                            (buffer-substring
+                             (progn
+                               (goto-char (process-mark proc))
+                               (beginning-of-line nil)
+                               (point))
+                             comint-last-input-end))))
+;;; Test/Debug code
+;;                (save-excursion (set-buffer
+;;                                 (get-buffer-create "*idlwave-shell-output*"))
+;;                                (goto-char (point-max))
+;;                                (insert "%%%" string))
+                  ;; Scan for state and do post command - bracket them
+                  ;; with idlwave-shell-ready=nil since they
+                  ;; may call idlwave-shell-send-command.
+                  (let ((idlwave-shell-ready nil))
+                    (idlwave-shell-scan-for-state)
+                    ;; Unset idlwave-shell-ready to prevent sending
+                    ;; commands to IDL while running hook.
+                    (if (listp idlwave-shell-post-command-hook)
+                        (eval idlwave-shell-post-command-hook)
+                      (funcall idlwave-shell-post-command-hook))
+                    ;; Reset to default state for next command.
+                    ;; Also we do not want to find this prompt again.
+                    (setq idlwave-shell-accumulation nil
+                          idlwave-shell-command-output nil
+                          idlwave-shell-post-command-hook nil
+                          idlwave-shell-hide-output nil))
+                  ;; Done with post command. Do pending command if
+                  ;; any.
+                  (idlwave-shell-send-command))))
+        (store-match-data data)))))
+
+(defun idlwave-shell-sentinel (process event)
+  "The sentinel function for the IDLWAVE shell process."
+  (let* ((buf (idlwave-shell-buffer))
+	 (win (get-buffer-window buf)))
+    (when (get-buffer buf)
+      (save-excursion
+	(set-buffer (idlwave-shell-buffer))
+	(goto-char (point-max))
+	(insert (format "\n\n  Process %s %s" process event))))
+    (when (and (> (length (frame-list)) 1)
+	       (frame-live-p idlwave-shell-idl-wframe))
+      (delete-frame idlwave-shell-idl-wframe)
+      (setq idlwave-shell-idl-wframe nil
+	    idlwave-shell-display-wframe nil))
+    (when (window-live-p win)
+      (delete-window win))
+    (idlwave-shell-cleanup)))
+
+(defun idlwave-shell-scan-for-state ()
+  "Scan for state info.
+Looks for messages in output from last IDL command indicating where
+IDL has stopped. The types of messages we are interested in are
+execution halted, stepped, breakpoint, interrupted at and trace
+messages.  We ignore error messages otherwise.
+For breakpoint messages process any attached count or command
+parameters.
+Update the windows if a message is found."
+  (let (update)
+    (cond
+     ;; Make sure we have output
+     ((not idlwave-shell-command-output))
+
+     ;; Various types of HALT messages.
+     ((string-match idlwave-shell-halt-messages-re
+		    idlwave-shell-command-output)
+      ;; Grab the file and line state info.
+      (setq idlwave-shell-halt-frame
+            (idlwave-shell-parse-line 
+             (substring idlwave-shell-command-output (match-end 0)))
+            update t))
+
+     ;; Handle breakpoints separately
+     ((string-match idlwave-shell-break-message
+                    idlwave-shell-command-output)
+      (setq idlwave-shell-halt-frame 
+            (idlwave-shell-parse-line 
+             (substring idlwave-shell-command-output (match-end 0)))
+            update t)
+      ;; We used to to counting hits on breakpoints
+      ;; this is no longer supported since IDL breakpoints
+      ;; have learned counting.
+      ;; Do breakpoint command processing
+      (let ((bp (assoc 
+                 (list
+                  (nth 0 idlwave-shell-halt-frame)
+                  (nth 1 idlwave-shell-halt-frame))
+                 idlwave-shell-bp-alist)))
+        (if bp
+            (let ((cmd (idlwave-shell-bp-get bp 'cmd)))
+              (if cmd
+                  ;; Execute command
+                  (if (listp cmd)
+                      (eval cmd)
+                    (funcall cmd))))
+          ;; A breakpoint that we did not know about - perhaps it was
+          ;; set by the user or IDL isn't reporting breakpoints like
+          ;; we expect.  Lets update our list.
+          (idlwave-shell-bp-query)))))
+
+    ;; Handle compilation errors in addition to the above
+    (if (and idlwave-shell-command-output
+             (or (string-match
+                  idlwave-shell-syntax-error idlwave-shell-command-output)
+                 (string-match
+                  idlwave-shell-other-error idlwave-shell-command-output)))
+	(progn
+	  (save-excursion
+	    (set-buffer
+	     (get-buffer-create idlwave-shell-error-buffer))
+	    (erase-buffer)
+	    (insert idlwave-shell-command-output)
+	    (goto-char (point-min))
+	    (setq idlwave-shell-error-last (point)))
+          (idlwave-shell-goto-next-error)))
+    
+    ;; Do update
+    (when update
+      (idlwave-shell-display-line (idlwave-shell-pc-frame)))))
+
+
+(defvar idlwave-shell-error-buffer
+  "*idlwave-shell-errors*"
+  "Buffer containing syntax errors from IDL compilations.")
+
+;; FIXME: the following two variables do not currently allow line breaks
+;; in module and file names.  I am not sure if it will be necessary to
+;; change this.  Currently it seems to work the way it is.
+(defvar idlwave-shell-syntax-error
+  "^% Syntax error.\\s-*\n\\s-*At:\\s-*\\(.*\\),\\s-*Line\\s-*\\(.*\\)"  
+  "A regular expression to match an IDL syntax error.
+The first \(..\) pair should match the file name.  The second pair
+should match the line number.")
+
+(defvar idlwave-shell-other-error
+  "^% .*\n\\s-*At:\\s-*\\(.*\\),\\s-*Line\\s-*\\(.*\\)"
+  "A regular expression to match any IDL error.
+The first \(..\) pair should match the file name.  The second pair
+should match the line number.")
+
+(defvar idlwave-shell-file-line-message
+  (concat 
+   "\\("                                 ; program name group (1)
+   "\\<[a-zA-Z][a-zA-Z0-9_$:]*"          ; start with a letter, followed by [..]
+   "\\([ \t]*\n[ \t]*[a-zA-Z0-9_$:]+\\)*"; continuation lines program name (2)
+   "\\)"                                 ; end program name group (1)
+   "[ \t\n]+"                            ; white space
+   "\\("                                 ; line number group (3)
+   "[0-9]+"                              ; the line number (the fix point)
+   "\\([ \t]*\n[ \t]*[0-9]+\\)*"         ; continuation lines number (4)
+   "\\)"                                 ; end line number group (3)
+   "[ \t\n]+"                            ; white space
+   "\\("                                 ; file name group (5)
+   "[^ \t\n]+"                           ; file names can contain any non-white
+   "\\([ \t]*\n[ \t]*[^ \t\n]+\\)*"      ; continuation lines file name (6)
+   "\\)"                                 ; end line number group (5)
+   )
+  "*A regular expression to parse out the file name and line number.
+The 1st group should match the subroutine name.  
+The 3rd group is the line number.
+The 5th group is the file name.
+All parts may contain linebreaks surrounded by spaces.  This is important
+in IDL5 which inserts random linebreaks in long module and file names.")
+
+(defun idlwave-shell-parse-line (string)
+  "Parse IDL message for the subroutine, file name and line number.
+We need to work hard here to remove the stupid line breaks inserted by
+IDL5.  These line breaks can be right in the middle of procedure
+or file names.
+It is very difficult to come up with a robust solution.  This one seems
+to be pretty good though.  
+
+Here is in what ways it improves over the previous solution:
+
+1. The procedure name can be split and will be restored.
+2. The number can be split.  I have never seen this, but who knows.
+3. We do not require the `.pro' extension for files.
+
+This function can still break when the file name ends on a end line
+and the message line contains an additional line with garbage.  Then
+the first part of that garbage will be added to the file name.
+However, the function checks the existence of the files with and
+without this last part - thus the function only breaks if file name
+plus garbage match an existing regular file.  This is hopefully very
+unlikely."
+
+  (let (number procedure file)
+    (when (string-match idlwave-shell-file-line-message string)
+      (setq procedure (match-string 1 string)
+	    number (match-string 3 string)
+	    file (match-string 5 string))
+	
+      ;; Repair the strings
+      (setq procedure (idlwave-shell-repair-string procedure))
+      (setq number (idlwave-shell-repair-string number))
+      (setq file (idlwave-shell-repair-file-name file))
+
+      ;; If we have a file, return the frame list
+      (if file
+	  (list (idlwave-shell-file-name file)
+		(string-to-int number)
+		procedure)
+	;; No success finding a file
+	nil))))
+
+(defun idlwave-shell-repair-string (string)
+  "Repair a string by taking out all linebreaks.  This is destructive!"
+  (while (string-match "[ \t]*\n[ \t]*" string)
+    (setq string (replace-match "" t t string)))
+  string)
+
+(defun idlwave-shell-repair-file-name (file)
+  "Repair a file name string by taking out all linebreaks.
+The last line of STRING may be garbage - we check which one makes a valid
+file name."
+  (let ((file1 "") (file2 "") (start 0))
+    ;; We scan no further than to the next "^%" line
+    (if (string-match "^%" file) 
+	(setq file (substring file 0 (match-beginning 0))))
+    ;; Take out the line breaks
+    (while (string-match "[ \t]*\n[ \t]*" file start)
+      (setq file1 (concat file1 (substring file start (match-beginning 0)))
+	    start (match-end 0)))
+    (setq file2 (concat file1 (substring file start)))
+    (cond
+     ((file-regular-p file2) file2)
+     ((file-regular-p file1) file1)
+     ;; If we cannot veryfy the existence of the file, we return the shorter
+     ;; name.  The idea behind this is that this may be a relative file name
+     ;; and our idea about the current working directory may be wrong.
+     ;; If it is a relative file name, it hopefully is short.
+     ((not (string= "" file1)) file1)
+     ((not (string= "" file2)) file2)
+     (t nil))))
+
+(defun idlwave-shell-cleanup ()
+  "Do necessary cleanup for a terminated IDL process."
+  (setq idlwave-shell-step-frame nil
+        idlwave-shell-halt-frame nil
+        idlwave-shell-pending-commands nil
+	idlwave-shell-command-line-to-execute nil
+	idlwave-shell-bp-alist nil
+	idlwave-shell-calling-stack-index 0)
+  (idlwave-shell-display-line nil)
+  (idlwave-shell-update-bp-overlays) ; kill old overlays
+  (idlwave-shell-kill-buffer "*idlwave-shell-hidden-output*")
+  (idlwave-shell-kill-buffer idlwave-shell-bp-buffer)
+  (idlwave-shell-kill-buffer idlwave-shell-error-buffer)
+  ;; (idlwave-shell-kill-buffer (idlwave-shell-buffer))
+  (and (get-buffer (idlwave-shell-buffer))
+       (bury-buffer (get-buffer (idlwave-shell-buffer))))
+  (run-hooks 'idlwave-shell-cleanup-hook))
+
+(defun idlwave-shell-kill-buffer (buf)
+  "Kill buffer BUF if it exists."
+  (if (setq buf (get-buffer buf))
+      (kill-buffer buf)))
+
+(defun idlwave-shell-kill-shell-buffer-confirm ()
+  (when (idlwave-shell-is-running)
+    (ding)
+    (unless (y-or-n-p "IDL shell is running.  Are you sure you want to kill the buffer? ")
+      (error "Abort"))
+    (message "Killing buffer *idl* and the associated process")))
+
+(defun idlwave-shell-resync-dirs ()
+  "Resync the buffer's idea of the current directory stack.
+This command queries IDL with the command bound to 
+`idlwave-shell-dirstack-query' (default \"printd\"), reads the
+output for the new directory stack."
+  (interactive)
+  (idlwave-shell-send-command idlwave-shell-dirstack-query
+			      'idlwave-shell-filter-directory
+			      'hide))
+
+(defun idlwave-shell-retall (&optional arg)
+  "Return from the entire calling stack."
+  (interactive "P")
+  (idlwave-shell-send-command "retall"))
+
+(defun idlwave-shell-closeall (&optional arg)
+  "Close all open files."
+  (interactive "P")
+  (idlwave-shell-send-command "close,/all"))
+
+(defun idlwave-shell-quit (&optional arg)
+  "Exit the idl process after confirmation.
+With prefix ARG, exit without confirmation."
+  (interactive "P")
+  (if (not (idlwave-shell-is-running))
+      (error "Shell is not running")
+    (if (or arg (y-or-n-p "Exit the IDLWAVE Shell? "))
+	(condition-case nil
+	    (idlwave-shell-send-command "exit")
+	  (error nil)))))
+
+(defun idlwave-shell-reset (&optional visible)
+  "Reset IDL.  Return to main level and destroy the leaftover variables.
+This issues the following commands:  
+RETALL
+WIDGET_CONTROL,/RESET
+CLOSE, /ALL
+HEAP_GC, /VERBOSE"
+  ;; OBJ_DESTROY, OBJ_VALID()  FIXME: should this be added?
+  (interactive "P")
+  (message "Resetting IDL")
+  (idlwave-shell-send-command "retall" nil (not visible))
+  (idlwave-shell-send-command "widget_control,/reset" nil (not visible))
+  (idlwave-shell-send-command "close,/all" nil (not visible))
+  ;; (idlwave-shell-send-command "obj_destroy, obj_valid()" nil (not visible))
+  (idlwave-shell-send-command "heap_gc,/verbose" nil (not visible))
+  (setq idlwave-shell-calling-stack-index 0))
+
+(defun idlwave-shell-filter-directory ()
+  "Get the current directory from `idlwave-shell-command-output'.
+Change the default directory for the process buffer to concur."
+  (save-excursion
+    (set-buffer (idlwave-shell-buffer))
+    (if (string-match "Current Directory: *\\(\\S-*\\) *$"
+		      idlwave-shell-command-output)
+	(let ((dir (substring idlwave-shell-command-output 
+			      (match-beginning 1) (match-end 1))))
+	  (message "Setting Emacs wd to %s" dir)
+	  (setq idlwave-shell-default-directory dir)
+	  (setq default-directory (file-name-as-directory dir))))))
+
+(defun idlwave-shell-complete (&optional arg)
+  "Do completion in the idlwave-shell buffer.
+Calls `idlwave-shell-complete-filename' after some executive commands or
+in strings.  Otherwise, calls `idlwave-complete' to complete modules and
+keywords."
+;;FIXME: batch files?
+  (interactive "P")
+  (let (cmd)
+    (cond
+     ((setq cmd (idlwave-shell-executive-command))
+      ;; We are in a command line with an executive command
+      (if (member (upcase cmd)
+		  '(".R" ".RU" ".RUN" ".RN" ".RNE" ".RNEW"
+		    ".COM" ".COMP" ".COMPI" ".COMPIL" ".COMPILE"))
+	  ;; This command expects file names
+	  (idlwave-shell-complete-filename)))
+     ((idlwave-shell-filename-string)
+      ;; In a string, could be a file name to here
+      (idlwave-shell-complete-filename))
+     (t
+      ;; Default completion of modules and keywords
+      (idlwave-complete)))))
+
+(defun idlwave-shell-complete-filename (&optional arg)
+  "Complete a file name at point if after a file name.
+We assume that we are after a file name when completing one of the
+args of an executive .run, .rnew or .compile.  Also, in a string
+constant we complete file names.  Otherwise return nil, so that
+other completion functions can do thier work."
+  (let* ((comint-file-name-chars idlwave-shell-file-name-chars)
+	 (completion-ignore-case (default-value 'completion-ignore-case)))
+    (comint-dynamic-complete-filename)))
+
+(defun idlwave-shell-executive-command ()
+  "Return the name of the current executive command, if any."
+  (save-excursion
+    (idlwave-beginning-of-statement)
+    (if (looking-at "[ \t]*\\([.][^ \t\n\r]*\\)")
+	(match-string 1))))
+
+(defun idlwave-shell-filename-string ()
+  "Return t if in a string and after what could be a file name."
+  (let ((limit (save-excursion (beginning-of-line) (point))))
+    (save-excursion
+      ;; Skip backwards over file name chars
+      (skip-chars-backward idlwave-shell-file-name-chars limit)
+      ;; Check of the next char is a string delimiter
+      (memq (preceding-char) '(?\' ?\")))))
+
+;;;
+;;; This section contains code for debugging IDL programs. --------------------
+;;;
+
+(defun idlwave-shell-redisplay (&optional hide)
+  "Tries to resync the display with where execution has stopped.
+Issues a \"help,/trace\" command followed by a call to 
+`idlwave-shell-display-line'.  Also updates the breakpoint
+overlays."
+  (interactive)
+  (idlwave-shell-send-command
+   "help,/trace"
+   '(idlwave-shell-display-line
+     (idlwave-shell-pc-frame))
+   hide)
+  (idlwave-shell-bp-query))
+
+(defun idlwave-shell-display-level-in-calling-stack (&optional hide)
+  (idlwave-shell-send-command 
+   "help,/trace"
+   'idlwave-shell-parse-stack-and-display
+   hide))
+
+(defun idlwave-shell-parse-stack-and-display ()
+  (let* ((lines (delete "" (idlwave-split-string
+			    idlwave-shell-command-output "^%")))
+	 (stack (delq nil (mapcar 'idlwave-shell-parse-line lines)))
+	 (nmax (1- (length stack)))
+	 (nmin 0) message)
+;    ;; Reset the stack to zero if it is a new stack.
+;    (if (not (equal stack idlwave-shell-last-calling-stack))
+;	(setq idlwave-shell-calling-stack-index 0))
+;    (setq idlwave-shell-last-calling-stack stack)
+    (cond
+     ((< nmax nmin)
+      (setq idlwave-shell-calling-stack-index 0)      
+      (error "Problem with calling stack"))
+     ((> idlwave-shell-calling-stack-index nmax)
+      (setq idlwave-shell-calling-stack-index nmax
+	    message (format "%d is the highest level on the calling stack"
+			    nmax)))
+     ((< idlwave-shell-calling-stack-index nmin)
+      (setq idlwave-shell-calling-stack-index nmin
+	    message (format "%d is the lowest level on the calling stack"
+			    nmin))))    
+    (idlwave-shell-display-line 
+     (nth idlwave-shell-calling-stack-index stack))
+    (message (or message 
+		 (format "On stack level %d"
+			 idlwave-shell-calling-stack-index)))))
+
+(defun idlwave-shell-stack-up ()
+  "Display the source code one step up the calling stack."
+  (interactive)
+  (incf idlwave-shell-calling-stack-index)
+  (idlwave-shell-display-level-in-calling-stack 'hide))
+(defun idlwave-shell-stack-down ()
+  "Display the source code one step down the calling stack."
+  (interactive)
+  (decf idlwave-shell-calling-stack-index)
+  (idlwave-shell-display-level-in-calling-stack 'hide))
+
+(defun idlwave-shell-goto-frame (&optional frame)
+  "Set buffer to FRAME with point at the frame line.
+If the optional argument FRAME is nil then idlwave-shell-pc-frame is
+used.  Does nothing if the resulting frame is nil."
+  (if frame ()
+    (setq frame (idlwave-shell-pc-frame)))
+  (cond
+   (frame
+    (set-buffer (idlwave-find-file-noselect (car frame)))
+    (widen)
+    (goto-line (nth 1 frame)))))
+
+(defun idlwave-shell-pc-frame ()
+  "Returns the frame for IDL execution."
+  (and idlwave-shell-halt-frame
+       (list (nth 0 idlwave-shell-halt-frame) 
+	     (nth 1 idlwave-shell-halt-frame))))
+
+(defun idlwave-shell-valid-frame (frame)
+  "Check that frame is for an existing file."
+  (file-readable-p (car frame)))
+
+(defun idlwave-shell-display-line (frame &optional col)
+  "Display FRAME file in other window with overlay arrow.
+
+FRAME is a list of file name, line number, and subroutine name.
+If FRAME is nil then remove overlay."
+  (if (not frame)
+      ;; Remove stop-line overlay from old position
+      (progn 
+        (setq overlay-arrow-string nil)
+        (if idlwave-shell-stop-line-overlay
+            (delete-overlay idlwave-shell-stop-line-overlay)))
+    (if (not (idlwave-shell-valid-frame frame))
+        (error (concat "Invalid frame - unable to access file: " (car frame)))
+;;;
+;;; buffer : the buffer to display a line in.
+;;; select-shell: current buffer is the shell.
+;;; 
+      (let* ((buffer (idlwave-find-file-noselect (car frame)))
+             (select-shell (equal (buffer-name) (idlwave-shell-buffer)))
+             window pos)
+
+	;; First make sure the shell window is visible
+	(idlwave-display-buffer (idlwave-shell-buffer)
+				nil (idlwave-shell-shell-frame))
+
+	;; Now display the buffer and remember which window it is.
+	(setq window (idlwave-display-buffer buffer
+					     nil (idlwave-shell-source-frame)))
+
+	;; Enter the buffer and mark the line
+        (save-excursion
+          (set-buffer buffer)
+          (save-restriction
+            (widen)
+            (goto-line (nth 1 frame))
+            (setq pos (point))
+            (if idlwave-shell-stop-line-overlay
+                ;; Move overlay
+		(move-overlay idlwave-shell-stop-line-overlay
+			      (point) (save-excursion (end-of-line) (point))
+			      (current-buffer))
+	      ;; Use the arrow instead, but only if marking is wanted.
+	      (if idlwave-shell-mark-stop-line
+		  (setq overlay-arrow-string idlwave-shell-overlay-arrow))
+              (or overlay-arrow-position  ; create the marker if necessary
+                  (setq overlay-arrow-position (make-marker)))
+              (set-marker overlay-arrow-position (point) buffer)))
+	  
+	  ;; If the point is outside the restriction, widen the buffer.
+          (if (or (< pos (point-min)) (> pos (point-max)))
+	      (progn
+		(widen)
+		(goto-char pos)))
+
+	  ;; If we have the column of the error, move the cursor there.
+          (if col (move-to-column col))
+          (setq pos (point)))
+
+	;; Make sure pos is really displayed in the window.
+        (set-window-point window pos)
+
+	;; FIXME: the following frame redraw was taken out because it
+        ;; flashes.  I think it is not needed.  The code is left here in
+	;; case we have to put it back in.
+	;; (redraw-frame (window-frame window))
+
+	;; If we came from the shell, go back there.  Otherwise select 
+	;; the window where the error is displayed.
+        (if (and (equal (buffer-name) (idlwave-shell-buffer)) 
+		 (not select-shell))
+            (select-window window))))))
+
+
+(defun idlwave-shell-step (arg)
+  "Step one source line. If given prefix argument ARG, step ARG source lines."
+  (interactive "p")
+  (or (not arg) (< arg 1)
+      (setq arg 1))
+  (idlwave-shell-send-command 
+   (concat ".s " (if (integerp arg) (int-to-string arg) arg))))
+
+(defun idlwave-shell-stepover (arg)
+  "Stepover one source line.
+If given prefix argument ARG, step ARG source lines. 
+Uses IDL's stepover executive command which does not enter called functions."
+  (interactive "p")
+  (or (not arg) (< arg 1)
+      (setq arg 1))
+  (idlwave-shell-send-command 
+   (concat ".so " (if (integerp arg) (int-to-string arg) arg))))
+
+(defun idlwave-shell-break-here (&optional count cmd)
+  "Set breakpoint at current line.  
+
+If Count is nil then an ordinary breakpoint is set.  We treat a count
+of 1 as a temporary breakpoint using the ONCE keyword.  Counts greater
+than 1 use the IDL AFTER=count keyword to break only after reaching
+the statement count times.
+
+Optional argument CMD is a list or function to evaluate upon reaching 
+the breakpoint."
+  
+  (interactive "P")
+  (if (listp count)
+      (setq count nil))
+  (idlwave-shell-set-bp
+   ;; Create breakpoint
+   (idlwave-shell-bp (idlwave-shell-current-frame)
+		     (list count cmd)
+		     (idlwave-shell-current-module))))
+
+(defun idlwave-shell-set-bp-check (bp)
+  "Check for failure to set breakpoint.
+This is run on `idlwave-shell-post-command-hook'.
+Offers to recompile the procedure if we failed.  This usually fixes
+the problem with not being able to set the breakpoint."
+  ;; Scan for message
+  (if (and idlwave-shell-command-output
+           (string-match "% BREAKPOINT: *Unable to find code"
+                         idlwave-shell-command-output))
+      ;; Offer to recompile
+      (progn
+        (if (progn
+              (beep)
+              (y-or-n-p 
+               (concat "Okay to recompile file "
+                       (idlwave-shell-bp-get bp 'file) " ")))
+            ;; Recompile
+            (progn
+              ;; Clean up before retrying
+              (idlwave-shell-command-failure)
+              (idlwave-shell-send-command
+               (concat ".run " (idlwave-shell-bp-get bp 'file)) nil nil)
+              ;; Try setting breakpoint again
+              (idlwave-shell-set-bp bp))
+          (beep)
+          (message "Unable to set breakpoint.")
+          (idlwave-shell-command-failure)
+          )
+        ;; return non-nil if no error found
+        nil)
+    'okay))
+
+(defun idlwave-shell-command-failure ()
+  "Do any necessary clean up when an IDL command fails.
+Call this from a function attached to `idlwave-shell-post-command-hook'
+that detects the failure of a command.
+For example, this is called from `idlwave-shell-set-bp-check' when a
+breakpoint can not be set."
+  ;; Clear pending commands
+  (setq idlwave-shell-pending-commands nil))
+
+(defun idlwave-shell-cont ()
+  "Continue executing."
+  (interactive)
+  (idlwave-shell-send-command ".c" '(idlwave-shell-redisplay 'hide)))
+
+(defun idlwave-shell-go ()
+  "Run .GO.  This starts the main program of the last compiled file."
+  (interactive)
+  (idlwave-shell-send-command ".go" '(idlwave-shell-redisplay 'hide)))
+
+(defun idlwave-shell-return ()
+  "Run .RETURN (continue to next return, but stay in subprogram)."
+  (interactive)
+  (idlwave-shell-send-command ".return" '(idlwave-shell-redisplay 'hide)))
+
+(defun idlwave-shell-skip ()
+  "Run .SKIP (skip one line, then step)."
+  (interactive)
+  (idlwave-shell-send-command ".skip" '(idlwave-shell-redisplay 'hide)))
+
+(defun idlwave-shell-clear-bp (bp)
+  "Clear breakpoint BP.
+Clears in IDL and in `idlwave-shell-bp-alist'."
+  (let ((index (idlwave-shell-bp-get bp)))
+    (if index
+        (progn
+          (idlwave-shell-send-command
+           (concat "breakpoint,/clear," 
+		   (if (integerp index) (int-to-string index) index)))
+	  (idlwave-shell-bp-query)))))
+
+(defun idlwave-shell-current-frame ()
+  "Return a list containing the current file name and line point is in.
+If in the IDL shell buffer, returns `idlwave-shell-pc-frame'."
+  (if (eq (current-buffer) (get-buffer (idlwave-shell-buffer)))
+      ;; In IDL shell
+      (idlwave-shell-pc-frame)
+    ;; In source
+    (list (idlwave-shell-file-name (buffer-file-name))
+          (save-restriction
+            (widen)
+            (save-excursion
+              (beginning-of-line)
+              (1+ (count-lines 1 (point))))))))
+
+(defun idlwave-shell-current-module ()
+  "Return the name of the module for the current file.
+Returns nil if unable to obtain a module name."
+  (if (eq (current-buffer) (get-buffer (idlwave-shell-buffer)))
+      ;; In IDL shell
+      (nth 2 idlwave-shell-halt-frame)
+    ;; In pro file
+    (save-restriction
+      (widen)
+      (save-excursion
+        (if (idlwave-prev-index-position)
+            (upcase (idlwave-unit-name)))))))
+
+(defun idlwave-shell-clear-current-bp ()
+  "Remove breakpoint at current line.
+This command can be called from the shell buffer if IDL is currently stopped
+at a breakpoint."
+  (interactive)
+  (let ((bp (idlwave-shell-find-bp (idlwave-shell-current-frame))))
+    (if bp (idlwave-shell-clear-bp bp)
+      ;; Try moving to beginning of statement
+      (save-excursion
+        (idlwave-shell-goto-frame)
+        (idlwave-beginning-of-statement)
+        (setq bp (idlwave-shell-find-bp (idlwave-shell-current-frame)))
+        (if bp (idlwave-shell-clear-bp bp)
+          (beep)
+          (message "Cannot identify breakpoint for this line"))))))
+
+(defun idlwave-shell-to-here ()
+  "Set a breakpoint with count 1 then continue."
+  (interactive)
+  (idlwave-shell-break-here 1)
+  (idlwave-shell-cont))
+
+(defun idlwave-shell-break-in (&optional module)
+  "Look for a module name near point and set a break point for it.
+The command looks for an identifier near point and sets a breakpoint
+for the first line of the corresponding module."
+  (interactive)
+  ;; get the identifier
+  (let (module)
+    (save-excursion
+      (skip-chars-backward "a-zA-Z0-9_$")
+      (if (looking-at idlwave-identifier)
+	  (setq module (match-string 0))
+	(error "No identifier at point")))
+    (idlwave-shell-send-command
+     idlwave-shell-sources-query
+     `(progn
+	(idlwave-shell-sources-filter)
+	(idlwave-shell-set-bp-in-module ,module))
+     'hide)))
+
+(defun idlwave-shell-set-bp-in-module (module)
+  "Set breakpoint in module.  Assumes that `idlwave-shell-sources-alist'
+contains an entry for that module."
+  (let ((source-file (car-safe 
+		      (cdr-safe
+		       (assoc (upcase module)
+			      idlwave-shell-sources-alist))))
+	buf)
+    (if (or (not source-file)
+	    (not (file-regular-p source-file))
+	    (not (setq buf
+		       (or (idlwave-get-buffer-visiting source-file)
+			   (find-file-noselect source-file)))))
+	(progn
+	  (message "The source file for module %s is probably not compiled"
+		   module)
+	  (beep))
+      (save-excursion
+	(set-buffer buf)
+	(save-excursion
+	  (goto-char (point-min))
+	  (let ((case-fold-search t))
+	    (if (re-search-forward 
+		 (concat "^[ \t]*\\(pro\\|function\\)[ \t]+"
+			 (downcase module)
+			 "[ \t\n,]") nil t)
+		(progn
+		  (goto-char (match-beginning 1))
+		  (message "Setting breakpoint for module %s" module)
+		  (idlwave-shell-break-here))
+	      (message "Cannot find module %s in file %s" module source-file)
+	      (beep))))))))
+
+(defun idlwave-shell-up ()
+  "Run to end of current block.
+Sets a breakpoint with count 1 at end of block, then continues."
+  (interactive)
+  (if (idlwave-shell-pc-frame)
+      (save-excursion
+        (idlwave-shell-goto-frame)
+        ;; find end of subprogram
+        (let ((eos (save-excursion
+                     (idlwave-beginning-of-subprogram)
+                     (idlwave-forward-block)
+                     (point))))
+          (idlwave-backward-up-block -1)
+          ;; move beyond end block line - IDL will not break there.
+          ;; That is, you can put a breakpoint there but when IDL does
+          ;; break it will report that it is at the next line.
+          (idlwave-next-statement)
+          (idlwave-end-of-statement)
+          ;; Make sure we are not beyond subprogram
+          (if (< (point) eos)
+              ;; okay
+              ()
+            ;; Move back inside subprogram
+            (goto-char eos)
+            (idlwave-previous-statement))
+          (idlwave-shell-to-here)))))
+
+(defun idlwave-shell-out ()
+  "Attempt to run until this procedure exits.
+Runs to the last statement and then steps 1 statement.  Use the .out command."
+  (interactive)
+  (idlwave-shell-send-command (concat ".o")))
+
+(defun idlwave-shell-help-expression ()
+  "Print help on current expression.  See `idlwave-shell-print'."
+  (interactive)
+  (idlwave-shell-print 'help))
+
+(defun idlwave-shell-mouse-print (event)
+  "Call `idlwave-shell-print' at the mouse position."
+  (interactive "e")
+  (mouse-set-point event)
+  (idlwave-shell-print))
+
+(defun idlwave-shell-mouse-help (event)
+  "Call `idlwave-shell-print' at the mouse position."
+  (interactive "e")
+  (mouse-set-point event)
+  (idlwave-shell-help-expression))
+
+(defun idlwave-shell-print (&optional help special)
+  "Print current expression.  With are HELP, show help on expression.
+An expression is an identifier plus 1 pair of matched parentheses
+directly following the identifier - an array or function
+call.  Alternatively, an expression is the contents of any matched
+parentheses when the open parentheses is not directly preceded by an
+identifier. If point is at the beginning or within an expression
+return the inner-most containing expression, otherwise, return the
+preceding expression."
+  (interactive "P")
+  (save-excursion
+    (let (beg end)
+      ;; Move to beginning of current or previous expression
+      (if (looking-at "\\<\\|(")
+          ;; At beginning of expression, don't move backwards unless
+          ;; this is at the end of an indentifier.
+          (if (looking-at "\\>")
+              (backward-sexp))
+        (backward-sexp))
+      (if (looking-at "\\>")
+          ;; Move to beginning of identifier - must be an array or
+          ;; function expression.
+          (backward-sexp))
+      ;; Move to end of expression
+      (setq beg (point))
+      (forward-sexp)
+      (while (looking-at "\\>(\\|\\.")
+        ;; an array
+        (forward-sexp))
+      (setq end (point))
+      (when idlwave-shell-expression-overlay
+	(move-overlay idlwave-shell-expression-overlay beg end)
+	(add-hook 'pre-command-hook 'idlwave-shell-delete-expression-overlay))
+      (if special
+	  (idlwave-shell-send-command 
+	   (concat (if help "help," "print,") (buffer-substring beg end))
+	   `(idlwave-shell-process-print-output ,(buffer-substring beg end) 
+						idlwave-shell-command-output
+						,special)
+	   'hide)
+	(idlwave-shell-recenter-shell-window)
+	(idlwave-shell-send-command 
+	 (concat (if help "help," "print,") (buffer-substring beg end)))))))
+
+(defun idlwave-shell-delete-expression-overlay ()
+  (condition-case nil
+      (if idlwave-shell-expression-overlay
+	  (delete-overlay idlwave-shell-expression-overlay))
+    (error nil))
+  (remove-hook 'pre-command-hook 'idlwave-shell-delete-expression-overlay))
+
+(defvar idlwave-shell-bp-alist nil
+  "Alist of breakpoints.
+A breakpoint is a cons cell \(\(file line\) . \(\(index module\) data\)\)
+
+The car is the frame for the breakpoint:
+file - full path file name.
+line - line number of breakpoint - integer.
+
+The first element of the cdr is a list of internal IDL data:
+index - the index number of the breakpoint internal to IDL.
+module - the module for breakpoint internal to IDL.
+
+Remaining elements of the cdr:
+data - Data associated with the breakpoint by idlwave-shell currently
+contains two items:
+
+count - number of times to execute breakpoint. When count reaches 0
+the breakpoint is cleared and removed from the alist.
+command - command to execute when breakpoint is reached, either a 
+lisp function to be called with `funcall' with no arguments or a
+list to be evaluated with `eval'.")
+
+(defun idlwave-shell-run-region (beg end &optional n)
+  "Compile and run the region using the IDL process.
+Copies the region to a temporary file `idlwave-shell-temp-pro-file'
+and issues the IDL .run command for the file.  Because the
+region is compiled and run as a main program there is no
+problem with begin-end blocks extending over multiple
+lines - which would be a problem if `idlwave-shell-evaluate-region'
+was used.  An END statement is appended to the region if necessary.
+
+If there is a prefix argument, display IDL process."
+  (interactive "r\nP")
+  (let ((oldbuf (current-buffer)))
+    (save-excursion
+      (set-buffer (idlwave-find-file-noselect
+		   idlwave-shell-temp-pro-file))
+      (erase-buffer)
+      (insert-buffer-substring oldbuf beg end)
+      (if (not (save-excursion
+                 (idlwave-previous-statement)
+                 (idlwave-look-at "\\<end\\>")))
+          (insert "\nend\n"))
+      (save-buffer 0)))
+  (idlwave-shell-send-command (concat ".run " idlwave-shell-temp-pro-file))
+  (if n
+      (idlwave-display-buffer (idlwave-shell-buffer) 
+			      nil (idlwave-shell-shell-frame))))
+
+(defun idlwave-shell-evaluate-region (beg end &optional n)
+  "Send region to the IDL process.
+If there is a prefix argument, display IDL process.
+Does not work for a region with multiline blocks - use
+`idlwave-shell-run-region' for this."
+  (interactive "r\nP")
+  (idlwave-shell-send-command (buffer-substring beg end))
+  (if n
+      (idlwave-display-buffer (idlwave-shell-buffer) 
+			      nil (idlwave-shell-shell-frame))))
+
+(defun idlwave-display-buffer (buf not-this-window-p &optional frame)
+  (if (or (< emacs-major-version 20)
+	  (and (= emacs-major-version 20)
+	       (< emacs-minor-version 3)))
+      ;; Only two args.
+      (display-buffer buf not-this-window-p)
+    ;; Three ares possible.
+    (display-buffer buf not-this-window-p frame)))
+
+(defvar idlwave-shell-bp-buffer "*idlwave-shell-bp*"
+  "Scratch buffer for parsing IDL breakpoint lists and other stuff.")
+
+(defun idlwave-shell-bp-query ()
+  "Reconcile idlwave-shell's breakpoint list with IDL's.
+Queries IDL using the string in `idlwave-shell-bp-query'."
+  (interactive)
+  (idlwave-shell-send-command idlwave-shell-bp-query
+			      'idlwave-shell-filter-bp
+			      'hide))
+
+(defun idlwave-shell-bp-get (bp &optional item)
+  "Get a value for a breakpoint.
+BP has the form of elements in idlwave-shell-bp-alist.
+Optional second arg ITEM is the particular value to retrieve.
+ITEM can be 'file, 'line, 'index, 'module, 'count, 'cmd, or 'data.
+'data returns a list of 'count and 'cmd.
+Defaults to 'index."
+  (cond
+   ;; Frame
+   ((eq item 'line) (nth 1 (car bp)))
+   ((eq item 'file) (nth 0 (car bp)))
+   ;; idlwave-shell breakpoint data
+   ((eq item 'data) (cdr (cdr bp)))
+   ((eq item 'count) (nth 0 (cdr (cdr bp))))
+   ((eq item 'cmd) (nth 1 (cdr (cdr bp))))
+   ;; IDL breakpoint info
+   ((eq item 'module) (nth 1 (car (cdr bp))))
+   ;;    index - default
+   (t (nth 0 (car (cdr bp))))))
+
+(defun idlwave-shell-filter-bp ()
+  "Get the breakpoints from `idlwave-shell-command-output'.
+Create `idlwave-shell-bp-alist' updating breakpoint count and command data
+from previous breakpoint list."
+  (save-excursion
+    (set-buffer (get-buffer-create idlwave-shell-bp-buffer))
+    (erase-buffer)
+    (insert idlwave-shell-command-output)
+    (goto-char (point-min))
+    (let ((old-bp-alist idlwave-shell-bp-alist))
+      (setq idlwave-shell-bp-alist (list nil))
+      (if (re-search-forward "^\\s-*Index.*\n\\s-*-" nil t)
+          (while (and
+                  (not (progn (forward-line) (eobp)))
+                  ;; Parse breakpoint line.
+                  ;; Breakpoints have the form:
+                  ;;  Index Module Line File
+                  ;;  All seperated by whitespace.
+                  ;;
+                  ;;  Add the breakpoint info to the list
+                  (re-search-forward
+                   "\\s-*\\(\\S-+\\)\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)" nil t))
+            (nconc idlwave-shell-bp-alist
+                   (list
+                    (cons
+                     (list
+                      (save-match-data
+                        (idlwave-shell-file-name
+                         (buffer-substring ; file
+                          (match-beginning 4) (match-end 4))))
+                      (string-to-int    ; line
+                       (buffer-substring
+                        (match-beginning 3) (match-end 3))))
+                     (list
+                      (list
+                       (buffer-substring ; index
+                        (match-beginning 1) (match-end 1))
+                       (buffer-substring ; module
+                        (match-beginning 2) (match-end 2)))
+                      ;; idlwave-shell data: count, command
+                      nil nil))))))
+      (setq idlwave-shell-bp-alist (cdr idlwave-shell-bp-alist))
+      ;; Update count, commands of breakpoints
+      (mapcar 'idlwave-shell-update-bp old-bp-alist)))
+  ;; Update the breakpoint overlays
+  (idlwave-shell-update-bp-overlays)
+  ;; Return the new list
+  idlwave-shell-bp-alist)
+
+(defun idlwave-shell-update-bp (bp)
+  "Update BP data in breakpoint list.
+If BP frame is in `idlwave-shell-bp-alist' updates the breakpoint data."
+  (let ((match (assoc (car bp) idlwave-shell-bp-alist)))
+    (if match (setcdr (cdr match) (cdr (cdr bp))))))
+
+(defun idlwave-shell-set-bp-data (bp data)
+  "Set the data of BP to DATA."
+  (setcdr (cdr bp) data))
+
+(defun idlwave-shell-bp (frame &optional data module)
+  "Create a breakpoint structure containing FRAME and DATA.  Second
+and third args, DATA and MODULE, are optional.  Returns a breakpoint
+of the format used in `idlwave-shell-bp-alist'.  Can be used in commands
+attempting match a breakpoint in `idlwave-shell-bp-alist'."
+  (cons frame (cons (list nil module) data)))
+
+(defvar idlwave-shell-old-bp nil
+  "List of breakpoints previous to setting a new breakpoint.")
+
+(defun idlwave-shell-sources-bp (bp)
+  "Check `idlwave-shell-sources-alist' for source of breakpoint using BP.
+If an equivalency is found, return the IDL internal source name.
+Otherwise return the filename in bp."
+  (let*
+      ((bp-file (idlwave-shell-bp-get bp 'file))
+       (bp-module (idlwave-shell-bp-get bp 'module))
+       (internal-file-list (cdr (assoc bp-module idlwave-shell-sources-alist))))
+    (if (and internal-file-list
+	     (equal bp-file (nth 0 internal-file-list)))
+        (nth 1 internal-file-list)
+      bp-file)))
+
+(defun idlwave-shell-set-bp (bp)
+  "Try to set a breakpoint BP.
+
+The breakpoint will be placed at the beginning of the statement on the
+line specified by BP or at the next IDL statement if that line is not
+a statement.
+Determines IDL's internal representation for the breakpoint which may
+have occured at a different line then used with the breakpoint
+command."
+  
+  ;; Get and save the old breakpoints
+  (idlwave-shell-send-command 
+   idlwave-shell-bp-query
+   '(progn
+      (idlwave-shell-filter-bp)
+      (setq idlwave-shell-old-bp idlwave-shell-bp-alist))
+   'hide)
+  ;; Get sources for IDL compiled procedures followed by setting
+  ;; breakpoint.
+  (idlwave-shell-send-command
+   idlwave-shell-sources-query
+   (` (progn
+	(idlwave-shell-sources-filter)
+	(idlwave-shell-set-bp2 (quote (, bp)))))
+   'hide))
+
+(defun idlwave-shell-set-bp2 (bp)
+  "Use results of breakpoint and sources query to set bp.
+Use the count argument with IDLs breakpoint command.
+We treat a count of 1 as a temporary breakpoint. 
+Counts greater than 1 use the IDL AFTER=count keyword to break
+only after reaching the statement count times."
+  (let*
+      ((arg (idlwave-shell-bp-get bp 'count))
+       (key (cond
+             ((not (and arg (numberp arg))) "")
+             ((= arg 1)
+              ",/once")
+             ((> arg 1)
+              (format ",after=%d" arg))))
+       (line (idlwave-shell-bp-get bp 'line)))
+    (idlwave-shell-send-command
+     (concat "breakpoint,'" 
+	     (idlwave-shell-sources-bp bp) "',"
+	     (if (integerp line) (setq line (int-to-string line)))
+	     key)
+     ;; Check for failure and look for breakpoint in IDL's list
+     (` (progn
+          (if (idlwave-shell-set-bp-check (quote (, bp)))
+              (idlwave-shell-set-bp3 (quote (, bp)))))
+        )
+     ;; do not hide output 
+     nil
+     'preempt)))
+
+(defun idlwave-shell-set-bp3 (bp)
+  "Find the breakpoint in IDL's internal list of breakpoints."
+  (idlwave-shell-send-command idlwave-shell-bp-query
+			      (` (progn
+				   (idlwave-shell-filter-bp)
+				   (idlwave-shell-new-bp (quote (, bp)))))
+			      'hide
+			      'preempt))
+
+(defun idlwave-shell-find-bp (frame)
+  "Return breakpoint from `idlwave-shell-bp-alist' for frame.
+Returns nil if frame not found."
+  (assoc frame idlwave-shell-bp-alist))
+
+(defun idlwave-shell-new-bp (bp)
+  "Find the new breakpoint in IDL's list and update with DATA.
+The actual line number for a breakpoint in IDL may be different than
+the line number used with the IDL breakpoint command.
+Looks for a new breakpoint index number in the list.  This is
+considered the new breakpoint if the file name of frame matches."
+  (let ((obp-index (mapcar 'idlwave-shell-bp-get idlwave-shell-old-bp))
+        (bpl idlwave-shell-bp-alist))
+    (while (and (member (idlwave-shell-bp-get (car bpl)) obp-index)
+                (setq bpl (cdr bpl))))
+    (if (and
+         (not bpl)
+         ;; No additional breakpoint.
+         ;; Need to check if we are just replacing a breakpoint.
+         (setq bpl (assoc (car bp) idlwave-shell-bp-alist)))
+        (setq bpl (list bpl)))
+    (if (and bpl
+             (equal (idlwave-shell-bp-get (setq bpl (car bpl)) 'file)
+                    (idlwave-shell-bp-get bp 'file)))
+        ;; Got the breakpoint - add count, command to it.
+        ;; This updates `idlwave-shell-bp-alist' because a deep copy was
+        ;; not done for bpl.
+        (idlwave-shell-set-bp-data bpl (idlwave-shell-bp-get bp 'data))
+      (beep)
+      (message "Failed to identify breakpoint in IDL"))))
+
+(defvar idlwave-shell-bp-overlays nil
+  "List of overlays marking breakpoints")
+
+(defun idlwave-shell-update-bp-overlays ()
+  "Update the overlays which mark breakpoints in the source code.
+Existing overlays are recycled, in order to minimize consumption."
+  ;; FIXME: we could cache them all, but that would be more work.
+  (when idlwave-shell-mark-breakpoints
+    (let ((bp-list idlwave-shell-bp-alist)
+	  (ov-list idlwave-shell-bp-overlays)
+	  ov bp)
+      ;; Delete the old overlays from their buffers
+      (while (setq ov (pop ov-list))
+	(delete-overlay ov))
+      (setq ov-list idlwave-shell-bp-overlays
+	    idlwave-shell-bp-overlays nil)
+      (while (setq bp (pop bp-list))
+	(save-excursion
+	  (idlwave-shell-goto-frame (car bp))
+	  (let* ((end (progn (end-of-line 1) (point)))
+		 (beg (progn (beginning-of-line 1) (point)))
+		 (ov (or (pop ov-list)
+			 (idlwave-shell-make-new-bp-overlay))))
+	    (move-overlay ov beg end)
+	    (push ov idlwave-shell-bp-overlays)))))))
+
+(defvar idlwave-shell-bp-glyph)
+(defun idlwave-shell-make-new-bp-overlay ()
+  "Make a new overlay for highlighting breakpoints.
+This stuff is stringly dependant upon the version of Emacs."
+  (let ((ov (make-overlay 1 1)))
+    (if (featurep 'xemacs)
+	;; This is XEmacs
+	(progn
+	  (cond 
+	   ((eq (console-type) 'tty)
+	    ;; tty's cannot display glyphs
+	    (set-extent-property ov 'face 'idlwave-shell-bp-face))
+	   ((and (memq idlwave-shell-mark-breakpoints '(t glyph))
+		 idlwave-shell-bp-glyph)
+	    ;; use the glyph
+	    (set-extent-property ov 'begin-glyph idlwave-shell-bp-glyph))
+	   (idlwave-shell-mark-breakpoints
+	    ;; use the face
+	    (set-extent-property ov 'face 'idlwave-shell-bp-face))
+	   (t 
+	    ;; no marking
+	    nil))
+	  (set-extent-priority ov -1))  ; make stop line face prevail
+      ;; This is Emacs
+      (cond
+       (window-system
+	(if (and (memq idlwave-shell-mark-breakpoints '(t glyph))
+		 idlwave-shell-bp-glyph)   ; this var knows if glyph's possible
+	    ;; use a glyph
+	    (let ((string "@"))
+	      (put-text-property 0 1
+				 'display (cons nil idlwave-shell-bp-glyph)
+				 string)
+	      (overlay-put ov 'before-string string))
+	  (overlay-put ov 'face 'idlwave-shell-bp-face)))
+       (idlwave-shell-mark-breakpoints
+	;; use a face
+	(overlay-put ov 'face 'idlwave-shell-bp-face))
+       (t 
+	;; No marking
+	nil)))
+    ov))
+
+(defun idlwave-shell-edit-default-command-line (arg)
+  "Edit the current execute command."
+  (interactive "P")
+  (setq idlwave-shell-command-line-to-execute
+	(read-string "IDL> " idlwave-shell-command-line-to-execute)))
+
+(defun idlwave-shell-execute-default-command-line (arg)
+  "Execute a command line.  On first use, ask for the command.
+Also with prefix arg, ask for the command.  You can also uase the command
+`idlwave-shell-edit-default-command-line' to edit the line."
+  (interactive "P")
+  (if (or (not idlwave-shell-command-line-to-execute)
+	  arg)
+      (setq idlwave-shell-command-line-to-execute 
+	    (read-string "IDL> " idlwave-shell-command-line-to-execute)))
+  (idlwave-shell-reset nil)
+  (idlwave-shell-send-command idlwave-shell-command-line-to-execute
+			      '(idlwave-shell-redisplay 'hide)))
+
+(defun idlwave-shell-save-and-run ()
+  "Save file and run it in IDL.
+Runs `save-buffer' and sends a '.RUN' command for the associated file to IDL.
+When called from the shell buffer, re-run the file which was last handled by
+one of the save-and-.. commands."  
+  (interactive)
+  (idlwave-shell-save-and-action 'run))
+
+(defun idlwave-shell-save-and-compile ()
+  "Save file and run it in IDL.
+Runs `save-buffer' and sends '.COMPILE' command for the associated file to IDL.
+When called from the shell buffer, re-compile the file which was last handled by
+one of the save-and-.. commands."
+  (interactive)
+  (idlwave-shell-save-and-action 'compile))
+
+(defun idlwave-shell-save-and-batch ()
+  "Save file and batch it in IDL.
+Runs `save-buffer' and sends a '@file' command for the associated file to IDL.
+When called from the shell buffer, re-batch the file which was last handled by
+one of the save-and-.. commands."  
+  (interactive)
+  (idlwave-shell-save-and-action 'batch))
+
+(defun idlwave-shell-save-and-action (action)
+  "Save file and compile it in IDL.
+Runs `save-buffer' and sends a '.RUN' command for the associated file to IDL.
+When called from the shell buffer, re-compile the file which was last
+handled by this command."
+  ;; Remove the stop overlay.
+  (if idlwave-shell-stop-line-overlay
+      (delete-overlay idlwave-shell-stop-line-overlay))
+  (setq overlay-arrow-string nil)
+  (let (buf)
+    (cond
+     ((eq major-mode 'idlwave-mode)
+      (save-buffer)
+      (setq idlwave-shell-last-save-and-action-file (buffer-file-name)))
+     (idlwave-shell-last-save-and-action-file
+      (if (setq buf (idlwave-get-buffer-visiting
+		     idlwave-shell-last-save-and-action-file))
+	  (save-excursion
+	    (set-buffer buf)
+	    (save-buffer))))
+     (t (setq idlwave-shell-last-save-and-action-file
+	      (read-file-name "File: ")))))
+  (if (file-regular-p idlwave-shell-last-save-and-action-file)
+      (progn
+	(idlwave-shell-send-command
+	 (concat (cond ((eq action 'run)     ".run ")
+		       ((eq action 'compile) ".compile ")
+		       ((eq action 'batch)   "@")
+		       (t (error "Unknown action %s" action)))
+		 idlwave-shell-last-save-and-action-file)
+	 nil nil)
+	(idlwave-shell-bp-query))
+    (let ((msg (format "No such file %s" 
+		       idlwave-shell-last-save-and-action-file)))
+      (setq idlwave-shell-last-save-and-action-file nil)
+      (error msg))))
+
+(defvar idlwave-shell-sources-query "help,/source"
+  "IDL command to obtain source files for compiled procedures.")
+
+(defvar idlwave-shell-sources-alist nil
+  "Alist of IDL procedure names and compiled source files.
+Elements of the alist have the form:
+
+  (module name . (source-file-truename idlwave-internal-filename)).")
+
+(defun idlwave-shell-sources-query ()
+  "Determine source files for IDL compiled procedures.
+Queries IDL using the string in `idlwave-shell-sources-query'."
+  (interactive)
+  (idlwave-shell-send-command idlwave-shell-sources-query
+			      'idlwave-shell-sources-filter
+			      'hide))
+
+(defun idlwave-shell-sources-filter ()
+  "Get source files from `idlwave-shell-sources-query' output.
+Create `idlwave-shell-sources-alist' consisting of 
+list elements of the form:
+ (module name . (source-file-truename idlwave-internal-filename))."
+  (save-excursion
+    (set-buffer (get-buffer-create idlwave-shell-bp-buffer))
+    (erase-buffer)
+    (insert idlwave-shell-command-output)
+    (goto-char (point-min))
+    (let (cpro cfun)
+      (if (re-search-forward "Compiled Procedures:" nil t)
+          (progn
+            (forward-line) ; Skip $MAIN$
+            (setq cpro (point))))
+      (if (re-search-forward "Compiled Functions:" nil t)
+          (progn
+            (setq cfun (point))
+            (setq idlwave-shell-sources-alist
+                  (append
+                   ;; compiled procedures
+                   (progn
+                     (beginning-of-line)
+                     (narrow-to-region cpro (point))
+                     (goto-char (point-min))
+                     (idlwave-shell-sources-grep))
+                   ;; compiled functions
+                   (progn
+                     (widen)
+                     (goto-char cfun)
+                     (idlwave-shell-sources-grep)))))))))
+
+(defun idlwave-shell-sources-grep ()
+  (save-excursion
+    (let ((al (list nil)))
+      (while (and
+              (not (progn (forward-line) (eobp)))
+              (re-search-forward
+               "\\s-*\\(\\S-+\\)\\s-+\\(\\S-+\\)" nil t))
+        (nconc al
+               (list
+                (cons
+                 (buffer-substring      ; name
+                  (match-beginning 1) (match-end 1))
+                 (let ((internal-filename
+                        (buffer-substring       ; source
+                         (match-beginning 2) (match-end 2))))
+                   (list
+                    (idlwave-shell-file-name internal-filename)
+                    internal-filename))
+		 ))))
+      (cdr al))))
+
+
+(defun idlwave-shell-clear-all-bp ()
+  "Remove all breakpoints in IDL."
+  (interactive)
+  (idlwave-shell-send-command
+   idlwave-shell-bp-query
+   '(progn
+      (idlwave-shell-filter-bp)
+      (mapcar 'idlwave-shell-clear-bp idlwave-shell-bp-alist))
+   'hide))
+
+(defun idlwave-shell-list-all-bp ()
+  "List all breakpoints in IDL."
+  (interactive)
+  (idlwave-shell-send-command
+   idlwave-shell-bp-query))
+
+(defvar idlwave-shell-error-last 0
+  "Position of last syntax error in `idlwave-shell-error-buffer'.")
+
+(defun idlwave-shell-goto-next-error ()
+  "Move point to next IDL syntax error."
+  (interactive)
+  (let (frame col)
+    (save-excursion
+      (set-buffer idlwave-shell-error-buffer)
+      (goto-char idlwave-shell-error-last)
+      (if (or (re-search-forward idlwave-shell-syntax-error nil t)
+              (re-search-forward idlwave-shell-other-error nil t))
+          (progn
+            (setq frame
+                  (list
+                   (save-match-data
+                     (idlwave-shell-file-name
+                      (buffer-substring (match-beginning 1) (match-end 1))))
+                   (string-to-int
+                    (buffer-substring (match-beginning 2)
+                                      (match-end 2)))))
+            ;; Try to find the column of the error
+            (save-excursion
+              (setq col
+                    (if (re-search-backward "\\^" nil t)
+                        (current-column)
+                      0)))))
+      (setq idlwave-shell-error-last (point)))
+    (if frame
+        (progn
+          (idlwave-shell-display-line frame col))
+      (beep)
+      (message "No more errors."))))
+
+(defun idlwave-shell-file-name (name)
+  "If idlwave-shell-use-truename is non-nil, convert file name to true name.
+Otherwise, just expand the file name."
+  (let ((def-dir (if (eq major-mode 'idlwave-shell-mode)
+		     default-directory
+		   idlwave-shell-default-directory)))
+    (if idlwave-shell-use-truename 
+	(file-truename name def-dir) 
+      (expand-file-name name def-dir))))
+
+
+;; Keybindings --------------------------------------------------------------
+
+(defvar idlwave-shell-mode-map (copy-keymap comint-mode-map)
+  "Keymap for idlwave-mode.")
+(defvar idlwave-shell-mode-prefix-map (make-sparse-keymap))
+(fset 'idlwave-shell-mode-prefix-map idlwave-shell-mode-prefix-map)
+
+;(define-key idlwave-shell-mode-map "\M-?" 'comint-dynamic-list-completions)
+;(define-key idlwave-shell-mode-map "\t" 'comint-dynamic-complete)
+(define-key idlwave-shell-mode-map "\t"       'idlwave-shell-complete)
+(define-key idlwave-shell-mode-map "\M-\t"    'idlwave-shell-complete)
+(define-key idlwave-shell-mode-map "\C-c\C-s" 'idlwave-shell)
+(define-key idlwave-shell-mode-map "\C-c?"    'idlwave-routine-info)
+(define-key idlwave-shell-mode-map "\C-c\C-i" 'idlwave-update-routine-info)
+(define-key idlwave-shell-mode-map "\C-c="    'idlwave-resolve)
+(define-key idlwave-shell-mode-map "\C-c\C-v" 'idlwave-find-module)
+(define-key idlwave-shell-mode-map idlwave-shell-prefix-key
+  'idlwave-shell-debug-map)
+
+;; The following set of bindings is used to bind the debugging keys.
+;; If `idlwave-shell-activate-prefix-keybindings' is non-nil, the first key
+;; in the list gets bound the C-c C-d prefix map.
+;; If `idlwave-shell-activate-alt-keybindings' is non-nil, the second key
+;; in the list gets bound directly in both idlwave-mode-map and 
+;; idlwave-shell-mode-map.
+
+;; Used keys:   abcde  hi klmnopqrs u wxyz 
+;; Unused keys:      fg  j         t v  
+(let ((specs
+ '(([(control ?b)]   [(alt ?b)]   idlwave-shell-break-here)
+   ([(control ?i)]   [(alt ?i)]   idlwave-shell-break-in)
+   ([(control ?d)]   [(alt ?d)]   idlwave-shell-clear-current-bp)
+   ([(control ?a)]   [(alt ?a)]   idlwave-shell-clear-all-bp)
+   ([(control ?s)]   [(alt ?s)]   idlwave-shell-step)
+   ([(control ?n)]   [(alt ?n)]   idlwave-shell-stepover)
+   ([(control ?k)]   [(alt ?k)]   idlwave-shell-skip)
+   ([(control ?u)]   [(alt ?u)]   idlwave-shell-up)
+   ([(control ?o)]   [(alt ?o)]   idlwave-shell-out)
+   ([(control ?m)]   [(alt ?m)]   idlwave-shell-return)
+   ([(control ?h)]   [(alt ?h)]   idlwave-shell-to-here)
+   ([(control ?r)]   [(alt ?r)]   idlwave-shell-cont)
+   ([(control ?y)]   [(alt ?y)]   idlwave-shell-execute-default-command-line)
+   ([(control ?z)]   [(alt ?z)]   idlwave-shell-reset)
+   ([(control ?q)]   [(alt ?q)]   idlwave-shell-quit)
+   ([(control ?p)]   [(alt ?p)]   idlwave-shell-print)
+   ([(??)]           [(alt ??)]   idlwave-shell-help-expression)
+   ([(control ?c)]   [(alt ?c)]   idlwave-shell-save-and-run)
+   ([(        ?@)]   [(alt ?@)]   idlwave-shell-save-and-batch)
+   ([(control ?x)]   [(alt ?x)]   idlwave-shell-goto-next-error)
+   ([(control ?e)]   [(alt ?e)]   idlwave-shell-run-region)
+   ([(control ?w)]   [(alt ?w)]   idlwave-shell-resync-dirs)
+   ([(control ?l)]   [(alt ?l)]   idlwave-shell-redisplay)
+   ([(control ?t)]   [(alt ?t)]   idlwave-shell-toggle-toolbar)
+   ([(control up)]   [(alt up)]   idlwave-shell-stack-up)
+   ([(control down)] [(alt down)] idlwave-shell-stack-down)))   
+      s k1 k2 cmd)
+  (while (setq s (pop specs))
+    (setq k1  (nth 0 s)
+	  k2  (nth 1 s)
+	  cmd (nth 2 s))
+    (when idlwave-shell-activate-prefix-keybindings
+      (and k1 (define-key idlwave-shell-mode-prefix-map k1 cmd)))
+    (when idlwave-shell-activate-alt-keybindings
+      (and k2 (define-key idlwave-mode-map       k2 cmd))
+      (and k2 (define-key idlwave-shell-mode-map k2 cmd)))))
+
+;; Enter the prefix map at the two places.
+(fset 'idlwave-debug-map       idlwave-shell-mode-prefix-map)
+(fset 'idlwave-shell-debug-map idlwave-shell-mode-prefix-map)
+
+;; The Menus --------------------------------------------------------------
+
+(defvar idlwave-shell-menu-def
+  '("Debug"
+    ["Save and .RUN" idlwave-shell-save-and-run
+     (or (eq major-mode 'idlwave-mode)
+	 idlwave-shell-last-save-and-action-file)]
+    ["Save and .COMPILE" idlwave-shell-save-and-compile
+     (or (eq major-mode 'idlwave-mode)
+	 idlwave-shell-last-save-and-action-file)]
+    ["Save and @Batch" idlwave-shell-save-and-batch
+     (or (eq major-mode 'idlwave-mode)
+	 idlwave-shell-last-save-and-action-file)]
+    ["Goto Next Error" idlwave-shell-goto-next-error t]
+    "--"
+    ["Execute Default Cmd" idlwave-shell-execute-default-command-line t]
+    ["Edit Default Cmd" idlwave-shell-edit-default-command-line t]
+    "--"
+    ["Set Breakpoint" idlwave-shell-break-here
+     (eq major-mode 'idlwave-mode)]
+    ["Break in Module" idlwave-shell-break-in t]
+    ["Clear Breakpoint" idlwave-shell-clear-current-bp t]
+    ["Clear All Breakpoints" idlwave-shell-clear-all-bp t]
+    ["List  All Breakpoints" idlwave-shell-list-all-bp t]
+    "--"
+    ["Step (into)" idlwave-shell-step t]
+    ["Step (over)" idlwave-shell-stepover t]
+    ["Skip One Statement" idlwave-shell-skip t]
+    ["Continue" idlwave-shell-cont t]
+    ("Continue to"
+     ["End of Block" idlwave-shell-up t]
+     ["End of Subprog" idlwave-shell-return t]
+     ["End of Subprog+1" idlwave-shell-out t]
+     ["Here (Cursor Line)" idlwave-shell-to-here
+      (eq major-mode 'idlwave-mode)])
+    "--"
+    ["Print expression" idlwave-shell-print t]
+    ["Help on expression" idlwave-shell-help-expression t]
+    ["Evaluate Region" idlwave-shell-evaluate-region 
+     (eq major-mode 'idlwave-mode)]
+    ["Run Region" idlwave-shell-run-region (eq major-mode 'idlwave-mode)]
+    "--"
+    ["Redisplay" idlwave-shell-redisplay t]
+    ["Stack Up" idlwave-shell-stack-up t]
+    ["Stack Down" idlwave-shell-stack-down t]
+    "--"
+    ["Update Working Dir" idlwave-shell-resync-dirs t]
+    ["Reset IDL" idlwave-shell-reset t]
+    "--"
+    ["Toggle Toolbar" idlwave-shell-toggle-toolbar t]
+    ["Exit IDL" idlwave-shell-quit t]))
+
+(if (or (featurep 'easymenu) (load "easymenu" t))
+    (progn
+      (easy-menu-define
+       idlwave-shell-mode-menu idlwave-shell-mode-map "IDL shell menus"
+       idlwave-shell-menu-def)
+      (easy-menu-define 
+       idlwave-mode-debug-menu idlwave-mode-map "IDL debugging menus"
+       idlwave-shell-menu-def)
+      (save-excursion
+	(mapcar (lambda (buf)
+		  (set-buffer buf)
+		  (if (eq major-mode 'idlwave-mode)
+		      (progn
+			(easy-menu-remove idlwave-mode-debug-menu)
+			(easy-menu-add idlwave-mode-debug-menu))))
+		(buffer-list)))))
+
+;; The Breakpoint Glyph -------------------------------------------------------
+
+(defvar idlwave-shell-bp-glyph nil
+  "The glyph to mark breakpoint lines in the source code.")
+
+(let ((image-string "/* XPM */
+static char * file[] = {
+\"14 12 3 1\",
+\" 	c #FFFFFFFFFFFF s backgroundColor\",
+\".	c #4B4B4B4B4B4B\",
+\"R	c #FFFF00000000\",
+\"              \",
+\"              \",
+\"    RRRR      \",
+\"   RRRRRR     \",
+\"  RRRRRRRR    \",
+\"  RRRRRRRR    \",
+\"  RRRRRRRR    \",
+\"  RRRRRRRR    \",
+\"   RRRRRR     \",
+\"    RRRR      \",
+\"              \",
+\"              \"};"))
+      
+  (setq idlwave-shell-bp-glyph
+	(cond ((and (featurep 'xemacs)
+		    (featurep 'xpm))
+	       (make-glyph image-string))
+	      ((and (not (featurep 'xemacs))
+		    (fboundp 'image-type-available-p)
+		    (image-type-available-p 'xpm))
+	       (list 'image :type 'xpm :data image-string))
+	      (t nil))))
+
+(provide 'idlwave-shell)
+
+;;; Load the toolbar when wanted by the user.
+
+(defun idlwave-shell-toggle-toolbar ()
+  "Toggle the display of the debugging toolbar."
+  (interactive)
+  (if (featurep 'idlwave-toolbar)
+      (idlwave-toolbar-toggle)
+    (require 'idlwave-toolbar)
+    (idlwave-toolbar-toggle)))
+
+
+(when idlwave-shell-use-toolbar
+  (or (load "idlwave-toolbar" t)
+      (message
+       "Tried to load file `idlwave-toolbar.el', but file does not exist")))
+
+;;; idlwave-shell.el ends here
+
+