diff lisp/progmodes/idlw-shell.el @ 69822:84de63539ab8

Update to IDLWAVE version 6.0; see idlwave.org. Includes code to obsolete idlw-rinfo.el.
author J.D. Smith <jdsmith@as.arizona.edu>
date Thu, 06 Apr 2006 18:47:37 +0000
parents dc49655f57ae
children b79a60a5fdeb 81f2d90dee68 65ca8fb66a0d
line wrap: on
line diff
--- a/lisp/progmodes/idlw-shell.el	Thu Apr 06 18:46:56 2006 +0000
+++ b/lisp/progmodes/idlw-shell.el	Thu Apr 06 18:47:37 2006 +0000
@@ -1,12 +1,12 @@
 ;; idlw-shell.el --- run IDL as an inferior process of Emacs.
 ;; Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-;; Free Software Foundation, Inc.
+;;    Free Software Foundation
 
 ;; Authors: J.D. Smith <jdsmith@as.arizona.edu>
 ;;          Carsten Dominik <dominik@astro.uva.nl>
 ;;          Chris Chase <chase@att.com>
 ;; Maintainer: J.D. Smith <jdsmith@as.arizona.edu>
-;; Version: 5.7_22
+;; Version: 6.0_em22
 ;; Keywords: processes
 
 ;; This file is part of GNU Emacs.
@@ -138,6 +138,11 @@
 
 ;; (defcustom idlwave-shell-automatic-start...)  See idlwave.el
 
+(defcustom idlwave-shell-use-dedicated-window nil
+  "*Non-nil means, never replace the shell frame with another buffer."
+  :group 'idlwave-shell-general-setup
+  :type 'boolean) 
+
 (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
@@ -313,8 +318,15 @@
 	       (const :tag "All debug and stepping commands" 	   debug)
 	       (const :tag "Close, window, retall, etc. commands"  misc))))
 
+(defcustom idlwave-shell-max-print-length 200
+  "Maximum number of array elements to print when examining."
+  :group 'idlwave-shell-command-setup
+  :type 'integer)
+
 (defcustom idlwave-shell-examine-alist 
-  '(("Print"          	. "print,___")
+  `(("Print"          	. ,(concat "idlwave_print_safe,___," 
+				   (number-to-string 
+				    idlwave-shell-max-print-length)))
     ("Help"           	. "help,___")
     ("Structure Help"  	. "help,___,/STRUCTURE")
     ("Dimensions"     	. "print,size(___,/DIMENSIONS)")
@@ -322,6 +334,7 @@
     ("N_Elements"     	. "print,n_elements(___)")
     ("All Size Info"  	. "help,(__IWsz__=size(___,/STRUCTURE)),/STRUCTURE & print,__IWsz__.DIMENSIONS")
     ("Ptr Valid"      	. "print,ptr_valid(___)")
+    ("Arg Present"      . "print,arg_present(___)")
     ("Widget Valid"     . "print,widget_info(___,/VALID)")
     ("Widget Geometry"  . "help,widget_info(___,/GEOMETRY)"))
   "Alist of special examine commands for popup selection.  
@@ -437,6 +450,11 @@
   :group 'idlwave-shell-command-setup
   :type 'boolean)
 
+(defcustom idlwave-shell-reset-no-prompt nil
+  "If non-nil, skip the yes/no prompt when resetting the IDL session."
+  :group 'idlwave-shell-command-setup
+  :type 'boolean)
+
 ;; Breakpoint Overlays etc
 (defgroup idlwave-shell-highlighting-and-faces nil
   "Highlighting and Faces used by the IDLWAVE Shell mode."
@@ -488,11 +506,11 @@
 
 (defcustom idlwave-shell-electric-stop-line-face 
   (prog1
-      (copy-face 'modeline 'idlwave-shell-electric-stop-line-face)
-    (set-face-background 'idlwave-shell-electric-stop-line-face 
+      (copy-face 'modeline 'idlwave-shell-electric-stop-line)
+    (set-face-background 'idlwave-shell-electric-stop-line 
 			 idlwave-shell-electric-stop-color)
     (condition-case nil
-	(set-face-foreground 'idlwave-shell-electric-stop-line-face nil)
+	(set-face-foreground 'idlwave-shell-electric-stop-line nil)
       (error nil)))
   "*The face for `idlwave-shell-stop-line-overlay' when in electric debug mode.
 Allows you to choose the font, color and other properties for the line
@@ -553,6 +571,7 @@
     "Face for highlighting lines with breakpoints."
     :group 'idlwave-shell-highlighting-and-faces))
 
+
 (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
@@ -652,7 +671,7 @@
   "The overlay for where IDL is currently stopped.")
 (defvar idlwave-shell-is-stopped nil)
 (defvar idlwave-shell-expression-overlay nil
-  "The overlay for where IDL is currently stopped.")
+  "The overlay for the examined expression.")
 (defvar idlwave-shell-output-overlay nil
   "The overlay for the last IDL output.")
 
@@ -700,10 +719,21 @@
 (setq idlwave-shell-expression-overlay (make-overlay 1 1))
 (overlay-put idlwave-shell-expression-overlay
 	     'face idlwave-shell-expression-face)
+(overlay-put idlwave-shell-expression-overlay
+	     'priority 1)
 (setq idlwave-shell-output-overlay (make-overlay 1 1))
 (overlay-put idlwave-shell-output-overlay
 	     'face idlwave-shell-output-face)
 
+(copy-face idlwave-shell-stop-line-face 
+	   'idlwave-shell-pending-stop)
+(copy-face idlwave-shell-electric-stop-line-face 
+	   'idlwave-shell-pending-electric-stop)
+(set-face-background 'idlwave-shell-pending-stop "gray70")
+(set-face-background 'idlwave-shell-pending-electric-stop "gray70")
+
+
+
 (defvar idlwave-shell-bp-query "help,/breakpoints"
   "Command to obtain list of breakpoints")
 
@@ -823,6 +853,7 @@
   ?          Help on expression near point or in region ([C-u ?]).
   x          Examine expression near point or in region ([C-u x]) with 
              letter completion of the examine type.
+  e          Prompt for an expression to print.
 
  Miscellaneous:
   q   	     Quit - end debugging session and return to the Shell's main level.
@@ -998,6 +1029,8 @@
   (setq idlwave-shell-default-directory default-directory)
   (setq idlwave-shell-hide-output nil)
 
+  ;; NB: `make-local-hook' needed for older/alternative Emacs compatibility
+  ;; (make-local-hook 'kill-buffer-hook)
   (add-hook 'kill-buffer-hook 'idlwave-shell-kill-shell-buffer-confirm
 	    nil 'local)
   (add-hook 'kill-buffer-hook 'idlwave-shell-delete-temp-files nil 'local)
@@ -1040,6 +1073,8 @@
   (set (make-local-variable 'comment-start) ";")
   (setq abbrev-mode t)
 
+  ;; NB: `make-local-hook' needed for older/alternative Emacs compatibility
+  ;; make-local-hook 'post-command-hook)
   (add-hook 'post-command-hook 'idlwave-command-hook nil t)
 
   ;; Read the command history?
@@ -1061,23 +1096,25 @@
   (idlwave-shell-send-command 
    (format "defsysv,'!idlwave_version','%s',1" idlwave-mode-version)
    nil 'hide)
-  ;; Get the paths if they weren't read in from file
-  (if (and (not idlwave-path-alist)
-	   (or (not (stringp idlwave-system-directory))
-	       (eq (length idlwave-system-directory) 0)))
-      (idlwave-shell-send-command idlwave-shell-path-query
-				  'idlwave-shell-get-path-info
-				  'hide)))
-
+  ;; Read the paths, and save if they changed
+  (idlwave-shell-send-command idlwave-shell-path-query
+			      'idlwave-shell-get-path-info
+			      'hide))
+
+(defvar idlwave-system-directory)
 (defun idlwave-shell-get-path-info (&optional no-write)
   "Get the path lists, writing to file unless NO-WRITE is set."
   (let* ((rpl (idlwave-shell-path-filter))
 	 (sysdir (car rpl))
 	 (dirs (cdr rpl))
-	 (old-path-alist idlwave-path-alist))
+	 (old-path-alist idlwave-path-alist)
+	 (old-sys-dir idlwave-system-directory)
+	 path-changed sysdir-changed)
     (when sysdir
       (setq idlwave-system-directory sysdir)
-      (put 'idlwave-system-directory 'from-shell t))
+      (if (setq sysdir-changed 
+		(not (string= idlwave-system-directory old-sys-dir)))
+	  (put 'idlwave-system-directory 'from-shell t)))
     ;; Preserve any existing flags
     (setq idlwave-path-alist 
 	  (mapcar (lambda (x)
@@ -1086,11 +1123,13 @@
 			  (cons x (cdr old-entry))
 			(list x))))
 		  dirs))
-    (put 'idlwave-path-alist 'from-shell t)
+    (if (setq path-changed (not (equal idlwave-path-alist old-path-alist)))
+	(put 'idlwave-path-alist 'from-shell t))
     (if idlwave-path-alist 
-	(if (and idlwave-auto-write-paths
-		 (not idlwave-library-path)
-		 (not no-write) )
+	(if (and (not no-write)
+		 idlwave-auto-write-paths
+		 (or sysdir-changed path-changed)
+		 (not idlwave-library-path))
 	    (idlwave-write-paths))
       ;; Fall back
       (setq idlwave-path-alist old-path-alist))))
@@ -1199,12 +1238,14 @@
 	  (current-window (selected-window)))
       (select-window window)
       (goto-char (point-max))
+      (if idlwave-shell-use-dedicated-window
+	  (set-window-dedicated-p window t))
       (select-window current-window)
       (if idlwave-shell-ready
 	  (raise-frame (window-frame window)))
       (if (eq (selected-frame) (window-frame window))
 	  (select-window window))))
-  ;; Save the paths at the end
+  ;; Save the paths at the end, if they are from the Shell and new.
   (add-hook 'idlwave-shell-sentinel-hook 
 	    (lambda ()
 	      (if (and 
@@ -1518,10 +1559,10 @@
 	    
 	    
 ;;; Test/Debug code
-;	      (save-excursion (set-buffer
-;			       (get-buffer-create "*idlwave-shell-output*"))
-;			      (goto-char (point-max))
-;			      (insert "\nSTRING===>\n" string "\n<====\n"))
+	      ;(with-current-buffer
+	      ;	  (get-buffer-create "*idlwave-shell-output*")
+	      ;	(goto-char (point-max))
+	      ;	(insert "\nReceived STRING\n===>\n" string "\n<====\n"))
 	    
 	      ;; Check for prompt in current accumulating output
 	      (when (setq idlwave-shell-ready
@@ -1536,14 +1577,14 @@
 		      (re-search-backward idlwave-shell-prompt-pattern nil t)
 		      (goto-char (match-end 0))
 		      (setq idlwave-shell-command-output
-		      (buffer-substring (point-min) (point)))
+		      (buffer-substring-no-properties (point-min) (point)))
 		      (delete-region (point-min) (point)))
 		  (setq idlwave-shell-command-output
 			(with-current-buffer (process-buffer proc)
-			(buffer-substring
+			(buffer-substring-no-properties
 			 (save-excursion
 			   (goto-char (process-mark proc))
-			   (forward-line 0)
+			   (forward-line 0) ; Emacs 21 (beginning-of-line nil)
 			   (point))
 			 comint-last-input-end))))
 
@@ -1570,10 +1611,10 @@
 		  ;; Call the post-command hook
 		  (if (listp idlwave-shell-post-command-hook)
 		      (progn
-					;(message "Calling list")
-					;(prin1 idlwave-shell-post-command-hook)
+			;;(message "Calling list")
+			;;(prin1 idlwave-shell-post-command-hook)
 			(eval idlwave-shell-post-command-hook))
-					;(message "Calling command function")
+		    ;;(message "Calling command function")
 		    (funcall idlwave-shell-post-command-hook))
 
 		  ;; Reset to default state for next command.
@@ -1668,6 +1709,8 @@
 All parts may contain linebreaks surrounded by spaces.  This is important
 in IDL5 which inserts random linebreaks in long module and file names.")
 
+(defvar idlwave-shell-electric-debug-mode) ; defined by easy-mmode
+
 (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
@@ -1688,9 +1731,8 @@
 		     idlwave-shell-command-output)
        (string-match idlwave-shell-other-error
 		     idlwave-shell-command-output))
-      (save-excursion
-	(set-buffer
-	 (get-buffer-create idlwave-shell-error-buffer))
+      (with-current-buffer
+	  (get-buffer-create idlwave-shell-error-buffer)
 	(erase-buffer)
 	(insert idlwave-shell-command-output)
 	(goto-char (point-min))
@@ -1723,8 +1765,10 @@
 	     (substring idlwave-shell-command-output (match-end 0))))
       (setq idlwave-shell-current-state 'halt)
       ;; Don't debug trace messages
-      (idlwave-shell-display-line (idlwave-shell-pc-frame) nil
-				  (if trace 'no-debug)))
+      (idlwave-shell-display-line 
+       (idlwave-shell-pc-frame) nil
+       (if trace 'disable
+	 (if idlwave-shell-electric-debug-mode 'force))))
      
      ;; Fourth Priority: Breakpoints 
      ((string-match idlwave-shell-break-message
@@ -1763,29 +1807,29 @@
 
 
 (defun idlwave-shell-parse-line (string &optional skip-main)
-  "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.
-
-If optional arg SKIP-MAIN is non-nil, don't parse $MAIN$ routine stop
-statements."
+  "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 an 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.
+;
+;If optional arg SKIP-MAIN is non-nil, don't parse $MAIN$ routine stop
+;statements.
 
   (let (number procedure file)
     (when (and (not (if skip-main (string-match ":\\s-*\\$MAIN" string)))
@@ -1926,14 +1970,17 @@
 HEAP_GC, /VERBOSE"
   ;; OBJ_DESTROY, OBJ_VALID()  FIXME: should this be added?
   (interactive "P")
-  (message "Resetting IDL")
-  (setq idlwave-shell-calling-stack-index 0)
-  (idlwave-shell-send-command "retall" nil hidden)
-  (idlwave-shell-send-command "widget_control,/reset" nil hidden)
-  (idlwave-shell-send-command "close,/all" nil hidden)
-  ;; (idlwave-shell-send-command "obj_destroy, obj_valid()" nil hidden)
-  (idlwave-shell-send-command "heap_gc,/verbose" nil hidden)
-  (idlwave-shell-display-line nil))
+  (when (or idlwave-shell-reset-no-prompt 
+	    (yes-or-no-p "Really Reset IDL and discard current session? "))
+    (message "Resetting IDL")
+    (setq idlwave-shell-calling-stack-index 0)
+    ;; Give widget exit handlers a chance
+    (idlwave-shell-send-command "retall" nil hidden)
+    (idlwave-shell-send-command "widget_control,/reset" nil hidden)
+    (idlwave-shell-send-command "close,/all" nil hidden)
+    ;; (idlwave-shell-send-command "obj_destroy, obj_valid()" nil hidden)
+    (idlwave-shell-send-command "heap_gc,/verbose" nil hidden)
+    (idlwave-shell-display-line nil)))
 
 (defun idlwave-shell-path-filter ()
   ;; Convert the output of the path query into a list of directories
@@ -1978,9 +2025,6 @@
 	  (message 
 	   "Routine Info warning: No match for END line in \n>>>\n%s\n<<<\n" 
 	   idlwave-shell-command-output)))
-    (if (string-match "\\S-" text)
-	;; Obviously, the pro worked.  Make a note that we have it now.
-	(setq idlwave-idlwave_routine_info-compiled t))
     ;; Match the output lines
     (while (string-match "^IDLWAVE-\\(PRO\\|FUN\\): \\(.*\\)" text start)
       (setq start (match-end 0))
@@ -2208,7 +2252,6 @@
     (looking-at "\\$")))
 
 ;; Debugging Commands ------------------------------------------------------
-(defvar idlwave-shell-electric-debug-mode) ; defined by easy-mmode
 
 (defun idlwave-shell-redisplay (&optional hide)
   "Tries to resync the display with where execution has stopped.
@@ -2259,14 +2302,14 @@
     (setq idlwave-shell-calling-stack-routine 
 	  (nth 2 (nth idlwave-shell-calling-stack-index stack)))
 
-    ;; only edebug if in that mode already
+    ;; force edebug for this frame if we're in that mode already
     (idlwave-shell-display-line 
      (nth idlwave-shell-calling-stack-index stack) nil
-     (unless idlwave-shell-electric-debug-mode 'no-debug)) 
+     (if idlwave-shell-electric-debug-mode 'force))
     (message "%s" (or message 
-		 (format "In routine %s (stack level %d)"
-			 idlwave-shell-calling-stack-routine
-			 (- idlwave-shell-calling-stack-index))))))
+		      (format "In routine %s (stack level %d)"
+			      idlwave-shell-calling-stack-routine
+			      (- idlwave-shell-calling-stack-index))))))
 
 (defun idlwave-shell-stack-up ()
   "Display the source code one step up the calling stack."
@@ -2302,30 +2345,38 @@
   "Check that frame is for an existing file."
   (file-readable-p (car frame)))
 
+(defun idlwave-shell-stop-line-pending ()
+  ;; Temporarily change the color of the stop line overlay
+  (if idlwave-shell-stop-line-overlay
+      (overlay-put idlwave-shell-stop-line-overlay 'face
+		   (if idlwave-shell-electric-debug-mode
+		       'idlwave-shell-pending-electric-stop
+		     'idlwave-shell-pending-stop))))
+
 (defvar idlwave-shell-suppress-electric-debug nil)
-(defun idlwave-shell-display-line (frame &optional col no-debug)
-  "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 COL is set, move point to that
-column in the line.  If NO-DEBUG is non-nil, do *not* toggle the electric
-debug mode."
+(defun idlwave-shell-display-line (frame &optional col debug)
+  "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 col is set, move point to that
+column in the line.  if debug is non-nil, enable the electric debug
+mode.  if it is 'disable, do not enable no matter what the setting of
+'idlwave-shell-automatic-electric-debug'.  if it is 'force, enable no
+matter what the settings of that variable."
   (if (not frame)
-      ;; Remove stop-line overlay from old position
+      ;; remove stop-line overlay from old position
       (progn 
         (setq overlay-arrow-string nil)
 	(setq idlwave-shell-mode-line-info nil)
 	(setq idlwave-shell-is-stopped nil)
         (if idlwave-shell-stop-line-overlay
             (delete-overlay idlwave-shell-stop-line-overlay))
-	;; Turn off electric debug everywhere, if it's on
-	(if (and (not no-debug)
-		 idlwave-shell-automatic-electric-debug)
-	    (idlwave-shell-electric-debug-all-off)))
+	;; turn off electric debug everywhere, if it's on
+	(idlwave-shell-electric-debug-all-off))
     (if (not (idlwave-shell-valid-frame frame))
-	;; FIXME: errors are dangerous in shell filters.  But I think I
+	;; fixme: errors are dangerous in shell filters.  but i think i
 	;; have never encountered this one.
-        (error (concat "Invalid frame - unable to access file: " (car 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.
@@ -2339,15 +2390,15 @@
              (select-shell (equal (buffer-name) (idlwave-shell-buffer)))
              window pos electric)
 
-	;; First make sure the shell window is visible
+	;; 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.
+	;; 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
+	;; enter the buffer and mark the line
         (save-excursion
           (set-buffer buffer)
           (save-restriction
@@ -2358,45 +2409,53 @@
 	    (setq idlwave-shell-is-stopped t)
 	    
             (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.
+                (progn
+		  ;; restore face and move overlay 
+		  (overlay-put idlwave-shell-stop-line-overlay 'face
+			       (if idlwave-shell-electric-debug-mode
+                                   idlwave-shell-electric-stop-line-face 
+                                 idlwave-shell-stop-line-face))
+		  (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 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 we have the column of the error, move the cursor there.
           (if col (move-to-column col))
           (setq pos (point))
 	  
-	  ;; Enter electric debug mode, if not prohibited and not in
+	  ;; enter electric debug mode, if not prohibited and not in
 	  ;; it already
-	  (when (and (or 
-		      (eq idlwave-shell-automatic-electric-debug t)
-		      (and 
-		       (eq idlwave-shell-automatic-electric-debug 'breakpoint)
-		       (not (eq idlwave-shell-current-state 'error))))
-		     (not no-debug)
-		     (not idlwave-shell-suppress-electric-debug)
-		     (not idlwave-shell-electric-debug-mode))
-	    (idlwave-shell-electric-debug-mode)
-	    (setq electric t)))
+	  (when  (and (not idlwave-shell-electric-debug-mode)
+		      (or (eq debug 'force)
+			  (and 
+			   (not (eq debug 'disable)) ;; explicitly disabled
+			   (or 
+			    (eq idlwave-shell-automatic-electric-debug t)
+			    (and 
+			     (eq idlwave-shell-automatic-electric-debug 
+				 'breakpoint)
+			     (not (eq idlwave-shell-current-state 'error))))
+			   (not idlwave-shell-suppress-electric-debug))))
+	    (idlwave-shell-electric-debug-mode t))
+	  (setq electric idlwave-shell-electric-debug-mode))
 	
 	;; Make sure pos is really displayed in the window.
 	(set-window-point window pos)
 	
 	;; If we came from the shell, go back there.  Otherwise select 
-	;; the window where the error is displayed.
+	;; the window where the error/halt is displayed.
         (if (or (and idlwave-shell-electric-zap-to-file electric)
 		(and (equal (buffer-name) (idlwave-shell-buffer)) 
 		     (not select-shell)))
@@ -2408,6 +2467,7 @@
   (interactive "p")
   (or (not arg) (< arg 1)
       (setq arg 1))
+  (idlwave-shell-stop-line-pending)
   (idlwave-shell-send-command 
    (concat ".s " (if (integerp arg) (int-to-string arg) arg))
    nil (if (idlwave-shell-hide-p 'debug) 'mostly) nil t))
@@ -2419,6 +2479,7 @@
   (interactive "p")
   (or (not arg) (< arg 1)
       (setq arg 1))
+  (idlwave-shell-stop-line-pending)
   (idlwave-shell-send-command 
    (concat ".so " (if (integerp arg) (int-to-string arg) arg))
    nil (if (idlwave-shell-hide-p 'debug) 'mostly) nil t))
@@ -2462,13 +2523,13 @@
               (beep)
               (y-or-n-p 
                (concat "Okay to recompile file "
-                       (idlwave-shell-bp-get bp '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 
+               (concat ".run \"" (idlwave-shell-bp-get bp 'file) "\"") nil 
 	       (if (idlwave-shell-hide-p 'run) 'mostly) nil t)
               ;; Try setting breakpoint again
               (idlwave-shell-set-bp bp))
@@ -2496,6 +2557,7 @@
 (defun idlwave-shell-cont (&optional no-show)
   "Continue executing."
   (interactive)
+  (idlwave-shell-stop-line-pending)
   (idlwave-shell-send-command ".c" (unless no-show 
 				     '(idlwave-shell-redisplay 'hide))
 			      (if (idlwave-shell-hide-p 'debug) 'mostly) 
@@ -2504,6 +2566,7 @@
 (defun idlwave-shell-go ()
   "Run .GO.  This starts the main program of the last compiled file."
   (interactive)
+  (idlwave-shell-stop-line-pending)
   (idlwave-shell-send-command ".go" '(idlwave-shell-redisplay 'hide)
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
@@ -2511,6 +2574,7 @@
 (defun idlwave-shell-return ()
   "Run .RETURN (continue to next return, but stay in subprogram)."
   (interactive)
+  (idlwave-shell-stop-line-pending)
   (idlwave-shell-send-command ".return" '(idlwave-shell-redisplay 'hide)
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
@@ -2518,6 +2582,7 @@
 (defun idlwave-shell-skip ()
   "Run .SKIP (skip one line, then step)."
   (interactive)
+  (idlwave-shell-stop-line-pending)  
   (idlwave-shell-send-command ".skip" '(idlwave-shell-redisplay 'hide)
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
@@ -2603,6 +2668,7 @@
 (defun idlwave-shell-to-here ()
   "Set a breakpoint with count 1 then continue."
   (interactive)
+  ;; temporarily disable all other breakpoints
   (let ((disabled (idlwave-shell-enable-all-bp 'disable 'no-update)))
     (idlwave-shell-break-here 1 nil nil nil 'no-show)
     (idlwave-shell-cont 'no-show)
@@ -2739,13 +2805,18 @@
   `(lambda (event)
      "Expansion function for expression examination."
      (interactive "e")
-     (let ((transient-mark-mode t)
-	   (zmacs-regions t)
-	   (tracker (if (featurep 'xemacs) 
-			(if (fboundp 'default-mouse-track-event-is-with-button)
-			    'idlwave-xemacs-hack-mouse-track
-			  'mouse-track)
-		      'mouse-drag-region)))
+     (let* ((drag-track (fboundp 'mouse-drag-track))
+	    (transient-mark-mode t)
+	    (zmacs-regions t)
+	    (tracker (if (featurep 'xemacs) 
+			 (if (fboundp 
+			      'default-mouse-track-event-is-with-button)
+			     'idlwave-xemacs-hack-mouse-track
+			   'mouse-track)
+		       ;; Emacs 22 no longer completes the drag with
+		       ;; mouse-drag-region, without an additional
+		       ;; event.  mouse-drag-track does so.
+		       (if drag-track 'mouse-drag-track 'mouse-drag-region))))
        (funcall tracker event)
        (idlwave-shell-print (if (idlwave-region-active-p) '(4) nil)
 			    ,help ,ev))))
@@ -2756,8 +2827,9 @@
   t)
 
 (defun idlwave-xemacs-hack-mouse-track (event)
-  (if (featurep 'xemacs) 
-      (let ((oldfunc (symbol-function 'default-mouse-track-event-is-with-button)))
+  (if (featurep 'xemacs)
+      (let ((oldfunc (symbol-function 
+		      'default-mouse-track-event-is-with-button)))
 	(unwind-protect
 	    (progn
 	      (fset 'default-mouse-track-event-is-with-button 
@@ -2822,6 +2894,11 @@
 If instead COMPLETE-HELP-TYPE is non-nil, choose from
 idlw-shell-examine-alist via mini-buffer shortcut key."
   (interactive "P")
+
+  ;; For speed: assume the helper routine hasn't been lost, e.g. with
+  ;; .FULL_RESET_SESSION.  We'll recover if necessary
+  (unless idlwave-idlwave_routine_info-compiled
+    (idlwave-shell-compile-helper-routines))
   (save-excursion
     (let* ((process (get-buffer-process (current-buffer)))
 	   (process-mark (if process (process-mark process)))
@@ -2831,7 +2908,7 @@
 		(format "  [-%d:%s]" 
 			idlwave-shell-calling-stack-index 
 			idlwave-shell-calling-stack-routine)))
-	   expr beg end cmd examine-hook)
+	   expr beg end cmd)
       (cond
        ((equal arg '(16))
 	(setq expr (read-string "Expression: ")))
@@ -2874,10 +2951,6 @@
 		      (current-buffer))
 	(add-hook 'pre-command-hook 
 		  'idlwave-shell-delete-expression-overlay))
-      (setq examine-hook 
-	    (if idlwave-shell-separate-examine-output
-		'idlwave-shell-examine-display
-	      'idlwave-shell-examine-highlight))
       (add-hook 'pre-command-hook
 		'idlwave-shell-delete-output-overlay)
       
@@ -2939,7 +3012,7 @@
 	;;(idlwave-shell-recenter-shell-window)
 	(idlwave-shell-send-command 
 	 cmd 
-	 examine-hook 
+	 'idlwave-shell-check-compiled-and-display
 	 (if idlwave-shell-separate-examine-output 'hide))))))
 
 (defvar idlwave-shell-examine-window-alist nil
@@ -2949,6 +3022,15 @@
 (define-key idlwave-shell-examine-map "q" 'idlwave-shell-examine-display-quit)
 (define-key idlwave-shell-examine-map "c" 'idlwave-shell-examine-display-clear)
 
+
+(defun idlwave-shell-check-compiled-and-display ()
+  "Check examine output for warning about undefined procedure/function."
+  (if (string-match "% Attempt to call undefined" idlwave-shell-command-output)
+      (idlwave-shell-compile-helper-routines))
+  (if idlwave-shell-separate-examine-output
+      (idlwave-shell-examine-display)
+    (idlwave-shell-examine-highlight)))
+
 (defun idlwave-shell-examine-display ()
   "View the examine command output in a separate buffer."
   (let (win cur-beg cur-end)
@@ -3121,13 +3203,16 @@
 to insert expression in place of the marker ___, e.g.: print,
 size(___,/DIMENSIONS)"
   (cond
-   ((null help) (concat "print, " expr))
+   ((null help)
+    (concat "idlwave_print_safe, " expr "," 
+	    (number-to-string idlwave-shell-max-print-length)))
    ((stringp help) 
     (if (string-match "\\(^\\|[^_]\\)\\(___\\)\\([^_]\\|$\\)" help)
 	(concat (substring help 0 (match-beginning 2))
 		expr
 		(substring help (match-end 2)))))
-   (t (concat "help, " expr))))
+   (t 
+    (concat "help, " expr))))
    
 
 (defun idlwave-shell-examine-highlight ()
@@ -3221,7 +3306,8 @@
                  (idlwave-look-at "\\<end\\>")))
           (insert "\nend\n"))
       (save-buffer 0)))
-  (idlwave-shell-send-command (concat ".run " idlwave-shell-temp-pro-file)
+  (idlwave-shell-send-command (concat ".run \"" 
+				      idlwave-shell-temp-pro-file "\"")
 			      nil 
 			      (if (idlwave-shell-hide-p 'run) 'mostly)
 			      nil t)
@@ -3822,8 +3908,11 @@
 		       ((eq action 'compile) ".compile ")
 		       ((eq action 'batch)   "@")
 		       (t (error "Unknown action %s" action)))
-		 idlwave-shell-last-save-and-action-file)
-	 'idlwave-shell-maybe-update-routine-info
+		 "\""
+		 idlwave-shell-last-save-and-action-file
+		 "\"")
+	 `(idlwave-shell-maybe-update-routine-info nil
+	   ,idlwave-shell-last-save-and-action-file)
 	 (if (idlwave-shell-hide-p 'run) 'mostly) nil t)
 	(idlwave-shell-bp-query))
     (let ((msg (format "No such file %s" 
@@ -3831,14 +3920,14 @@
       (setq idlwave-shell-last-save-and-action-file nil)
       (error msg))))
 
-(defun idlwave-shell-maybe-update-routine-info (&optional wait)
+(defun idlwave-shell-maybe-update-routine-info (&optional wait file)
   "Update the routine info if the shell is not stopped at an error."
   (if (and (not idlwave-shell-is-stopped)
 	   (or (eq t idlwave-auto-routine-info-updates)
 	       (memq 'compile-buffer idlwave-auto-routine-info-updates))
 	   idlwave-query-shell-for-routine-info
 	   idlwave-routines)
-      (idlwave-shell-update-routine-info t nil wait)))
+      (idlwave-shell-update-routine-info t nil wait file)))
 
 (defvar idlwave-shell-sources-query "help,/source,/full"
   "IDL command to obtain source files for compiled procedures.")
@@ -3983,7 +4072,7 @@
       (setq idlwave-shell-error-last (point)))
     (if frame
         (progn
-          (idlwave-shell-display-line frame col 'no-debug))
+          (idlwave-shell-display-line frame col 'disable))
       (beep)
       (message "No more errors."))))
 
@@ -4158,6 +4247,8 @@
   'idlwave-shell-stack-down)
 (define-key idlwave-shell-electric-debug-mode-map "_" 
   'idlwave-shell-stack-down)
+(define-key idlwave-shell-electric-debug-mode-map "e" 
+  '(lambda () (interactive) (idlwave-shell-print '(16))))
 (define-key idlwave-shell-electric-debug-mode-map "q" 'idlwave-shell-retall)
 (define-key idlwave-shell-electric-debug-mode-map "t" 
   '(lambda () (interactive) (idlwave-shell-send-command "help,/TRACE")))
@@ -4181,9 +4272,11 @@
   ;; session until we return or hit $MAIN$.  Cancel this suppression
   ;; if it's explicitly turned on.
   (if idlwave-shell-electric-debug-mode
-      (setq idlwave-shell-suppress-electric-debug t)
-    (setq idlwave-shell-suppress-electric-debug nil))
-  (idlwave-shell-electric-debug-mode))
+      (progn ;; Turn it off, and make sure it stays off.
+	(setq idlwave-shell-suppress-electric-debug t)
+	(idlwave-shell-electric-debug-mode 0))
+    (setq idlwave-shell-suppress-electric-debug nil)
+    (idlwave-shell-electric-debug-mode t)))
 
 (defvar idlwave-shell-electric-debug-read-only) 
 (defvar idlwave-shell-electric-debug-buffers nil)
@@ -4196,9 +4289,9 @@
 
 When Electric Debug mode is enabled, the many debugging commands are
 available as single key sequences."
-  nil
-  " *Debugging*"
-  idlwave-shell-electric-debug-mode-map)
+nil
+" *Debugging*"
+idlwave-shell-electric-debug-mode-map)
 
 (add-hook 
  'idlwave-shell-electric-debug-mode-on-hook
@@ -4249,7 +4342,7 @@
 	  (when (and (eq major-mode 'idlwave-mode)
 		     buffer-file-name
 		     idlwave-shell-electric-debug-mode)
-	    (idlwave-shell-electric-debug-mode))))))
+	    (idlwave-shell-electric-debug-mode 0))))))
   (setq idlwave-shell-electric-debug-buffers nil))
 
 ;; Show the help text