New directory
[bpt/emacs.git] / lisp / progmodes / idlw-shell.el
CommitLineData
5e72c6b2 1;; idlw-shell.el --- run IDL as an inferior process of Emacs.
76959b77 2;; Copyright (c) 1999, 2000, 2001,2002 Free Software Foundation
5e72c6b2
S
3
4;; Author: Carsten Dominik <dominik@astro.uva.nl>
5;; Chris Chase <chase@att.com>
6;; Maintainer: J.D. Smith <jdsmith@as.arizona.edu>
76959b77 7;; Version: 4.15
463f5630 8;; Date: $Date: 2002/09/13 06:18:53 $
8c7b4ec8
EZ
9;; Keywords: processes
10
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs; see the file COPYING. If not, write to the
25;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26;; Boston, MA 02111-1307, USA.
27
28;;; Commentary:
5e72c6b2
S
29;;
30;; This mode is for IDL version 5 or later. It should work on
31;; Emacs>20.3 or XEmacs>20.4.
32;;
8c7b4ec8
EZ
33;; Runs IDL as an inferior process of Emacs, much like the emacs
34;; `shell' or `telnet' commands. Provides command history and
35;; searching. Provides debugging commands available in buffers
36;; visiting IDL procedure files, e.g., breakpoint setting, stepping,
37;; execution until a certain line, printing expressions under point,
38;; visual line pointer for current execution line, etc.
39;;
40;; Documentation should be available online with `M-x idlwave-info'.
5e72c6b2
S
41;;
42;; New versions of IDLWAVE, documentation, and more information
43;; available from:
44;; http://idlwave.org
45;;
8c7b4ec8
EZ
46;; INSTALLATION:
47;; =============
13ae1076 48;;
8c7b4ec8
EZ
49;; Follow the instructions in the INSTALL file of the distribution.
50;; In short, put this file on your load path and add the following
51;; lines to your .emacs file:
52;;
53;; (autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t)
54;;
55;;
56;; SOURCE
57;; ======
58;;
59;; The newest version of this file can be found on the maintainers
60;; web site.
13ae1076 61;;
5e72c6b2 62;; http://idlwave.org
13ae1076 63;;
8c7b4ec8
EZ
64;; DOCUMENTATION
65;; =============
66;;
67;; IDLWAVE is documented online in info format.
68;; A printable version of the documentation is available from the
69;; maintainers webpage (see under SOURCE)
70;;
71;;
72;; KNOWN PROBLEMS
73;; ==============
74;;
8c7b4ec8
EZ
75;; Under XEmacs the Debug menu in the shell does not display the
76;; keybindings in the prefix map. There bindings are available anyway - so
77;; it is a bug in XEmacs.
ca660d22 78;; The Debug menu in source buffers *does* display the bindings correctly.
8c7b4ec8 79;;
13ae1076 80;;
8c7b4ec8
EZ
81;; CUSTOMIZATION VARIABLES
82;; =======================
83;;
84;; IDLWAVE has customize support - so if you want to learn about
85;; the variables which control the behavior of the mode, use
86;; `M-x idlwave-customize'.
87;;
88;;--------------------------------------------------------------------------
89;;
8c7b4ec8
EZ
90\f
91;;; Code:
92
93(require 'comint)
94(require 'idlwave)
95
96(eval-when-compile (require 'cl))
97
98(defvar idlwave-shell-have-new-custom nil)
99(eval-and-compile
5e72c6b2
S
100 ;; Kludge to allow `defcustom' for Emacs 19.
101 (condition-case () (require 'custom) (error nil))
102 (if (and (featurep 'custom)
103 (fboundp 'custom-declare-variable)
13ae1076 104 (fboundp 'defface))
5e72c6b2
S
105 ;; We've got what we needed
106 (setq idlwave-shell-have-new-custom t)
107 ;; We have the old or no custom-library, hack around it!
108 (defmacro defgroup (&rest args) nil)
13ae1076 109 (defmacro defcustom (var value doc &rest args)
5e72c6b2 110 `(defvar ,var ,value ,doc))))
8c7b4ec8
EZ
111
112;;; Customizations: idlwave-shell group
113
76959b77 114;; General/Misc. customizations
8c7b4ec8 115(defgroup idlwave-shell-general-setup nil
05a1abfc
CD
116 "General setup of the Shell interaction for IDLWAVE/Shell."
117 :prefix "idlwave-shell"
8c7b4ec8
EZ
118 :group 'idlwave)
119
120(defcustom idlwave-shell-prompt-pattern "^ ?IDL> "
13ae1076
JB
121 "*Regexp to match IDL prompt at beginning of a line.
122For example, \"^IDL> \" or \"^WAVE> \".
8c7b4ec8 123The \"^\" means beginning of line.
13ae1076 124This variable is used to initialise `comint-prompt-regexp' in the
8c7b4ec8
EZ
125process buffer.
126
127This is a fine thing to set in your `.emacs' file."
128 :group 'idlwave-shell-general-setup
129 :type 'regexp)
130
131(defcustom idlwave-shell-process-name "idl"
132 "*Name to be associated with the IDL process. The buffer for the
133process output is made by surrounding this name with `*'s."
134 :group 'idlwave-shell-general-setup
135 :type 'string)
136
05a1abfc 137;; (defcustom idlwave-shell-automatic-start...) See idlwave.el
8c7b4ec8 138
8c7b4ec8
EZ
139(defcustom idlwave-shell-use-dedicated-frame nil
140 "*Non-nil means, IDLWAVE should use a special frame to display shell buffer."
141 :group 'idlwave-shell-general-setup
142 :type 'boolean)
143
144(defcustom idlwave-shell-frame-parameters
145 '((height . 30) (unsplittable . nil))
146 "The frame parameters for a dedicated idlwave-shell frame.
147See also `idlwave-shell-use-dedicated-frame'.
148The default makes the frame splittable, so that completion works correctly."
149 :group 'idlwave-shell-general-setup
150 :type '(repeat
151 (cons symbol sexp)))
152
5e72c6b2
S
153(defcustom idlwave-shell-raise-frame t
154 "*Non-nil means, `idlwave-shell' raises the frame showing the shell window."
155 :group 'idlwave-shell-general-setup
156 :type 'boolean)
157
05a1abfc
CD
158(defcustom idlwave-shell-arrows-do-history t
159 "*Non-nil means UP and DOWN arrows move through command history.
160This variable can have 3 values:
161nil Arrows just move the cursor
162t Arrows force the cursor back to the current command line and
163 walk the history
164'cmdline When the cursor is in the current command line, arrows walk the
165 history. Everywhere else in the buffer, arrows move the cursor."
166 :group 'idlwave-shell-general-setup
167 :type '(choice
168 (const :tag "never" nil)
169 (const :tag "everywhere" t)
170 (const :tag "in command line only" cmdline)))
171
5e72c6b2 172;; FIXME: add comint-input-ring-size?
5e72c6b2 173
8c7b4ec8 174(defcustom idlwave-shell-use-toolbar t
05a1abfc 175 "*Non-nil means, use the debugging toolbar in all IDL related buffers.
ca660d22
CD
176Starting the shell will then add the toolbar to all idlwave-mode buffers.
177Exiting the shell will removed everywhere.
8c7b4ec8 178Available on XEmacs and on Emacs 21.x or later.
ca660d22
CD
179At any time you can toggle the display of the toolbar with
180`C-c C-d C-t' (`idlwave-shell-toggle-toolbar')."
8c7b4ec8
EZ
181 :group 'idlwave-shell-general-setup
182 :type 'boolean)
183
184(defcustom idlwave-shell-temp-pro-prefix "/tmp/idltemp"
185 "*The prefix for temporary IDL files used when compiling regions.
186It should be an absolute pathname.
5e72c6b2 187The full temporary file name is obtained by using `make-temp-file'
8c7b4ec8
EZ
188so that the name will be unique among multiple Emacs processes."
189 :group 'idlwave-shell-general-setup
190 :type 'string)
191
192(defvar idlwave-shell-fix-inserted-breaks nil
193 "*OBSOLETE VARIABLE, is no longer used.
194
195The documentation of this variable used to be:
196If non-nil then run `idlwave-shell-remove-breaks' to clean up IDL messages.")
197
198(defcustom idlwave-shell-prefix-key "\C-c\C-d"
199 "*The prefix key for the debugging map `idlwave-shell-mode-prefix-map'.
200This variable must already be set when idlwave-shell.el is loaded.
05a1abfc 201Setting it in the mode-hook is too late."
8c7b4ec8
EZ
202 :group 'idlwave-shell-general-setup
203 :type 'string)
204
205(defcustom idlwave-shell-activate-prefix-keybindings t
206 "Non-nil means, the debug commands will be bound to the prefix key.
207The prefix key itself is given in the option `idlwave-shell-prefix-key'.
208So by default setting a breakpoint will be on C-c C-d C-b."
209 :group 'idlwave-shell-general-setup
210 :type 'boolean)
211
05a1abfc
CD
212;; (defcustom idlwave-shell-debug-modifiers... See idlwave.el
213
214(defvar idlwave-shell-activate-alt-keybindings nil
215 "Obsolete variable. See `idlwave-shell-debug-modifiers'.")
8c7b4ec8
EZ
216
217(defcustom idlwave-shell-use-truename nil
218 "*Non-nil means, use use `file-truename' when looking for buffers.
219If this variable is non-nil, Emacs will use the function `file-truename' to
220resolve symbolic links in the file paths printed by e.g., STOP commands.
221This means, unvisited files will be loaded under their truename.
15e42531 222However, when a file is already visited under a different name, IDLWAVE will
8c7b4ec8
EZ
223reuse that buffer.
224This option was once introduced in order to avoid multiple buffers visiting
225the same file. However, IDLWAVE no longer makes this mistake, so it is safe
226to set this option to nil."
227 :group 'idlwave-shell-general-setup
228 :type 'boolean)
229
76959b77 230(defcustom idlwave-shell-file-name-chars "~/A-Za-z0-9+:_.$#%={}\\-"
8c7b4ec8
EZ
231 "The characters allowed in file names, as a string.
232Used for file name completion. Must not contain `'', `,' and `\"'
233because these are used as separators by IDL."
234 :group 'idlwave-shell-general-setup
235 :type 'string)
236
237(defcustom idlwave-shell-mode-hook '()
238 "*Hook for customising `idlwave-shell-mode'."
239 :group 'idlwave-shell-general-setup
240 :type 'hook)
241
76959b77
S
242(defcustom idlwave-shell-graphics-window-size '(500 400)
243 "Size of IDL graphics windows popped up by special IDLWAVE command.
244The command is `C-c C-d C-f' and accepts as a prefix the window nr.
245A command like `WINDOW,N,xsize=XX,ysize=YY' is sent to IDL."
246 :group 'idlwave-shell-general-setup
247 :type '(list
248 (integer :tag "x size")
249 (integer :tag "y size")))
250
251;; Commands Sent to Shell... etc.
252(defgroup idlwave-shell-command-setup nil
253 "Setup for command parameters of the Shell interaction for IDLWAVE."
254 :prefix "idlwave-shell"
255 :group 'idlwave)
256
257(defcustom idlwave-shell-initial-commands "!more=0"
258 "Initial commands, separated by newlines, to send to IDL.
259This string is sent to the IDL process by `idlwave-shell-mode' which is
260invoked by `idlwave-shell'."
261 :group 'idlwave-shell-command-setup
262 :type 'string)
263
264(defcustom idlwave-shell-save-command-history t
265 "Non-nil means preserve command history between sessions.
266The file `idlwave-shell-command-history-file' is used to save and restore
267the history."
268 :group 'idlwave-shell-command-setup
269 :type 'boolean)
270
271(defcustom idlwave-shell-command-history-file "~/.idlwhist"
272 "The file in which the command history of the idlwave shell is saved.
273In order to change the size of the history, see the variable
274`comint-input-ring-size'.
275The history is only saved if the variable `idlwave-shell-save-command-history'
276is non-nil."
277 :group 'idlwave-shell-command-setup
278 :type 'file)
13ae1076 279
76959b77
S
280(defcustom idlwave-shell-show-commands
281 '(run misc breakpoint)
13ae1076 282 "*A list of command types to show output from in the shell.
76959b77
S
283Possibilities are 'run, 'debug, 'breakpoint, and 'misc . Unlisted
284types are not displayed in the shell. The single type 'everything
285causes all the copious shell traffic to be displayed."
286 :group 'idlwave-shell-command-setup
287 :type '(choice
288 (const everything)
289 (set :tag "Checklist" :greedy t
290 (const :tag "All .run and .compile commands" run)
291 (const :tag "All breakpoint commands" breakpoint)
292 (const :tag "All debug and stepping commands" debug)
293 (const :tag "Return, close, etc. commands" misc))))
5e72c6b2 294
13ae1076 295(defcustom idlwave-shell-examine-alist
5e72c6b2
S
296 '(("Print" . "print,___")
297 ("Help" . "help,___")
298 ("Structure Help" . "help,___,/STRUCTURE")
299 ("Dimensions" . "print,size(___,/DIMENSIONS)")
300 ("Type" . "print,size(___,/TNAME)")
301 ("N_Elements" . "print,n_elements(___)")
302 ("All Size Info" . "help,(__IWsz__=size(___,/STRUCTURE)),/STRUCTURE & print,__IWsz__.DIMENSIONS")
303 ("Ptr Valid" . "print,ptr_valid(___)")
304 ("Widget Valid" . "print,widget_info(___,/VALID)")
305 ("Widget Geometry" . "help,widget_info(___,/GEOMETRY)"))
13ae1076 306 "Alist of special examine commands for popup selection.
5e72c6b2
S
307The keys are used in the selection popup created by
308`idlwave-shell-examine-select', and the corresponding value is sent as
309a command to the shell, with special sequence `___' replaced by the
310expression being examined."
76959b77 311 :group 'idlwave-shell-command-setup
5e72c6b2 312 :type '(repeat
13ae1076 313 (cons
5e72c6b2
S
314 (string :tag "Label ")
315 (string :tag "Command"))))
ca660d22 316
76959b77
S
317(defvar idlwave-shell-print-expression-function nil
318 "*OBSOLETE VARIABLE, is no longer used.")
319
5e72c6b2
S
320(defcustom idlwave-shell-separate-examine-output t
321 "*Non-nil mean, put output of examine commands in their own buffer."
76959b77 322 :group 'idlwave-shell-command-setup
5e72c6b2 323 :type 'boolean)
13ae1076 324
76959b77
S
325(defcustom idlwave-shell-comint-settings
326 '((comint-scroll-to-bottom-on-input . t)
327 (comint-scroll-to-bottom-on-output . t)
328 (comint-scroll-show-maximum-output . nil))
329
330 "Alist of special settings for the comint variables in the IDLWAVE Shell.
331Each entry is a cons cell with the name of a variable and a value.
332The function `idlwave-shell-mode' will make local variables out of each entry.
333Changes to this variable will only be active when the shell buffer is
334newly created."
335 :group 'idlwave-shell-command-setup
336 :type '(repeat
337 (cons variable sexp)))
338
339(defcustom idlwave-shell-query-for-class t
340 "*Non-nil means query the shell for object class on object completions."
341 :group 'idlwave-shell-command-setup
342 :type 'boolean)
343
15e42531
CD
344(defcustom idlwave-shell-use-input-mode-magic nil
345 "*Non-nil means, IDLWAVE should check for input mode spells in output.
346The spells are strings printed by your IDL program and matched
347by the regular expressions in `idlwave-shell-input-mode-spells'.
348When these expressions match, IDLWAVE switches to character input mode and
349back, respectively. See `idlwave-shell-input-mode-spells' for details."
76959b77 350 :group 'idlwave-shell-command-setup
15e42531
CD
351 :type 'boolean)
352
353(defcustom idlwave-shell-input-mode-spells
354 '("^<onechar>$" "^<chars>$" "^</chars>$")
355 "The three regular expressions which match the magic spells for input modes.
356
357When the first regexp matches in the output streem of IDL, IDLWAVE
358prompts for a single character and sends it immediately to IDL, similar
359to the command \\[idlwave-shell-send-char].
360
361When the second regexp matches, IDLWAVE switches to a blocking
362single-character input mode. This is the same mode which can be entered
363manually with \\[idlwave-shell-char-mode-loop].
364This input mode exits when the third regexp matches in the output,
365or when the IDL prompt is encountered.
366
367The variable `idlwave-shell-use-input-mode-magic' must be non-nil to enable
368scanning for these expressions. If the IDL program produces lots of
369output, shell operation may be slowed down.
370
371This mechanism is useful for correct interaction with the IDL function
372GET_KBRD, because in normal operation IDLWAVE only sends \\n terminated
05a1abfc 373strings. Here is some example code which makes use of the default spells.
15e42531
CD
374
375 print,'<chars>' ; Make IDLWAVE switch to character mode
376 REPEAT BEGIN
377 A = GET_KBRD(1)
378 PRINT, BYTE(A)
379 ENDREP UNTIL A EQ 'q'
380 print,'</chars>' ; Make IDLWAVE switch back to line mode
381
382 print,'Quit the program, y or n?'
383 print,'<onechar>' ; Ask IDLWAVE to send one character
384 answer = GET_KBRD(1)
385
386Since the IDLWAVE shell defines the system variable `!IDLWAVE_VERSION',
13ae1076 387you could actually check if you are running under Emacs before printing
15e42531
CD
388the magic strings. Here is a procedure which uses this.
389
390Usage:
391======
392idlwave_char_input ; Make IDLWAVE send one character
393idlwave_char_input,/on ; Start the loop to send characters
394idlwave_char_input,/off ; End the loop to send chracters
395
396
397pro idlwave_char_input,on=on,off=off
398 ;; Test if we are running under Emacs
399 defsysv,'!idlwave_version',exists=running_emacs
400 if running_emacs then begin
401 if keyword_set(on) then print,'<chars>' $
402 else if keyword_set(off) then print,'</chars>' $
403 else print,'<onechar>'
13ae1076 404 endif
15e42531 405end"
76959b77 406 :group 'idlwave-shell-command-setup
15e42531
CD
407 :type '(list
408 (regexp :tag "One-char regexp")
409 (regexp :tag "Char-mode regexp")
410 (regexp :tag "Line-mode regexp")))
411
8c7b4ec8 412
76959b77 413;; Breakpoint Overlays etc
8c7b4ec8 414(defgroup idlwave-shell-highlighting-and-faces nil
05a1abfc
CD
415 "Highlighting and Faces used by the IDLWAVE Shell mode."
416 :prefix "idlwave-shell"
8c7b4ec8
EZ
417 :group 'idlwave)
418
419(defcustom idlwave-shell-mark-stop-line t
420 "*Non-nil means, mark the source code line where IDL is currently stopped.
421Value decides about the method which is used to mark the line. Legal values
422are:
423
424nil Do not mark the line
425'arrow Use the overlay arrow
426'face Use `idlwave-shell-stop-line-face' to highlight the line.
05a1abfc 427t Use what IDLWAVE thinks is best. Will be a face where possible,
8c7b4ec8
EZ
428 otherwise the overlay arrow.
429The overlay-arrow has the disadvantage to hide the first chars of a line.
430Since many people do not have the main block of IDL programs indented,
431a face highlighting may be better.
5e72c6b2 432In Emacs 21, the overlay arrow is displayed in a special area and never
8c7b4ec8
EZ
433hides any code, so setting this to 'arrow on Emacs 21 sounds like a good idea."
434 :group 'idlwave-shell-highlighting-and-faces
435 :type '(choice
436 (const :tag "No marking" nil)
437 (const :tag "Use overlay arrow" arrow)
438 (const :tag "Highlight with face" face)
439 (const :tag "Face or arrow." t)))
440
441(defcustom idlwave-shell-overlay-arrow ">"
442 "*The overlay arrow to display at source lines where execution halts.
443We use a single character by default, since the main block of IDL procedures
444often has no indentation. Where possible, IDLWAVE will use overlays to
445display the stop-lines. The arrow is only used on character-based terminals.
446See also `idlwave-shell-use-overlay-arrow'."
447 :group 'idlwave-shell-highlighting-and-faces
448 :type 'string)
449
450(defcustom idlwave-shell-stop-line-face 'highlight
451 "*The face for `idlwave-shell-stop-line-overlay'.
452Allows you to choose the font, color and other properties for
453line where IDL is stopped. See also `idlwave-shell-mark-stop-line'."
454 :group 'idlwave-shell-highlighting-and-faces
455 :type 'symbol)
456
8c7b4ec8
EZ
457(defcustom idlwave-shell-mark-breakpoints t
458 "*Non-nil means, mark breakpoints in the source files.
459Legal values are:
460nil Do not mark breakpoints.
461'face Highlight line with `idlwave-shell-breakpoint-face'.
462'glyph Red dot at the beginning of line. If the display does not
463 support glyphs, will use 'face instead.
464t Glyph when possible, otherwise face (same effect as 'glyph)."
465 :group 'idlwave-shell-highlighting-and-faces
466 :type '(choice
467 (const :tag "No marking" nil)
468 (const :tag "Highlight with face" face)
469 (const :tag "Display glyph (red dot)" glyph)
470 (const :tag "Glyph or face." t)))
471
472(defvar idlwave-shell-use-breakpoint-glyph t
cff745c3 473 "Obsolete variable. See `idlwave-shell-mark-breakpoints.")
8c7b4ec8
EZ
474
475(defcustom idlwave-shell-breakpoint-face 'idlwave-shell-bp-face
476 "*The face for breakpoint lines in the source code.
477Allows you to choose the font, color and other properties for
478lines which have a breakpoint. See also `idlwave-shell-mark-breakpoints'."
479 :group 'idlwave-shell-highlighting-and-faces
480 :type 'symbol)
481
482(if idlwave-shell-have-new-custom
483 ;; We have the new customize - use it to define a customizable face
484 (defface idlwave-shell-bp-face
485 '((((class color)) (:foreground "Black" :background "Pink"))
486 (t (:underline t)))
487 "Face for highlighting lines-with-breakpoints."
488 :group 'idlwave-shell-highlighting-and-faces)
489 ;; Just copy the underline face to be on the safe side.
490 (copy-face 'underline 'idlwave-shell-bp-face))
491
ca660d22
CD
492(defcustom idlwave-shell-expression-face 'secondary-selection
493 "*The face for `idlwave-shell-expression-overlay'.
494Allows you to choose the font, color and other properties for
495the expression printed by IDL."
496 :group 'idlwave-shell-highlighting-and-faces
497 :type 'symbol)
498
5e72c6b2
S
499(defcustom idlwave-shell-output-face 'secondary-selection
500 "*The face for `idlwave-shell-output-overlay'.
501Allows you to choose the font, color and other properties for
502the expression output by IDL."
503 :group 'idlwave-shell-highlighting-and-faces
504 :type 'symbol)
505
8c7b4ec8
EZ
506;;; End user customization variables
507
508;;; External variables
509(defvar comint-last-input-start)
510(defvar comint-last-input-end)
511
5e72c6b2
S
512(defun idlwave-shell-temp-file (type)
513 "Return a temp file, creating it if necessary.
514
515TYPE is either 'pro or 'rinfo, and idlwave-shell-temp-pro-file or
516idlwave-shell-temp-rinfo-save-file is set (respectively)."
13ae1076 517 (cond
5e72c6b2 518 ((eq type 'rinfo)
13ae1076
JB
519 (or idlwave-shell-temp-rinfo-save-file
520 (setq idlwave-shell-temp-rinfo-save-file
5e72c6b2
S
521 (idlwave-shell-make-temp-file idlwave-shell-temp-pro-prefix))))
522 ((eq type 'pro)
523 (or idlwave-shell-temp-pro-file
13ae1076 524 (setq idlwave-shell-temp-pro-file
5e72c6b2 525 (idlwave-shell-make-temp-file idlwave-shell-temp-pro-prefix))))
13ae1076 526 (t (error "Wrong argument (idlwave-shell-temp-file): %s"
5e72c6b2 527 (symbol-name type)))))
13ae1076 528
8c7b4ec8 529
5e72c6b2
S
530(defun idlwave-shell-make-temp-file (prefix)
531 "Create a temporary file."
532 ; Hard coded make-temp-file for Emacs<21
533 (if (fboundp 'make-temp-file)
534 (make-temp-file prefix)
535 (let (file
536 (temp-file-dir (if (boundp 'temporary-file-directory)
537 temporary-file-directory
538 "/tmp")))
539 (while (condition-case ()
540 (progn
541 (setq file
542 (make-temp-name
543 (expand-file-name prefix temp-file-dir)))
544 (if (featurep 'xemacs)
545 (write-region "" nil file nil 'silent nil)
546 (write-region "" nil file nil 'silent nil 'excl))
547 nil)
548 (file-already-exists t))
549 ;; the file was somehow created by someone else between
550 ;; `make-temp-name' and `write-region', let's try again.
551 nil)
552 file)))
15e42531 553
5e72c6b2
S
554;; Other variables
555(defvar idlwave-shell-temp-pro-file
556 nil
8c7b4ec8
EZ
557 "Absolute pathname for temporary IDL file for compiling regions")
558
15e42531 559(defvar idlwave-shell-temp-rinfo-save-file
5e72c6b2 560 nil
15e42531
CD
561 "Absolute pathname for temporary IDL file save file for routine_info.
562This is used to speed up the reloading of the routine info procedure
563before use by the shell.")
564
76959b77 565(defvar idlwave-shell-dirstack-query "cd,current=___cur & print,___cur"
13ae1076 566 "Command used by `idlwave-shell-resync-dirs' to query IDL for
8c7b4ec8
EZ
567the directory stack.")
568
05a1abfc 569(defvar idlwave-shell-path-query "__pa=expand_path(!path,/array)&for i=0,n_elements(__pa)-1 do print,'PATH:<'+__pa[i]+'>'&print,'SYSDIR:<'+!dir+'>'"
15e42531
CD
570 "The command which gets !PATH and !DIR infor from the shell.")
571
ca660d22 572(defvar idlwave-shell-mode-line-info nil
13ae1076 573 "Additional info displayed in the mode line")
ca660d22 574
8c7b4ec8
EZ
575(defvar idlwave-shell-default-directory nil
576 "The default directory in the idlwave-shell buffer, of outside use.")
577
578(defvar idlwave-shell-last-save-and-action-file nil
579 "The last file which was compiled with `idlwave-shell-save-and-...'.")
580
581;; Highlighting uses overlays. When necessary, require the emulation.
582(if (not (fboundp 'make-overlay))
583 (condition-case nil
584 (require 'overlay)
585 (error nil)))
586
587(defvar idlwave-shell-stop-line-overlay nil
588 "The overlay for where IDL is currently stopped.")
15e42531 589(defvar idlwave-shell-is-stopped nil)
8c7b4ec8
EZ
590(defvar idlwave-shell-expression-overlay nil
591 "The overlay for where IDL is currently stopped.")
5e72c6b2
S
592(defvar idlwave-shell-output-overlay nil
593 "The overlay for the last IDL output.")
594
8c7b4ec8
EZ
595;; If these were already overlays, delete them. This probably means that we
596;; are reloading this file.
597(if (overlayp idlwave-shell-stop-line-overlay)
598 (delete-overlay idlwave-shell-stop-line-overlay))
599(if (overlayp idlwave-shell-expression-overlay)
600 (delete-overlay idlwave-shell-expression-overlay))
5e72c6b2
S
601(if (overlayp idlwave-shell-output-overlay)
602 (delete-overlay idlwave-shell-output-overlay))
603
8c7b4ec8
EZ
604;; Set to nil initially
605(setq idlwave-shell-stop-line-overlay nil
5e72c6b2
S
606 idlwave-shell-expression-overlay nil
607 idlwave-shell-output-overlay nil)
8c7b4ec8
EZ
608
609;; Define the shell stop overlay. When left nil, the arrow will be used.
610(cond
611 ((or (null idlwave-shell-mark-stop-line)
612 (eq idlwave-shell-mark-stop-line 'arrow))
613 ;; Leave the overlay nil
614 nil)
615
616 ((eq idlwave-shell-mark-stop-line 'face)
617 ;; Try to use a face. If not possible, arrow will be used anyway
618 ;; So who can display faces?
619 (when (or (featurep 'xemacs) ; XEmacs can do also ttys
620 (fboundp 'tty-defined-colors) ; Emacs 21 as well
621 window-system) ; Window systems always
622 (progn
623 (setq idlwave-shell-stop-line-overlay (make-overlay 1 1))
13ae1076 624 (overlay-put idlwave-shell-stop-line-overlay
8c7b4ec8
EZ
625 'face idlwave-shell-stop-line-face))))
626
627 (t
628 ;; IDLWAVE may decide. Will use a face on window systems, arrow elsewhere
629 (if window-system
630 (progn
631 (setq idlwave-shell-stop-line-overlay (make-overlay 1 1))
13ae1076 632 (overlay-put idlwave-shell-stop-line-overlay
8c7b4ec8
EZ
633 'face idlwave-shell-stop-line-face)))))
634
5e72c6b2 635;; Now the expression and output overlays
8c7b4ec8
EZ
636(setq idlwave-shell-expression-overlay (make-overlay 1 1))
637(overlay-put idlwave-shell-expression-overlay
638 'face idlwave-shell-expression-face)
5e72c6b2
S
639(setq idlwave-shell-output-overlay (make-overlay 1 1))
640(overlay-put idlwave-shell-output-overlay
641 'face idlwave-shell-output-face)
642
8c7b4ec8
EZ
643(defvar idlwave-shell-bp-query "help,/breakpoints"
644 "Command to obtain list of breakpoints")
645
646(defvar idlwave-shell-command-output nil
647 "String for accumulating current command output.")
648
649(defvar idlwave-shell-post-command-hook nil
650 "Lisp list expression or function to run when an IDL command is finished.
651The current command is finished when the IDL prompt is displayed.
652This is evaluated if it is a list or called with funcall.")
653
5e72c6b2
S
654(defvar idlwave-shell-sentinel-hook nil
655 "Hook run when the idl process exits.")
656
8c7b4ec8
EZ
657(defvar idlwave-shell-hide-output nil
658 "If non-nil the process output is not inserted into the output
659 buffer.")
660
661(defvar idlwave-shell-accumulation nil
662 "Accumulate last line of output.")
663
664(defvar idlwave-shell-command-line-to-execute nil)
665(defvar idlwave-shell-cleanup-hook nil
666 "List of functions to do cleanup when the shell exits.")
667
668(defvar idlwave-shell-pending-commands nil
669 "List of commands to be sent to IDL.
670Each element of the list is list of \(CMD PCMD HIDE\), where CMD is a
671string to be sent to IDL and PCMD is a post-command to be placed on
672`idlwave-shell-post-command-hook'. If HIDE is non-nil, hide the output
673from command CMD. PCMD and HIDE are optional.")
674
675(defun idlwave-shell-buffer ()
676 "Name of buffer associated with IDL process.
677The name of the buffer is made by surrounding `idlwave-shell-process-name
678with `*'s."
679 (concat "*" idlwave-shell-process-name "*"))
680
681(defvar idlwave-shell-ready nil
682 "If non-nil can send next command to IDL process.")
683
76959b77
S
684(defvar idlwave-shell-wait-for-output nil
685 "Whether to wait for output to accumulate.")
686
8c7b4ec8
EZ
687;;; The following are the types of messages we attempt to catch to
688;;; resync our idea of where IDL execution currently is.
13ae1076 689;;;
8c7b4ec8
EZ
690
691(defvar idlwave-shell-halt-frame nil
692 "The frame associated with halt/breakpoint messages.")
693
694(defvar idlwave-shell-step-frame nil
695 "The frame associated with step messages.")
696
697(defvar idlwave-shell-trace-frame nil
698 "The frame associated with trace messages.")
699
700(defconst idlwave-shell-halt-messages
701 '("^% Execution halted at"
702 "^% Interrupted at:"
703 "^% Stepped to:"
704 "^% At "
705 "^% Stop encountered:"
706 )
707 "*A list of regular expressions matching IDL messages.
708These are the messages containing file and line information where
709IDL is currently stopped.")
710
711(defconst idlwave-shell-halt-messages-re
712 (mapconcat 'identity idlwave-shell-halt-messages "\\|")
713 "The regular expression computed from idlwave-shell-halt-messages")
714
715(defconst idlwave-shell-trace-messages
716 '("^% At " ;; First line of a trace message
717 )
718 "*A list of regular expressions matching IDL trace messages.
719These are the messages containing file and line information where
720IDL will begin looking for the next statement to execute.")
721
722(defconst idlwave-shell-step-messages
723 '("^% Stepped to:"
724 )
725 "*A list of regular expressions matching stepped execution messages.
726These are IDL messages containing file and line information where
727IDL has currently stepped.")
728
729(defvar idlwave-shell-break-message "^% Breakpoint at:"
730 "*Regular expression matching an IDL breakpoint message line.")
731
732
733(defvar idlwave-shell-bp-alist)
734;(defvar idlwave-shell-post-command-output)
735(defvar idlwave-shell-sources-alist)
736(defvar idlwave-shell-menu-def)
737(defvar idlwave-shell-mode-menu)
738(defvar idlwave-shell-initial-commands)
739(defvar idlwave-shell-syntax-error)
740(defvar idlwave-shell-other-error)
741(defvar idlwave-shell-error-buffer)
742(defvar idlwave-shell-error-last)
743(defvar idlwave-shell-bp-buffer)
744(defvar idlwave-shell-sources-query)
745(defvar idlwave-shell-mode-map)
ca660d22 746(defvar idlwave-shell-calling-stack-index)
8c7b4ec8
EZ
747
748(defun idlwave-shell-mode ()
749 "Major mode for interacting with an inferior IDL process.
750
7511. Shell Interaction
752 -----------------
753 RET after the end of the process' output sends the text from the
754 end of process to the end of the current line. RET before end of
755 process output copies the current line (except for the prompt) to the
756 end of the buffer.
757
758 Command history, searching of previous commands, command line
759 editing are available via the comint-mode key bindings, by default
05a1abfc
CD
760 mostly on the key `C-c'. Command history is also available with
761 the arrow keys UP and DOWN.
8c7b4ec8
EZ
762
7632. Completion
764 ----------
15e42531
CD
765 TAB and M-TAB do completion of IDL routines, classes and keywords -
766 similar to M-TAB in `idlwave-mode'. In executive commands and
767 strings, it completes file names. Abbreviations are also expanded
768 like in `idlwave-mode'.
8c7b4ec8
EZ
769
7703. Routine Info
771 ------------
772 `\\[idlwave-routine-info]' displays information about an IDL routine near point,
773 just like in `idlwave-mode'. The module used is the one at point or
774 the one whose argument list is being edited.
13ae1076 775 To update IDLWAVE's knowledge about compiled or edited modules, use
8c7b4ec8
EZ
776 \\[idlwave-update-routine-info].
777 \\[idlwave-find-module] find the source of a module.
778 \\[idlwave-resolve] tells IDL to compile an unresolved module.
15e42531
CD
779 \\[idlwave-context-help] shows the online help on the item at
780 point, if online help has been installed.
13ae1076 781
8c7b4ec8
EZ
782
7834. Debugging
784 ---------
785 A complete set of commands for compiling and debugging IDL programs
13ae1076 786 is available from the menu. Also keybindings starting with a
8c7b4ec8
EZ
787 `C-c C-d' prefix are available for most commands in the *idl* buffer
788 and also in source buffers. The best place to learn about the
789 keybindings is again the menu.
790
791 On Emacs versions where this is possible, a debugging toolbar is
792 installed.
793
794 When IDL is halted in the middle of a procedure, the corresponding
795 line of that procedure file is displayed with an overlay in another
796 window. Breakpoints are also highlighted in the source.
797
798 \\[idlwave-shell-resync-dirs] queries IDL in order to change Emacs current directory
799 to correspond to the IDL process current directory.
800
8015. Hooks
802 -----
803 Turning on `idlwave-shell-mode' runs `comint-mode-hook' and
804 `idlwave-shell-mode-hook' (in that order).
805
8066. Documentation and Customization
807 -------------------------------
808 Info documentation for this package is available. Use \\[idlwave-info]
809 to display (complain to your sysadmin if that does not work).
810 For Postscript and HTML versions of the documentation, check IDLWAVE's
5e72c6b2 811 homepage at `http://idlwave.org'.
8c7b4ec8
EZ
812 IDLWAVE has customize support - see the group `idlwave'.
813
8147. Keybindings
815 -----------
816\\{idlwave-shell-mode-map}"
817
818 (interactive)
05a1abfc
CD
819 ;; We don't do `kill-all-local-variables' here, because this is done by
820 ;; comint - idlwave-shell-mode only add on top of that.
8c7b4ec8
EZ
821 (setq comint-prompt-regexp idlwave-shell-prompt-pattern)
822 (setq comint-process-echoes t)
823 ;; Can not use history expansion because "!" is used for system variables.
824 (setq comint-input-autoexpand nil)
5e72c6b2 825; (setq comint-input-ring-size 64)
8c7b4ec8
EZ
826 (make-local-variable 'comint-completion-addsuffix)
827 (set (make-local-variable 'completion-ignore-case) t)
828 (setq comint-completion-addsuffix '("/" . ""))
829 (setq comint-input-ignoredups t)
830 (setq major-mode 'idlwave-shell-mode)
831 (setq mode-name "IDL-Shell")
ca660d22
CD
832 (setq idlwave-shell-mode-line-info nil)
833 (setq mode-line-format
834 '(""
835 mode-line-modified
836 mode-line-buffer-identification
837 " "
838 global-mode-string
839 " %[("
840 mode-name
841 mode-line-process
842 minor-mode-alist
843 "%n"
844 ")%]-"
845 idlwave-shell-mode-line-info
846 "---"
847 (line-number-mode "L%l--")
848 (column-number-mode "C%c--")
849 (-3 . "%p")
850 "-%-"))
8c7b4ec8
EZ
851 ;; (make-local-variable 'idlwave-shell-bp-alist)
852 (setq idlwave-shell-halt-frame nil
853 idlwave-shell-trace-frame nil
854 idlwave-shell-command-output nil
855 idlwave-shell-step-frame nil)
856 (idlwave-shell-display-line nil)
ca660d22 857 (setq idlwave-shell-calling-stack-index 0)
15e42531 858
76959b77
S
859 (when idlwave-shell-query-for-class
860 (add-to-list (make-local-variable 'idlwave-determine-class-special)
861 'idlwave-shell-get-object-class)
862 (setq idlwave-store-inquired-class t))
863
8c7b4ec8
EZ
864 ;; Make sure comint-last-input-end does not go to beginning of
865 ;; buffer (in case there were other processes already in this buffer).
866 (set-marker comint-last-input-end (point))
15e42531 867 (setq idlwave-idlwave_routine_info-compiled nil)
8c7b4ec8 868 (setq idlwave-shell-ready nil)
76959b77 869 (setq idlwave-shell-wait-for-output nil)
8c7b4ec8
EZ
870 (setq idlwave-shell-bp-alist nil)
871 (idlwave-shell-update-bp-overlays) ; Throw away old overlays
872 (setq idlwave-shell-sources-alist nil)
873 (setq idlwave-shell-default-directory default-directory)
15e42531 874 (setq idlwave-shell-hide-output nil)
5e72c6b2
S
875
876 ;; NB: `make-local-hook' needed for older/alternative Emacs compatibility
877 (make-local-hook 'kill-buffer-hook)
8c7b4ec8
EZ
878 (add-hook 'kill-buffer-hook 'idlwave-shell-kill-shell-buffer-confirm
879 nil 'local)
15e42531
CD
880 (add-hook 'kill-buffer-hook 'idlwave-shell-delete-temp-files nil 'local)
881 (add-hook 'kill-emacs-hook 'idlwave-shell-delete-temp-files)
8c7b4ec8
EZ
882 (use-local-map idlwave-shell-mode-map)
883 (easy-menu-add idlwave-shell-mode-menu idlwave-shell-mode-map)
15e42531 884
5e72c6b2
S
885 ;; Set the optional comint variables
886 (when idlwave-shell-comint-settings
887 (let ((list idlwave-shell-comint-settings) entry)
888 (while (setq entry (pop list))
889 (set (make-local-variable (car entry)) (cdr entry)))))
05a1abfc 890
15e42531
CD
891 ;; IDLWAVE syntax, and turn on abbreviations
892 (setq local-abbrev-table idlwave-mode-abbrev-table)
893 (set-syntax-table idlwave-mode-syntax-table)
05a1abfc 894 (set (make-local-variable 'comment-start) ";")
15e42531 895 (setq abbrev-mode t)
5e72c6b2
S
896
897 ;; NB: `make-local-hook' needed for older/alternative Emacs compatibility
898 (make-local-hook 'post-command-hook)
15e42531
CD
899 (add-hook 'post-command-hook 'idlwave-command-hook nil t)
900
5e72c6b2
S
901 ;; Read the command history?
902 (when (and idlwave-shell-save-command-history
903 (stringp idlwave-shell-command-history-file))
904 (set (make-local-variable 'comint-input-ring-file-name)
905 idlwave-shell-command-history-file)
906 (if (file-regular-p idlwave-shell-command-history-file)
907 (comint-read-input-ring)))
908
15e42531 909 ;; Run the hooks.
8c7b4ec8
EZ
910 (run-hooks 'idlwave-shell-mode-hook)
911 (idlwave-shell-send-command idlwave-shell-initial-commands nil 'hide)
15e42531 912 ;; Define a system variable which knows the version of IDLWAVE
13ae1076 913 (idlwave-shell-send-command
15e42531
CD
914 (format "defsysv,'!idlwave_version','%s',1" idlwave-mode-version)
915 nil 'hide)
916 (if (and (not idlwave-path-alist)
917 (not idlwave-sys-dir))
918 (idlwave-shell-send-command idlwave-shell-path-query
919 'idlwave-shell-get-path-info
920 'hide)))
921
922(defun idlwave-shell-get-path-info ()
923 (let* ((rpl (idlwave-shell-path-filter))
924 (sysdir (car rpl))
925 (dirs (cdr rpl)))
926 (setq idlwave-sys-dir sysdir)
927 (setq idlwave-path-alist (mapcar (lambda(x) (cons x nil))
928 dirs))))
8c7b4ec8
EZ
929
930(if (not (fboundp 'idl-shell))
931 (fset 'idl-shell 'idlwave-shell))
932
933(defvar idlwave-shell-idl-wframe nil
934 "Frame for displaying the idl shell window.")
935(defvar idlwave-shell-display-wframe nil
936 "Frame for displaying the idl source files.")
937
8c7b4ec8 938(defvar idlwave-shell-calling-stack-index 0)
ca660d22 939(defvar idlwave-shell-calling-stack-routine nil)
8c7b4ec8
EZ
940
941(defun idlwave-shell-source-frame ()
942 "Return the frame to be used for source display."
943 (if idlwave-shell-use-dedicated-frame
944 ;; We want separate frames for source and shell
945 (if (frame-live-p idlwave-shell-display-wframe)
946 ;; The frame exists, so we use it.
947 idlwave-shell-display-wframe
948 ;; The frame does not exist. We use the current frame.
5e72c6b2
S
949 ;; However, if the current is the shell frame, we make a new frame,
950 ;; or recycle the first existing visible frame
8c7b4ec8
EZ
951 (setq idlwave-shell-display-wframe
952 (if (eq (selected-frame) idlwave-shell-idl-wframe)
5e72c6b2
S
953 (or
954 (let ((flist (visible-frame-list))
955 (frame (selected-frame)))
956 (catch 'exit
957 (while flist
13ae1076
JB
958 (if (not (eq (car flist)
959 idlwave-shell-idl-wframe))
5e72c6b2
S
960 (throw 'exit (car flist))
961 (setq flist (cdr flist))))))
962 (make-frame))
8c7b4ec8
EZ
963 (selected-frame))))))
964
965(defun idlwave-shell-shell-frame ()
966 "Return the frame to be used for the shell buffer."
967 (if idlwave-shell-use-dedicated-frame
968 ;; We want a dedicated frame
969 (if (frame-live-p idlwave-shell-idl-wframe)
970 ;; It does exist, so we use it.
971 idlwave-shell-idl-wframe
972 ;; It does not exist. Check if we have a source frame.
973 (if (not (frame-live-p idlwave-shell-display-wframe))
974 ;; We do not have a source frame, so we use this one.
975 (setq idlwave-shell-display-wframe (selected-frame)))
976 ;; Return a new frame
13ae1076 977 (setq idlwave-shell-idl-wframe
8c7b4ec8 978 (make-frame idlwave-shell-frame-parameters)))))
13ae1076 979
8c7b4ec8 980;;;###autoload
5e72c6b2 981(defun idlwave-shell (&optional arg quick)
8c7b4ec8
EZ
982 "Run an inferior IDL, with I/O through buffer `(idlwave-shell-buffer)'.
983If buffer exists but shell process is not running, start new IDL.
984If buffer exists and shell process is running, just switch to the buffer.
985
986When called with a prefix ARG, or when `idlwave-shell-use-dedicated-frame'
987is non-nil, the shell buffer and the source buffers will be in
988separate frames.
989
5e72c6b2
S
990The command to run comes from variable `idlwave-shell-explicit-file-name',
991with options taken from `idlwave-shell-command-line-options'.
8c7b4ec8
EZ
992
993The buffer is put in `idlwave-shell-mode', providing commands for sending
994input and controlling the IDL job. See help on `idlwave-shell-mode'.
995See also the variable `idlwave-shell-prompt-pattern'.
996
997\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
998 (interactive "P")
5e72c6b2
S
999 (if (eq arg 'quick)
1000 (progn
1001 (let ((idlwave-shell-use-dedicated-frame nil))
1002 (idlwave-shell nil)
1003 (delete-other-windows))
1004 (and idlwave-shell-use-dedicated-frame
1005 (setq idlwave-shell-idl-wframe (selected-frame)))
13ae1076 1006 (add-hook 'idlwave-shell-sentinel-hook
5e72c6b2
S
1007 'save-buffers-kill-emacs t))
1008
1009 ;; A non-nil arg means, we want a dedicated frame. This will last
1010 ;; for the current editing session.
1011 (if arg (setq idlwave-shell-use-dedicated-frame t))
1012 (if (equal arg '(16)) (setq idlwave-shell-use-dedicated-frame nil))
13ae1076 1013
5e72c6b2
S
1014 ;; Check if the process still exists. If not, create it.
1015 (unless (comint-check-proc (idlwave-shell-buffer))
1016 (let* ((prg (or idlwave-shell-explicit-file-name "idl"))
1017 (buf (apply 'make-comint
1018 idlwave-shell-process-name prg nil
1019 (if (stringp idlwave-shell-command-line-options)
1020 (idlwave-split-string
1021 idlwave-shell-command-line-options)
1022 idlwave-shell-command-line-options)))
1023 (process (get-buffer-process buf)))
1024 (setq idlwave-idlwave_routine_info-compiled nil)
1025 (set-process-filter process 'idlwave-shell-filter)
1026 (set-process-sentinel process 'idlwave-shell-sentinel)
1027 (set-buffer buf)
1028 (idlwave-shell-mode)))
1029 (let ((window (idlwave-display-buffer (idlwave-shell-buffer) nil
1030 (idlwave-shell-shell-frame)))
1031 (current-window (selected-window)))
1032 (select-window window)
1033 (goto-char (point-max))
1034 (select-window current-window)
1035 (if idlwave-shell-ready
1036 (raise-frame (window-frame window)))
1037 (if (eq (selected-frame) (window-frame window))
1038 (select-window window))
1039 )))
8c7b4ec8
EZ
1040
1041(defun idlwave-shell-recenter-shell-window (&optional arg)
1042 "Run `idlwave-shell', but make sure the current window stays selected."
1043 (interactive "P")
1044 (let ((window (selected-window)))
1045 (idlwave-shell arg)
1046 (select-window window)))
1047
76959b77
S
1048(defun idlwave-shell-hide-p (type)
1049 "Whether to hide this type of command.
1050Return either nil or 'hide."
1051 (if (listp idlwave-shell-show-commands)
1052 (if (not (memq type idlwave-shell-show-commands)) 'hide)))
1053
8c7b4ec8
EZ
1054(defun idlwave-shell-send-command (&optional cmd pcmd hide preempt)
1055 "Send a command to IDL process.
1056
76959b77
S
1057\(CMD PCMD HIDE\) are placed at the end of
1058` idlwave-shell-pending-commands'. If IDL is ready the first command,
1059CMD, in `idlwave-shell-pending-commands' is sent to the IDL process.
1060If optional second argument PCMD is non-nil it will be placed on
1061`idlwave-shell-post-command-hook' when CMD is executed. If the
1062optional third argument HIDE is non-nil, then hide output from CMD.
8c7b4ec8 1063If optional fourth argument PREEMPT is non-nil CMD is put at front of
76959b77
S
1064`idlwave-shell-pending-commands'. If PREEMPT is 'wait, wait for all
1065output to complete and the next prompt to arrive before returning
1066\(useful if you need an answer now\). IDL is considered ready if the
1067prompt is present and if `idlwave-shell-ready' is non-nil."
1068
1069; (setq hide nil) ; FIXME: turn this on for debugging only
13ae1076 1070; (if (null cmd)
76959b77 1071; (progn
13ae1076 1072; (message "SENDING Pending commands: %s"
76959b77
S
1073; (prin1-to-string idlwave-shell-pending-commands)))
1074; (message "SENDING %s|||%s" cmd pcmd))
13ae1076 1075 (if (and (symbolp idlwave-shell-show-commands)
76959b77
S
1076 (eq idlwave-shell-show-commands 'everything))
1077 (setq hide nil))
1078 (let ((save-buffer (current-buffer))
1079 buf proc)
8c7b4ec8
EZ
1080 ;; Get or make the buffer and its process
1081 (if (or (not (setq buf (get-buffer (idlwave-shell-buffer))))
1082 (not (setq proc (get-buffer-process buf))))
1083 (if (not idlwave-shell-automatic-start)
1084 (error
1085 (substitute-command-keys
1086 "You need to first start an IDL shell with \\[idlwave-shell]"))
1087 (idlwave-shell-recenter-shell-window)
1088 (setq buf (get-buffer (idlwave-shell-buffer)))
1089 (if (or (not (setq buf (get-buffer (idlwave-shell-buffer))))
1090 (not (setq proc (get-buffer-process buf))))
1091 ;; Still nothing
1092 (error "Problem with autostarting IDL shell"))))
76959b77 1093 (when (or cmd idlwave-shell-pending-commands)
8c7b4ec8 1094 (set-buffer buf)
8c7b4ec8
EZ
1095 ;; To make this easy, always push CMD onto pending commands
1096 (if cmd
76959b77
S
1097 (setq idlwave-shell-pending-commands
1098 (if preempt
1099 ;; Put at front.
1100 (append (list (list cmd pcmd hide))
1101 idlwave-shell-pending-commands)
1102 ;; Put at end.
13ae1076 1103 (append idlwave-shell-pending-commands
76959b77 1104 (list (list cmd pcmd hide))))))
8c7b4ec8 1105 ;; Check if IDL ready
76959b77
S
1106 (let ((save-point (point-marker)))
1107 (goto-char (process-mark proc))
1108 (if (and idlwave-shell-ready
1109 ;; Check for IDL prompt
1110 (prog2
1111 (forward-line 0)
1112 ;; (beginning-of-line) ; Changed for Emacs 21
1113 (looking-at idlwave-shell-prompt-pattern)
1114 (goto-char (process-mark proc))))
1115 ;; IDL ready for command, execute it
1116 (let* ((lcmd (car idlwave-shell-pending-commands))
1117 (cmd (car lcmd))
1118 (pcmd (nth 1 lcmd))
1119 (hide (nth 2 lcmd)))
1120 ;; If this is an executive command, reset the stack pointer
1121 (if (eq (string-to-char cmd) ?.)
1122 (setq idlwave-shell-calling-stack-index 0))
1123 ;; Set post-command
1124 (setq idlwave-shell-post-command-hook pcmd)
1125 ;; Output hiding
1126 (setq idlwave-shell-hide-output hide)
1127 ;; Pop command
1128 (setq idlwave-shell-pending-commands
1129 (cdr idlwave-shell-pending-commands))
1130 ;; Send command for execution
1131 (set-marker comint-last-input-start (point))
1132 (set-marker comint-last-input-end (point))
1133 (comint-simple-send proc cmd)
1134 (setq idlwave-shell-ready nil)
1135 (when (equal preempt 'wait) ; Get all the output at once
1136 (setq idlwave-shell-wait-for-output t)
1137 (accept-process-output proc))))
1138 (goto-char save-point))
1139 (set-buffer save-buffer))))
8c7b4ec8 1140
15e42531
CD
1141(defun idlwave-shell-send-char (c &optional no-error)
1142 "Send one character to the shell, without a newline."
1143 (interactive "cChar to send to IDL: ")
1144 (let ((errf (if (interactive-p) 'error 'message))
1145 buf proc)
1146 (if (or (not (setq buf (get-buffer (idlwave-shell-buffer))))
1147 (not (setq proc (get-buffer-process buf))))
1148 (funcall errf "Shell is not running"))
13ae1076 1149 (if (equal c ?\C-g)
15e42531
CD
1150 (funcall errf "Abort")
1151 (comint-send-string proc (char-to-string c)))))
1152
1153(defvar idlwave-shell-char-mode-active)
1154(defun idlwave-shell-input-mode-magic (string)
1155 "Check STRING for magic words and toggle character input mode.
1156See also the variable `idlwave-shell-input-mode-spells'."
1157 (cond
1158 ((string-match (car idlwave-shell-input-mode-spells) string)
1159 (call-interactively 'idlwave-shell-send-char))
1160 ((and (boundp 'idlwave-shell-char-mode-active)
1161 (string-match (nth 2 idlwave-shell-input-mode-spells) string))
1162 (setq idlwave-shell-char-mode-active 'exit))
1163 ((string-match (nth 1 idlwave-shell-input-mode-spells) string)
1164 ;; Set a timer which will soon start the character loop
1165 (if (fboundp 'start-itimer)
1166 (start-itimer "IDLWAVE Char Mode" 'idlwave-shell-char-mode-loop 0.5
1167 nil nil t 'no-error)
1168 (run-at-time 0.5 nil 'idlwave-shell-char-mode-loop 'no-error)))))
1169
1170(defvar keyboard-quit)
1171(defun idlwave-shell-char-mode-loop (&optional no-error)
1172 "Enter a loop which accepts single characters and sends them to IDL.
1173Characters are sent one by one, without newlines. The loop is blocking
1174and intercepts all input events to Emacs. You can use this command
1175to interact with the IDL command GET_KBRD.
1176The loop can be aborted by typing `C-g'. The loop also exits automatically
1177when the IDL prompt gets displayed again after the current IDL command."
1178 (interactive)
1179
1180 ;; First check if there is a shell waiting for input
1181 (let ((idlwave-shell-char-mode-active t)
1182 (errf (if no-error 'message 'error))
1183 buf proc c)
1184 (if (or (not (setq buf (get-buffer (idlwave-shell-buffer))))
1185 (not (setq proc (get-buffer-process buf))))
1186 (funcall errf "Shell is not running"))
1187 (if idlwave-shell-ready
1188 (funcall errf "No IDL program seems to be waiting for input"))
1189
13ae1076 1190 ;; OK, start the loop
15e42531
CD
1191 (message "Character mode on: Sending single chars (`C-g' to exit)")
1192 (message
1193 (catch 'exit
1194 (while t
1195 ;; Wait for input
1196 ;; FIXME: Is it too dangerous to inhibit quit here?
1197 (let ((inhibit-quit t))
1198 ;; We wait and check frequently if we should abort
1199 (while (sit-for 0.3)
1200 (and idlwave-shell-ready
1201 (throw 'exit "Character mode off (prompt displayed)"))
1202 (and (eq idlwave-shell-char-mode-active 'exit)
1203 (throw 'exit "Character mode off (closing spell incantation)")))
1204 ;; Interpret input as a character - ignore non-char input
1205 (condition-case nil
1206 (setq c (read-char))
05a1abfc 1207 (error (ding) (throw 'exit "Character mode off")))
15e42531
CD
1208 (cond
1209 ((null c) ; Non-char event: ignore
1210 (ding))
1211 ((equal c ?\C-g) ; Abort the loop
1212 (setq keyboard-quit nil)
1213 (ding)
1214 (throw 'exit "Character mode off (keyboard quit)"))
1215 (t ; Send the character and continue the loop
1216 (comint-send-string proc (char-to-string c))))
1217 (and (eq idlwave-shell-char-mode-active 'exit)
1218 (throw 'exit "Single char loop exited"))))))))
1219
76959b77 1220(defun idlwave-shell-move-or-history (up &optional arg)
05a1abfc 1221 "When in last line of process buffer, do `comint-previous-input'.
76959b77
S
1222Otherwise just move the line. Move down unless UP is non-nil."
1223 (let* ((proc-pos (marker-position
1224 (process-mark (get-buffer-process (current-buffer)))))
1225 (arg (or arg 1))
1226 (arg (if up arg (- arg))))
1227 (if (eq t idlwave-shell-arrows-do-history) (goto-char proc-pos))
1228 (if (and idlwave-shell-arrows-do-history
1229 (>= (1+ (save-excursion (end-of-line) (point))) proc-pos))
1230 (progn
1231 (goto-char proc-pos)
1232 (and (not (eolp)) (kill-line nil))
1233 (comint-previous-input arg))
1234 (previous-line arg))))
1235
1236(defun idlwave-shell-up-or-history (&optional arg)
1237"When in last line of process buffer, move to previous input.
1238 Otherwise just go up one line."
05a1abfc 1239 (interactive "p")
76959b77 1240 (idlwave-shell-move-or-history t arg))
05a1abfc
CD
1241
1242(defun idlwave-shell-down-or-history (&optional arg)
76959b77
S
1243"When in last line of process buffer, move to next input.
1244 Otherwise just go down one line."
05a1abfc 1245 (interactive "p")
76959b77 1246 (idlwave-shell-move-or-history nil arg))
8c7b4ec8 1247
76959b77
S
1248;; Newer versions of comint.el changed the name of comint-filter to
1249;; comint-output-filter.
8c7b4ec8
EZ
1250(defun idlwave-shell-comint-filter (process string) nil)
1251(if (fboundp 'comint-output-filter)
1252 (fset 'idlwave-shell-comint-filter (symbol-function 'comint-output-filter))
1253 (fset 'idlwave-shell-comint-filter (symbol-function 'comint-filter)))
1254
1255(defun idlwave-shell-is-running ()
1256 "Return t if the shell process is running."
1257 (eq (process-status idlwave-shell-process-name) 'run))
1258
15e42531
CD
1259(defvar idlwave-shell-hidden-output-buffer " *idlwave-shell-hidden-output*"
1260 "Buffer containing hidden output from IDL commands.")
13ae1076 1261
8c7b4ec8
EZ
1262(defun idlwave-shell-filter (proc string)
1263 "Replace Carriage returns in output. Watch for prompt.
1264When the IDL prompt is received executes `idlwave-shell-post-command-hook'
1265and then calls `idlwave-shell-send-command' for any pending commands."
1266 ;; We no longer do the cleanup here - this is done by the process sentinel
1267 (when (eq (process-status idlwave-shell-process-name) 'run)
1268 ;; OK, process is still running, so we can use it.
5e72c6b2 1269 (let ((data (match-data)) p)
8c7b4ec8
EZ
1270 (unwind-protect
1271 (progn
1272 ;; May change the original match data.
5e72c6b2
S
1273 (while (setq p (string-match "\C-M" string))
1274 (aset string p ?\ ))
1275
8c7b4ec8
EZ
1276 ;;
1277 ;; Keep output
1278
1279; Should not keep output because the concat is costly. If hidden put
1280; the output in a hide-buffer. Then when the output is needed in post
1281; processing can access either the hide buffer or the idlwave-shell
1282; buffer. Then watching for the prompt is easier. Furthermore, if it
1283; is hidden and there is no post command, could throw away output.
1284; (setq idlwave-shell-command-output
1285; (concat idlwave-shell-command-output string))
1286 ;; Insert the string. Do this before getting the
13ae1076 1287 ;; state.
5e72c6b2
S
1288 (while (setq p (string-match "\C-G" string))
1289 (ding)
1290 (aset string p ?\C-j ))
8c7b4ec8
EZ
1291 (if idlwave-shell-hide-output
1292 (save-excursion
1293 (set-buffer
15e42531 1294 (get-buffer-create idlwave-shell-hidden-output-buffer))
8c7b4ec8
EZ
1295 (goto-char (point-max))
1296 (insert string))
76959b77 1297 (idlwave-shell-comint-filter proc string))
5e72c6b2 1298 ;; Watch for magic - need to accumulate the current line
8c7b4ec8
EZ
1299 ;; since it may not be sent all at once.
1300 (if (string-match "\n" string)
15e42531
CD
1301 (progn
1302 (if idlwave-shell-use-input-mode-magic
1303 (idlwave-shell-input-mode-magic
1304 (concat idlwave-shell-accumulation string)))
1305 (setq idlwave-shell-accumulation
13ae1076 1306 (substring string
15e42531
CD
1307 (progn (string-match "\\(.*\n\\)*" string)
1308 (match-end 0)))))
8c7b4ec8
EZ
1309 (setq idlwave-shell-accumulation
1310 (concat idlwave-shell-accumulation string)))
13ae1076
JB
1311
1312
5e72c6b2
S
1313;;; Test/Debug code
1314; (save-excursion (set-buffer
1315; (get-buffer-create "*idlwave-shell-output*"))
1316; (goto-char (point-max))
1317; (insert "\nSTRING===>\n" string "\n<====\n"))
13ae1076 1318
76959b77
S
1319 ;; Check for prompt in current accumulating output
1320 (if (setq idlwave-shell-ready
1321 (string-match idlwave-shell-prompt-pattern
1322 idlwave-shell-accumulation))
1323 (progn
1324 (if idlwave-shell-hide-output
1325 (save-excursion
1326 (set-buffer idlwave-shell-hidden-output-buffer)
1327 (goto-char (point-max))
1328 (re-search-backward idlwave-shell-prompt-pattern nil t)
5e72c6b2 1329 (goto-char (match-end 0))
76959b77
S
1330 (setq idlwave-shell-command-output
1331 (buffer-substring (point-min) (point)))
13ae1076 1332
76959b77 1333;;; Test/Debug
5e72c6b2
S
1334; (save-excursion (set-buffer
1335; (get-buffer-create "*idlwave-shell-output*"))
1336; (goto-char (point-max))
1337; (insert "\nOUPUT===>\n" idlwave-shell-command-output "\n<===\n"))
13ae1076 1338
76959b77 1339 (delete-region (point-min) (point)))
8c7b4ec8 1340 (setq idlwave-shell-command-output
76959b77
S
1341 (with-current-buffer (process-buffer proc)
1342 (buffer-substring
1343 (save-excursion
1344 (goto-char (process-mark proc))
1345 (beginning-of-line nil)
1346 (point))
1347 comint-last-input-end))))
1348
8c7b4ec8
EZ
1349 ;; Scan for state and do post command - bracket them
1350 ;; with idlwave-shell-ready=nil since they
1351 ;; may call idlwave-shell-send-command.
1352 (let ((idlwave-shell-ready nil))
1353 (idlwave-shell-scan-for-state)
1354 ;; Unset idlwave-shell-ready to prevent sending
1355 ;; commands to IDL while running hook.
1356 (if (listp idlwave-shell-post-command-hook)
1357 (eval idlwave-shell-post-command-hook)
1358 (funcall idlwave-shell-post-command-hook))
1359 ;; Reset to default state for next command.
1360 ;; Also we do not want to find this prompt again.
1361 (setq idlwave-shell-accumulation nil
1362 idlwave-shell-command-output nil
1363 idlwave-shell-post-command-hook nil
76959b77
S
1364 idlwave-shell-hide-output nil
1365 idlwave-shell-wait-for-output nil))
8c7b4ec8
EZ
1366 ;; Done with post command. Do pending command if
1367 ;; any.
76959b77
S
1368 (idlwave-shell-send-command))
1369 ;; We didn't get the prompt yet... maybe accept more output
1370 (when idlwave-shell-wait-for-output
1371;;; Test/Debug code
1372; (save-excursion (set-buffer
1373; (get-buffer-create "*idlwave-shell-output*"))
1374; (goto-char (point-max))
1375; (insert "\n<=== WAITING ON OUTPUT ==>\n"))
1376 (accept-process-output proc nil 100))))
8c7b4ec8
EZ
1377 (store-match-data data)))))
1378
1379(defun idlwave-shell-sentinel (process event)
1380 "The sentinel function for the IDLWAVE shell process."
1381 (let* ((buf (idlwave-shell-buffer))
1382 (win (get-buffer-window buf)))
1383 (when (get-buffer buf)
1384 (save-excursion
1385 (set-buffer (idlwave-shell-buffer))
1386 (goto-char (point-max))
5e72c6b2
S
1387 (insert (format "\n\n Process %s %s" process event))
1388 (if (and idlwave-shell-save-command-history
1389 (stringp idlwave-shell-command-history-file))
1390 (condition-case nil
1391 (comint-write-input-ring)
1392 (error nil)))))
13ae1076 1393
8c7b4ec8
EZ
1394 (when (and (> (length (frame-list)) 1)
1395 (frame-live-p idlwave-shell-idl-wframe))
1396 (delete-frame idlwave-shell-idl-wframe)
1397 (setq idlwave-shell-idl-wframe nil
1398 idlwave-shell-display-wframe nil))
5e72c6b2
S
1399 (when (and (window-live-p win)
1400 (not (one-window-p 'nomini)))
8c7b4ec8 1401 (delete-window win))
5e72c6b2
S
1402 (idlwave-shell-cleanup)
1403 ;; Run the hook, if possible in the shell buffer.
1404 (if (get-buffer buf)
1405 (save-excursion
1406 (set-buffer buf)
1407 (run-hooks 'idlwave-shell-sentinel-hook))
1408 (run-hooks 'idlwave-shell-sentinel-hook))))
8c7b4ec8
EZ
1409
1410(defun idlwave-shell-scan-for-state ()
1411 "Scan for state info.
1412Looks for messages in output from last IDL command indicating where
1413IDL has stopped. The types of messages we are interested in are
1414execution halted, stepped, breakpoint, interrupted at and trace
1415messages. We ignore error messages otherwise.
1416For breakpoint messages process any attached count or command
1417parameters.
1418Update the windows if a message is found."
76959b77
S
1419 (cond
1420 ;; Make sure we have output
1421 ((not idlwave-shell-command-output))
13ae1076 1422
76959b77 1423 ;; First Priority: Syntax and other errors
13ae1076 1424 ((or
76959b77
S
1425 (string-match idlwave-shell-syntax-error idlwave-shell-command-output)
1426 (string-match idlwave-shell-other-error idlwave-shell-command-output))
1427 (save-excursion
1428 (set-buffer
1429 (get-buffer-create idlwave-shell-error-buffer))
1430 (erase-buffer)
1431 (insert idlwave-shell-command-output)
1432 (goto-char (point-min))
1433 (setq idlwave-shell-error-last (point)))
1434 (idlwave-shell-goto-next-error))
13ae1076 1435
76959b77
S
1436 ;; Second Priority: Various types of HALT messages.
1437 ((string-match idlwave-shell-halt-messages-re
1438 idlwave-shell-command-output)
1439 ;; Grab the file and line state info.
1440 (setq idlwave-shell-calling-stack-index 0)
1441 (setq idlwave-shell-halt-frame
13ae1076 1442 (idlwave-shell-parse-line
76959b77
S
1443 (substring idlwave-shell-command-output (match-end 0))))
1444 (idlwave-shell-display-line (idlwave-shell-pc-frame)))
13ae1076
JB
1445
1446 ;; Last Priority: Breakpoints
76959b77
S
1447 ((string-match idlwave-shell-break-message
1448 idlwave-shell-command-output)
1449 (setq idlwave-shell-calling-stack-index 0)
13ae1076
JB
1450 (setq idlwave-shell-halt-frame
1451 (idlwave-shell-parse-line
76959b77
S
1452 (substring idlwave-shell-command-output (match-end 0))))
1453 ;; We used to count hits on breakpoints
1454 ;; this is no longer supported since IDL breakpoints
1455 ;; have learned counting.
1456 ;; Do breakpoint command processing
13ae1076 1457 (let ((bp (assoc
76959b77
S
1458 (list
1459 (nth 0 idlwave-shell-halt-frame)
1460 (nth 1 idlwave-shell-halt-frame))
1461 idlwave-shell-bp-alist)))
1462 (if bp
1463 (let ((cmd (idlwave-shell-bp-get bp 'cmd)))
1464 (if cmd
1465 ;; Execute command
1466 (if (listp cmd) (eval cmd) (funcall cmd))))
1467 ;; A breakpoint that we did not know about - perhaps it was
1468 ;; set by the user or IDL isn't reporting breakpoints like
1469 ;; we expect. Lets update our list.
1470 (idlwave-shell-bp-query)))
1471 (idlwave-shell-display-line (idlwave-shell-pc-frame)))))
8c7b4ec8 1472
15e42531 1473(defvar idlwave-shell-error-buffer " *idlwave-shell-errors*"
8c7b4ec8
EZ
1474 "Buffer containing syntax errors from IDL compilations.")
1475
1476;; FIXME: the following two variables do not currently allow line breaks
1477;; in module and file names. I am not sure if it will be necessary to
1478;; change this. Currently it seems to work the way it is.
1479(defvar idlwave-shell-syntax-error
13ae1076 1480 "^% Syntax error.\\s-*\n\\s-*At:\\s-*\\(.*\\),\\s-*Line\\s-*\\(.*\\)"
8c7b4ec8
EZ
1481 "A regular expression to match an IDL syntax error.
1482The first \(..\) pair should match the file name. The second pair
1483should match the line number.")
1484
1485(defvar idlwave-shell-other-error
1486 "^% .*\n\\s-*At:\\s-*\\(.*\\),\\s-*Line\\s-*\\(.*\\)"
1487 "A regular expression to match any IDL error.
1488The first \(..\) pair should match the file name. The second pair
1489should match the line number.")
1490
1491(defvar idlwave-shell-file-line-message
13ae1076 1492 (concat
8c7b4ec8
EZ
1493 "\\(" ; program name group (1)
1494 "\\<[a-zA-Z][a-zA-Z0-9_$:]*" ; start with a letter, followed by [..]
1495 "\\([ \t]*\n[ \t]*[a-zA-Z0-9_$:]+\\)*"; continuation lines program name (2)
1496 "\\)" ; end program name group (1)
1497 "[ \t\n]+" ; white space
1498 "\\(" ; line number group (3)
1499 "[0-9]+" ; the line number (the fix point)
1500 "\\([ \t]*\n[ \t]*[0-9]+\\)*" ; continuation lines number (4)
1501 "\\)" ; end line number group (3)
1502 "[ \t\n]+" ; white space
1503 "\\(" ; file name group (5)
1504 "[^ \t\n]+" ; file names can contain any non-white
1505 "\\([ \t]*\n[ \t]*[^ \t\n]+\\)*" ; continuation lines file name (6)
1506 "\\)" ; end line number group (5)
1507 )
1508 "*A regular expression to parse out the file name and line number.
13ae1076 1509The 1st group should match the subroutine name.
8c7b4ec8
EZ
1510The 3rd group is the line number.
1511The 5th group is the file name.
1512All parts may contain linebreaks surrounded by spaces. This is important
1513in IDL5 which inserts random linebreaks in long module and file names.")
1514
1515(defun idlwave-shell-parse-line (string)
1516 "Parse IDL message for the subroutine, file name and line number.
1517We need to work hard here to remove the stupid line breaks inserted by
1518IDL5. These line breaks can be right in the middle of procedure
1519or file names.
1520It is very difficult to come up with a robust solution. This one seems
13ae1076 1521to be pretty good though.
8c7b4ec8
EZ
1522
1523Here is in what ways it improves over the previous solution:
1524
15251. The procedure name can be split and will be restored.
15262. The number can be split. I have never seen this, but who knows.
15273. We do not require the `.pro' extension for files.
1528
1529This function can still break when the file name ends on a end line
1530and the message line contains an additional line with garbage. Then
1531the first part of that garbage will be added to the file name.
1532However, the function checks the existence of the files with and
1533without this last part - thus the function only breaks if file name
1534plus garbage match an existing regular file. This is hopefully very
1535unlikely."
1536
1537 (let (number procedure file)
76959b77
S
1538 (when (and (not (string-match ":\\s-*\\$MAIN" string))
1539 (string-match idlwave-shell-file-line-message string))
8c7b4ec8
EZ
1540 (setq procedure (match-string 1 string)
1541 number (match-string 3 string)
1542 file (match-string 5 string))
13ae1076 1543
8c7b4ec8
EZ
1544 ;; Repair the strings
1545 (setq procedure (idlwave-shell-repair-string procedure))
1546 (setq number (idlwave-shell-repair-string number))
1547 (setq file (idlwave-shell-repair-file-name file))
1548
1549 ;; If we have a file, return the frame list
1550 (if file
1551 (list (idlwave-shell-file-name file)
1552 (string-to-int number)
1553 procedure)
1554 ;; No success finding a file
1555 nil))))
1556
1557(defun idlwave-shell-repair-string (string)
1558 "Repair a string by taking out all linebreaks. This is destructive!"
1559 (while (string-match "[ \t]*\n[ \t]*" string)
1560 (setq string (replace-match "" t t string)))
1561 string)
1562
1563(defun idlwave-shell-repair-file-name (file)
1564 "Repair a file name string by taking out all linebreaks.
1565The last line of STRING may be garbage - we check which one makes a valid
1566file name."
1567 (let ((file1 "") (file2 "") (start 0))
1568 ;; We scan no further than to the next "^%" line
13ae1076 1569 (if (string-match "^%" file)
8c7b4ec8
EZ
1570 (setq file (substring file 0 (match-beginning 0))))
1571 ;; Take out the line breaks
1572 (while (string-match "[ \t]*\n[ \t]*" file start)
1573 (setq file1 (concat file1 (substring file start (match-beginning 0)))
1574 start (match-end 0)))
1575 (setq file2 (concat file1 (substring file start)))
1576 (cond
1577 ((file-regular-p file2) file2)
1578 ((file-regular-p file1) file1)
1579 ;; If we cannot veryfy the existence of the file, we return the shorter
1580 ;; name. The idea behind this is that this may be a relative file name
1581 ;; and our idea about the current working directory may be wrong.
1582 ;; If it is a relative file name, it hopefully is short.
1583 ((not (string= "" file1)) file1)
1584 ((not (string= "" file2)) file2)
1585 (t nil))))
1586
1587(defun idlwave-shell-cleanup ()
1588 "Do necessary cleanup for a terminated IDL process."
1589 (setq idlwave-shell-step-frame nil
1590 idlwave-shell-halt-frame nil
1591 idlwave-shell-pending-commands nil
1592 idlwave-shell-command-line-to-execute nil
1593 idlwave-shell-bp-alist nil
15e42531 1594 idlwave-shell-calling-stack-index 0
8a36f093 1595 idlwave-idlwave_routine_info-compiled nil)
15e42531 1596 (idlwave-shell-delete-temp-files)
8c7b4ec8
EZ
1597 (idlwave-shell-display-line nil)
1598 (idlwave-shell-update-bp-overlays) ; kill old overlays
15e42531 1599 (idlwave-shell-kill-buffer idlwave-shell-hidden-output-buffer)
8c7b4ec8
EZ
1600 (idlwave-shell-kill-buffer idlwave-shell-bp-buffer)
1601 (idlwave-shell-kill-buffer idlwave-shell-error-buffer)
1602 ;; (idlwave-shell-kill-buffer (idlwave-shell-buffer))
1603 (and (get-buffer (idlwave-shell-buffer))
1604 (bury-buffer (get-buffer (idlwave-shell-buffer))))
1605 (run-hooks 'idlwave-shell-cleanup-hook))
1606
1607(defun idlwave-shell-kill-buffer (buf)
1608 "Kill buffer BUF if it exists."
1609 (if (setq buf (get-buffer buf))
1610 (kill-buffer buf)))
1611
1612(defun idlwave-shell-kill-shell-buffer-confirm ()
1613 (when (idlwave-shell-is-running)
1614 (ding)
1615 (unless (y-or-n-p "IDL shell is running. Are you sure you want to kill the buffer? ")
1616 (error "Abort"))
1617 (message "Killing buffer *idl* and the associated process")))
1618
05a1abfc
CD
1619(defun idlwave-shell-window (n)
1620 "Issue a `window,N' command to IDL, with special window size.
1621The size is given by `idlwave-shell-graphics-window-size'."
1622 (interactive "P")
1623 (let ((n (if n (prefix-numeric-value n) 0)))
13ae1076 1624 (idlwave-shell-send-command
05a1abfc 1625 (apply 'format "window,%d,xs=%d,ys=%d"
76959b77
S
1626 n idlwave-shell-graphics-window-size)
1627 nil (idlwave-shell-hide-p 'misc))))
05a1abfc 1628
8c7b4ec8 1629(defun idlwave-shell-resync-dirs ()
76959b77
S
1630 "Resync the buffer's idea of the current directory.
1631This command queries IDL with the command bound to
1632`idlwave-shell-dirstack-query', reads the output for the new
1633directory."
8c7b4ec8
EZ
1634 (interactive)
1635 (idlwave-shell-send-command idlwave-shell-dirstack-query
1636 'idlwave-shell-filter-directory
76959b77 1637 'hide 'wait))
8c7b4ec8
EZ
1638
1639(defun idlwave-shell-retall (&optional arg)
1640 "Return from the entire calling stack."
1641 (interactive "P")
76959b77 1642 (idlwave-shell-send-command "retall" nil (idlwave-shell-hide-p 'misc)))
8c7b4ec8
EZ
1643
1644(defun idlwave-shell-closeall (&optional arg)
1645 "Close all open files."
1646 (interactive "P")
76959b77 1647 (idlwave-shell-send-command "close,/all" nil (idlwave-shell-hide-p 'misc)))
8c7b4ec8
EZ
1648
1649(defun idlwave-shell-quit (&optional arg)
1650 "Exit the idl process after confirmation.
1651With prefix ARG, exit without confirmation."
1652 (interactive "P")
1653 (if (not (idlwave-shell-is-running))
1654 (error "Shell is not running")
1655 (if (or arg (y-or-n-p "Exit the IDLWAVE Shell? "))
1656 (condition-case nil
1657 (idlwave-shell-send-command "exit")
1658 (error nil)))))
1659
ca660d22 1660(defun idlwave-shell-reset (&optional hidden)
76959b77 1661 "Reset IDL. Return to main level and destroy the leftover variables.
13ae1076 1662This issues the following commands:
8c7b4ec8
EZ
1663RETALL
1664WIDGET_CONTROL,/RESET
1665CLOSE, /ALL
1666HEAP_GC, /VERBOSE"
1667 ;; OBJ_DESTROY, OBJ_VALID() FIXME: should this be added?
1668 (interactive "P")
1669 (message "Resetting IDL")
ca660d22
CD
1670 (setq idlwave-shell-calling-stack-index 0)
1671 (idlwave-shell-send-command "retall" nil hidden)
1672 (idlwave-shell-send-command "widget_control,/reset" nil hidden)
1673 (idlwave-shell-send-command "close,/all" nil hidden)
1674 ;; (idlwave-shell-send-command "obj_destroy, obj_valid()" nil hidden)
1675 (idlwave-shell-send-command "heap_gc,/verbose" nil hidden)
1676 (idlwave-shell-display-line nil))
8c7b4ec8 1677
15e42531
CD
1678(defun idlwave-shell-path-filter ()
1679 ;; Convert the output of the path query into a list of directories
1680 (let ((path-string idlwave-shell-command-output)
1681 (case-fold-search t)
1682 (start 0)
1683 dirs sysdir)
05a1abfc 1684 (while (string-match "^PATH:[ \t]*<\\(.*\\)>[ \t]*\n" path-string start)
15e42531
CD
1685 (push (match-string 1 path-string) dirs)
1686 (setq start (match-end 0)))
1687 (setq dirs (mapcar 'file-name-as-directory dirs))
05a1abfc 1688 (if (string-match "^SYSDIR:[ \t]*<\\(.*\\)>[ \t]*\n" path-string)
15e42531
CD
1689 (setq sysdir (file-name-as-directory
1690 (match-string 1 path-string))))
1691 (cons sysdir (nreverse dirs))))
1692
1693(defun idlwave-shell-routine-info-filter ()
1694 "Function which parses the special output from idlwave_routine_info.pro."
1695 (let ((text idlwave-shell-command-output)
1696 (start 0)
1697 sep sep-re file type spec specs name cs key keys class entry)
5e72c6b2 1698; (message "GOT: %s" text) ;??????????????????????
15e42531
CD
1699 ;; Initialize variables
1700 (setq idlwave-compiled-routines nil
1701 idlwave-unresolved-routines nil)
1702 ;; Cut out the correct part of the output.
1703 (if (string-match
1704 "^>>>BEGIN OF IDLWAVE ROUTINE INFO (\"\\(.+\\)\" IS THE SEPARATOR.*"
1705 text)
1706 (setq sep (match-string 1 text)
1707 sep-re (concat (regexp-quote sep) " *")
1708 text (substring text (match-end 0)))
1709 ;; Set dummy values and kill the text
1710 (setq sep "@" sep-re "@ *" text "")
13ae1076 1711 (message "Routine Info warning: No match for BEGIN line in \n>>>>\n%s\n<<<<\n"
5e72c6b2 1712 idlwave-shell-command-output))
15e42531
CD
1713 (if (string-match "^>>>END OF IDLWAVE ROUTINE INFO.*" text)
1714 (setq text (substring text 0 (match-beginning 0)))
13ae1076 1715 (message "Routine Info warning: No match for END line in \n>>>>\n%s\n<<<<\n"
5e72c6b2 1716 idlwave-shell-command-output))
15e42531
CD
1717 (if (string-match "\\S-" text)
1718 ;; Obviously, the pro worked. Make a note that we have it now.
1719 (setq idlwave-idlwave_routine_info-compiled t))
1720 ;; Match the output lines
1721 (while (string-match "^IDLWAVE-\\(PRO\\|FUN\\): \\(.*\\)" text start)
1722 (setq start (match-end 0))
1723 (setq type (match-string 1 text)
1724 spec (match-string 2 text)
1725 specs (idlwave-split-string spec sep-re)
1726 name (nth 0 specs)
1727 class (if (equal (nth 1 specs) "") nil (nth 1 specs))
1728 file (nth 2 specs)
1729 cs (nth 3 specs)
1730 key (nth 4 specs)
1731 keys (if (and (stringp key)
1732 (not (string-match "\\` *\\'" key)))
13ae1076 1733 (mapcar 'list
15e42531
CD
1734 (delete "" (idlwave-split-string key " +")))))
1735 (setq name (idlwave-sintern-routine-or-method name class t)
1736 class (idlwave-sintern-class class t)
1737 file (if (equal file "") nil file)
13ae1076 1738 keys (mapcar (lambda (x)
15e42531
CD
1739 (list (idlwave-sintern-keyword (car x) t))) keys))
1740 ;; Make sure we use the same string object for the same file
1741 (setq file (idlwave-sintern-file file t))
1742 ;; FIXME: What should I do with routines from the temp file???
1743 ;; Maybe just leave it in - there is a chance that the
1744 ;; routine is still in there.
1745 ;; (if (equal file idlwave-shell-temp-pro-file)
1746 ;; (setq file nil))
1747
1748 ;; In the following ignore routines already defined in buffers,
1749 ;; assuming that if the buffer stuff differs, it is a "new"
13ae1076 1750 ;; version.
15e42531
CD
1751 ;; We could do the same for the library to avoid duplicates -
1752 ;; but I think frequently a user might have several versions of
13ae1076 1753 ;; the same function in different programs, and in this case the
15e42531
CD
1754 ;; compiled one will be the best guess of all version.
1755 ;; Therefore, we leave duplicates of library routines in.
1756
1757 (cond ((string= name "$MAIN$")) ; ignore this one
1758 ((and (string= type "PRO")
1759 ;; FIXME: is it OK to make the buffer routines dominate?
1760 (or t (null file)
13ae1076 1761 (not (idlwave-rinfo-assq name 'pro class
15e42531
CD
1762 idlwave-buffer-routines)))
1763 ;; FIXME: is it OK to make the library routines dominate?
13ae1076 1764 ;;(not (idlwave-rinfo-assq name 'pro class
15e42531
CD
1765 ;; idlwave-library-routines))
1766 )
1767 (setq entry (list name 'pro class (cons 'compiled file) cs keys))
13ae1076 1768 (if file
15e42531
CD
1769 (push entry idlwave-compiled-routines)
1770 (push entry idlwave-unresolved-routines)))
13ae1076 1771
15e42531
CD
1772 ((and (string= type "FUN")
1773 ;; FIXME: is it OK to make the buffer routines dominate?
1774 (or t (not file)
13ae1076 1775 (not (idlwave-rinfo-assq name 'fun class
15e42531
CD
1776 idlwave-buffer-routines)))
1777 ;; FIXME: is it OK to make the library routines dominate?
13ae1076 1778 ;; (not (idlwave-rinfo-assq name 'fun class
15e42531
CD
1779 ;; idlwave-library-routines))
1780 )
1781 (setq entry (list name 'fun class (cons 'compiled file) cs keys))
1782 (if file
1783 (push entry idlwave-compiled-routines)
1784 (push entry idlwave-unresolved-routines))))))
1785 ;; Reverse the definitions so that they are alphabetically sorted.
1786 (setq idlwave-compiled-routines (nreverse idlwave-compiled-routines)
1787 idlwave-unresolved-routines (nreverse idlwave-unresolved-routines)))
1788
8c7b4ec8
EZ
1789(defun idlwave-shell-filter-directory ()
1790 "Get the current directory from `idlwave-shell-command-output'.
1791Change the default directory for the process buffer to concur."
1792 (save-excursion
1793 (set-buffer (idlwave-shell-buffer))
76959b77 1794 (if (string-match ",___cur[\n\r]\\(\\S-*\\) *[\n\r]"
8c7b4ec8 1795 idlwave-shell-command-output)
13ae1076 1796 (let ((dir (substring idlwave-shell-command-output
8c7b4ec8 1797 (match-beginning 1) (match-end 1))))
76959b77 1798; (message "Setting Emacs working dir to %s" dir)
8c7b4ec8
EZ
1799 (setq idlwave-shell-default-directory dir)
1800 (setq default-directory (file-name-as-directory dir))))))
1801
76959b77
S
1802(defvar idlwave-shell-get-object-class nil)
1803(defun idlwave-shell-get-object-class (apos)
1804 "Query the shell for the class of the object before point."
1805 (let ((bos (save-excursion (idlwave-start-of-substatement 'pre) (point)))
1806 (bol (save-excursion (forward-line 0) (point)))
1807 expression)
1808 (save-excursion
1809 (goto-char apos)
13ae1076 1810 (setq expression (buffer-substring
76959b77
S
1811 (catch 'exit
1812 (while t
13ae1076 1813 (if (not (re-search-backward
76959b77
S
1814 "[^][.A-Za-z0-9_() ]" bos t))
1815 (throw 'exit bos)) ;ran into bos
1816 (if (not (idlwave-is-pointer-dereference bol))
1817 (throw 'exit (1+ (point))))))
1818 apos)))
1819 (when (not (string= expression ""))
1820 (setq idlwave-shell-get-object-class nil)
1821 (idlwave-shell-send-command
1822 (concat "print,obj_class(" expression ")")
1823 'idlwave-shell-parse-object-class
1824 'hide 'wait)
1825 ;; If we don't know anything about the class, update shell routines
1826 (if (and idlwave-shell-get-object-class
1827 (not (assoc-ignore-case idlwave-shell-get-object-class
1828 (idlwave-class-alist))))
1829 (idlwave-shell-maybe-update-routine-info))
1830 idlwave-shell-get-object-class)))
1831
1832(defun idlwave-shell-parse-object-class ()
1833 "Parse the output of the obj_class command."
1834 (let ((match "print,obj_class([^\n\r]+[\n\r ]+"))
1835 (if (and
1836 (not (string-match (concat match match "\\s-*^[\n\r]+"
1837 "% Syntax error")
1838 idlwave-shell-command-output))
1839 (string-match (concat match "\\([A-Za-z_0-9]+\\)")
1840 idlwave-shell-command-output))
13ae1076 1841 (setq idlwave-shell-get-object-class
76959b77
S
1842 (match-string 1 idlwave-shell-command-output)))))
1843
1844
8c7b4ec8
EZ
1845(defun idlwave-shell-complete (&optional arg)
1846 "Do completion in the idlwave-shell buffer.
1847Calls `idlwave-shell-complete-filename' after some executive commands or
1848in strings. Otherwise, calls `idlwave-complete' to complete modules and
1849keywords."
8c7b4ec8
EZ
1850 (interactive "P")
1851 (let (cmd)
1852 (cond
1853 ((setq cmd (idlwave-shell-executive-command))
1854 ;; We are in a command line with an executive command
1855 (if (member (upcase cmd)
1856 '(".R" ".RU" ".RUN" ".RN" ".RNE" ".RNEW"
1857 ".COM" ".COMP" ".COMPI" ".COMPIL" ".COMPILE"))
1858 ;; This command expects file names
1859 (idlwave-shell-complete-filename)))
76959b77
S
1860
1861 ((idlwave-shell-batch-command)
1862 (idlwave-shell-complete-filename))
1863
15e42531
CD
1864 ((and (idlwave-shell-filename-string)
1865 (save-excursion
1866 (beginning-of-line)
1867 (let ((case-fold-search t))
76959b77
S
1868 (not (looking-at ".*obj_new")))))
1869 (idlwave-shell-complete-filename))
13ae1076 1870
8c7b4ec8
EZ
1871 (t
1872 ;; Default completion of modules and keywords
15e42531 1873 (idlwave-complete arg)))))
8c7b4ec8
EZ
1874
1875(defun idlwave-shell-complete-filename (&optional arg)
1876 "Complete a file name at point if after a file name.
1877We assume that we are after a file name when completing one of the
76959b77
S
1878args of an executive .run, .rnew or .compile."
1879 ;; CWD might have changed, resync, to set default directory
13ae1076 1880 (idlwave-shell-resync-dirs)
76959b77
S
1881 (let ((comint-file-name-chars idlwave-shell-file-name-chars))
1882 (comint-dynamic-complete-as-filename)))
8c7b4ec8
EZ
1883
1884(defun idlwave-shell-executive-command ()
1885 "Return the name of the current executive command, if any."
1886 (save-excursion
1887 (idlwave-beginning-of-statement)
76959b77 1888 (if (looking-at "[ \t]*\\([.][^ \t\n\r]+\\)")
8c7b4ec8
EZ
1889 (match-string 1))))
1890
1891(defun idlwave-shell-filename-string ()
1892 "Return t if in a string and after what could be a file name."
1893 (let ((limit (save-excursion (beginning-of-line) (point))))
1894 (save-excursion
1895 ;; Skip backwards over file name chars
1896 (skip-chars-backward idlwave-shell-file-name-chars limit)
1897 ;; Check of the next char is a string delimiter
1898 (memq (preceding-char) '(?\' ?\")))))
1899
76959b77
S
1900(defun idlwave-shell-batch-command ()
1901 "Returns t if we're in a batch command statement like @foo"
1902 (let ((limit (save-excursion (beginning-of-line) (point))))
1903 (save-excursion
1904 ;; Skip backwards over filename
1905 (skip-chars-backward idlwave-shell-file-name-chars limit)
1906 (skip-chars-backward " \t" limit)
1907 (and (eq (preceding-char) ?@) (not (idlwave-in-quote))))))
1908
8c7b4ec8
EZ
1909;;;
1910;;; This section contains code for debugging IDL programs. --------------------
1911;;;
1912
1913(defun idlwave-shell-redisplay (&optional hide)
1914 "Tries to resync the display with where execution has stopped.
13ae1076 1915Issues a \"help,/trace\" command followed by a call to
8c7b4ec8
EZ
1916`idlwave-shell-display-line'. Also updates the breakpoint
1917overlays."
1918 (interactive)
ca660d22 1919 (setq idlwave-shell-calling-stack-index 0)
8c7b4ec8
EZ
1920 (idlwave-shell-send-command
1921 "help,/trace"
1922 '(idlwave-shell-display-line
1923 (idlwave-shell-pc-frame))
1924 hide)
1925 (idlwave-shell-bp-query))
1926
1927(defun idlwave-shell-display-level-in-calling-stack (&optional hide)
13ae1076 1928 (idlwave-shell-send-command
8c7b4ec8 1929 "help,/trace"
ca660d22
CD
1930 `(progn
1931 ;; scanning for the state will reset the stack level - restore it
1932 (setq idlwave-shell-calling-stack-index
1933 ,idlwave-shell-calling-stack-index)
1934 ;; parse the stack and visit the selected frame
1935 (idlwave-shell-parse-stack-and-display))
8c7b4ec8
EZ
1936 hide))
1937
1938(defun idlwave-shell-parse-stack-and-display ()
1939 (let* ((lines (delete "" (idlwave-split-string
1940 idlwave-shell-command-output "^%")))
1941 (stack (delq nil (mapcar 'idlwave-shell-parse-line lines)))
1942 (nmax (1- (length stack)))
1943 (nmin 0) message)
8c7b4ec8
EZ
1944 (cond
1945 ((< nmax nmin)
15e42531
CD
1946 (setq idlwave-shell-calling-stack-index 0)
1947 (ding)
1948 (message "Problem with calling stack"))
8c7b4ec8 1949 ((> idlwave-shell-calling-stack-index nmax)
ca660d22 1950 (ding)
8c7b4ec8 1951 (setq idlwave-shell-calling-stack-index nmax
ca660d22
CD
1952 message (format "%d is the highest calling stack level - can't go further up"
1953 (- nmax))))
8c7b4ec8 1954 ((< idlwave-shell-calling-stack-index nmin)
ca660d22 1955 (ding)
8c7b4ec8 1956 (setq idlwave-shell-calling-stack-index nmin
ca660d22
CD
1957 message (format "%d is the current calling stack level - can't go further down"
1958 (- nmin)))))
13ae1076 1959 (setq idlwave-shell-calling-stack-routine
ca660d22 1960 (nth 2 (nth idlwave-shell-calling-stack-index stack)))
13ae1076 1961 (idlwave-shell-display-line
8c7b4ec8 1962 (nth idlwave-shell-calling-stack-index stack))
13ae1076 1963 (message (or message
ca660d22
CD
1964 (format "In routine %s (stack level %d)"
1965 idlwave-shell-calling-stack-routine
1966 (- idlwave-shell-calling-stack-index))))))
8c7b4ec8
EZ
1967
1968(defun idlwave-shell-stack-up ()
1969 "Display the source code one step up the calling stack."
1970 (interactive)
1971 (incf idlwave-shell-calling-stack-index)
1972 (idlwave-shell-display-level-in-calling-stack 'hide))
1973(defun idlwave-shell-stack-down ()
1974 "Display the source code one step down the calling stack."
1975 (interactive)
1976 (decf idlwave-shell-calling-stack-index)
1977 (idlwave-shell-display-level-in-calling-stack 'hide))
1978
1979(defun idlwave-shell-goto-frame (&optional frame)
1980 "Set buffer to FRAME with point at the frame line.
1981If the optional argument FRAME is nil then idlwave-shell-pc-frame is
1982used. Does nothing if the resulting frame is nil."
1983 (if frame ()
1984 (setq frame (idlwave-shell-pc-frame)))
1985 (cond
1986 (frame
15e42531 1987 (set-buffer (idlwave-find-file-noselect (car frame) 'shell))
8c7b4ec8
EZ
1988 (widen)
1989 (goto-line (nth 1 frame)))))
1990
1991(defun idlwave-shell-pc-frame ()
1992 "Returns the frame for IDL execution."
1993 (and idlwave-shell-halt-frame
13ae1076 1994 (list (nth 0 idlwave-shell-halt-frame)
ca660d22
CD
1995 (nth 1 idlwave-shell-halt-frame)
1996 (nth 2 idlwave-shell-halt-frame))))
8c7b4ec8
EZ
1997
1998(defun idlwave-shell-valid-frame (frame)
1999 "Check that frame is for an existing file."
2000 (file-readable-p (car frame)))
2001
2002(defun idlwave-shell-display-line (frame &optional col)
2003 "Display FRAME file in other window with overlay arrow.
2004
2005FRAME is a list of file name, line number, and subroutine name.
2006If FRAME is nil then remove overlay."
2007 (if (not frame)
2008 ;; Remove stop-line overlay from old position
13ae1076 2009 (progn
8c7b4ec8 2010 (setq overlay-arrow-string nil)
ca660d22 2011 (setq idlwave-shell-mode-line-info nil)
15e42531 2012 (setq idlwave-shell-is-stopped nil)
8c7b4ec8
EZ
2013 (if idlwave-shell-stop-line-overlay
2014 (delete-overlay idlwave-shell-stop-line-overlay)))
2015 (if (not (idlwave-shell-valid-frame frame))
15e42531
CD
2016 ;; FIXME: errors are dangerous in shell filters. But I think I
2017 ;; have never encountered this one.
8c7b4ec8
EZ
2018 (error (concat "Invalid frame - unable to access file: " (car frame)))
2019;;;
2020;;; buffer : the buffer to display a line in.
2021;;; select-shell: current buffer is the shell.
13ae1076 2022;;;
ca660d22
CD
2023 (setq idlwave-shell-mode-line-info
2024 (if (nth 2 frame)
13ae1076 2025 (format "[%d:%s]"
ca660d22
CD
2026 (- idlwave-shell-calling-stack-index)
2027 (nth 2 frame))))
15e42531 2028 (let* ((buffer (idlwave-find-file-noselect (car frame) 'shell))
8c7b4ec8
EZ
2029 (select-shell (equal (buffer-name) (idlwave-shell-buffer)))
2030 window pos)
2031
2032 ;; First make sure the shell window is visible
2033 (idlwave-display-buffer (idlwave-shell-buffer)
2034 nil (idlwave-shell-shell-frame))
2035
2036 ;; Now display the buffer and remember which window it is.
2037 (setq window (idlwave-display-buffer buffer
2038 nil (idlwave-shell-source-frame)))
2039
2040 ;; Enter the buffer and mark the line
2041 (save-excursion
2042 (set-buffer buffer)
2043 (save-restriction
2044 (widen)
2045 (goto-line (nth 1 frame))
2046 (setq pos (point))
15e42531 2047 (setq idlwave-shell-is-stopped t)
8c7b4ec8
EZ
2048 (if idlwave-shell-stop-line-overlay
2049 ;; Move overlay
2050 (move-overlay idlwave-shell-stop-line-overlay
2051 (point) (save-excursion (end-of-line) (point))
2052 (current-buffer))
2053 ;; Use the arrow instead, but only if marking is wanted.
2054 (if idlwave-shell-mark-stop-line
2055 (setq overlay-arrow-string idlwave-shell-overlay-arrow))
2056 (or overlay-arrow-position ; create the marker if necessary
2057 (setq overlay-arrow-position (make-marker)))
2058 (set-marker overlay-arrow-position (point) buffer)))
13ae1076 2059
8c7b4ec8
EZ
2060 ;; If the point is outside the restriction, widen the buffer.
2061 (if (or (< pos (point-min)) (> pos (point-max)))
2062 (progn
2063 (widen)
2064 (goto-char pos)))
2065
2066 ;; If we have the column of the error, move the cursor there.
2067 (if col (move-to-column col))
2068 (setq pos (point)))
2069
2070 ;; Make sure pos is really displayed in the window.
2071 (set-window-point window pos)
2072
13ae1076 2073 ;; If we came from the shell, go back there. Otherwise select
8c7b4ec8 2074 ;; the window where the error is displayed.
13ae1076 2075 (if (and (equal (buffer-name) (idlwave-shell-buffer))
8c7b4ec8
EZ
2076 (not select-shell))
2077 (select-window window))))))
2078
2079
2080(defun idlwave-shell-step (arg)
2081 "Step one source line. If given prefix argument ARG, step ARG source lines."
2082 (interactive "p")
2083 (or (not arg) (< arg 1)
2084 (setq arg 1))
13ae1076 2085 (idlwave-shell-send-command
76959b77
S
2086 (concat ".s " (if (integerp arg) (int-to-string arg) arg))
2087 nil (idlwave-shell-hide-p 'debug)))
8c7b4ec8
EZ
2088
2089(defun idlwave-shell-stepover (arg)
2090 "Stepover one source line.
13ae1076 2091If given prefix argument ARG, step ARG source lines.
8c7b4ec8
EZ
2092Uses IDL's stepover executive command which does not enter called functions."
2093 (interactive "p")
2094 (or (not arg) (< arg 1)
2095 (setq arg 1))
13ae1076 2096 (idlwave-shell-send-command
76959b77
S
2097 (concat ".so " (if (integerp arg) (int-to-string arg) arg))
2098 nil (idlwave-shell-hide-p 'debug)))
8c7b4ec8 2099
76959b77 2100(defun idlwave-shell-break-here (&optional count cmd condition)
13ae1076 2101 "Set breakpoint at current line.
8c7b4ec8
EZ
2102
2103If Count is nil then an ordinary breakpoint is set. We treat a count
2104of 1 as a temporary breakpoint using the ONCE keyword. Counts greater
2105than 1 use the IDL AFTER=count keyword to break only after reaching
2106the statement count times.
2107
13ae1076 2108Optional argument CMD is a list or function to evaluate upon reaching
8c7b4ec8 2109the breakpoint."
13ae1076 2110
8c7b4ec8 2111 (interactive "P")
76959b77 2112 (when (listp count)
13ae1076 2113 (if (equal (car count) 4)
76959b77
S
2114 (setq condition (read-string "Break Condition: ")))
2115 (setq count nil))
8c7b4ec8
EZ
2116 (idlwave-shell-set-bp
2117 ;; Create breakpoint
2118 (idlwave-shell-bp (idlwave-shell-current-frame)
76959b77 2119 (list count cmd condition)
8c7b4ec8
EZ
2120 (idlwave-shell-current-module))))
2121
2122(defun idlwave-shell-set-bp-check (bp)
2123 "Check for failure to set breakpoint.
2124This is run on `idlwave-shell-post-command-hook'.
2125Offers to recompile the procedure if we failed. This usually fixes
2126the problem with not being able to set the breakpoint."
2127 ;; Scan for message
2128 (if (and idlwave-shell-command-output
2129 (string-match "% BREAKPOINT: *Unable to find code"
2130 idlwave-shell-command-output))
2131 ;; Offer to recompile
2132 (progn
2133 (if (progn
2134 (beep)
13ae1076 2135 (y-or-n-p
8c7b4ec8
EZ
2136 (concat "Okay to recompile file "
2137 (idlwave-shell-bp-get bp 'file) " ")))
2138 ;; Recompile
2139 (progn
2140 ;; Clean up before retrying
2141 (idlwave-shell-command-failure)
2142 (idlwave-shell-send-command
13ae1076 2143 (concat ".run " (idlwave-shell-bp-get bp 'file)) nil
76959b77 2144 (idlwave-shell-hide-p 'run))
8c7b4ec8
EZ
2145 ;; Try setting breakpoint again
2146 (idlwave-shell-set-bp bp))
2147 (beep)
2148 (message "Unable to set breakpoint.")
2149 (idlwave-shell-command-failure)
2150 )
2151 ;; return non-nil if no error found
2152 nil)
2153 'okay))
2154
2155(defun idlwave-shell-command-failure ()
2156 "Do any necessary clean up when an IDL command fails.
2157Call this from a function attached to `idlwave-shell-post-command-hook'
2158that detects the failure of a command.
2159For example, this is called from `idlwave-shell-set-bp-check' when a
2160breakpoint can not be set."
2161 ;; Clear pending commands
2162 (setq idlwave-shell-pending-commands nil))
2163
2164(defun idlwave-shell-cont ()
2165 "Continue executing."
2166 (interactive)
76959b77
S
2167 (idlwave-shell-send-command ".c" '(idlwave-shell-redisplay 'hide)
2168 (idlwave-shell-hide-p 'debug)))
8c7b4ec8
EZ
2169
2170(defun idlwave-shell-go ()
2171 "Run .GO. This starts the main program of the last compiled file."
2172 (interactive)
76959b77
S
2173 (idlwave-shell-send-command ".go" '(idlwave-shell-redisplay 'hide)
2174 (idlwave-shell-hide-p 'debug)))
8c7b4ec8
EZ
2175
2176(defun idlwave-shell-return ()
2177 "Run .RETURN (continue to next return, but stay in subprogram)."
2178 (interactive)
76959b77
S
2179 (idlwave-shell-send-command ".return" '(idlwave-shell-redisplay 'hide)
2180 (idlwave-shell-hide-p 'debug)))
8c7b4ec8
EZ
2181
2182(defun idlwave-shell-skip ()
2183 "Run .SKIP (skip one line, then step)."
2184 (interactive)
76959b77
S
2185 (idlwave-shell-send-command ".skip" '(idlwave-shell-redisplay 'hide)
2186 (idlwave-shell-hide-p 'debug)))
8c7b4ec8
EZ
2187
2188(defun idlwave-shell-clear-bp (bp)
2189 "Clear breakpoint BP.
2190Clears in IDL and in `idlwave-shell-bp-alist'."
2191 (let ((index (idlwave-shell-bp-get bp)))
2192 (if index
2193 (progn
2194 (idlwave-shell-send-command
13ae1076 2195 (concat "breakpoint,/clear,"
76959b77
S
2196 (if (integerp index) (int-to-string index) index))
2197 nil (idlwave-shell-hide-p 'breakpoint))
8c7b4ec8
EZ
2198 (idlwave-shell-bp-query)))))
2199
2200(defun idlwave-shell-current-frame ()
2201 "Return a list containing the current file name and line point is in.
2202If in the IDL shell buffer, returns `idlwave-shell-pc-frame'."
2203 (if (eq (current-buffer) (get-buffer (idlwave-shell-buffer)))
2204 ;; In IDL shell
2205 (idlwave-shell-pc-frame)
2206 ;; In source
2207 (list (idlwave-shell-file-name (buffer-file-name))
2208 (save-restriction
2209 (widen)
2210 (save-excursion
2211 (beginning-of-line)
2212 (1+ (count-lines 1 (point))))))))
2213
2214(defun idlwave-shell-current-module ()
2215 "Return the name of the module for the current file.
2216Returns nil if unable to obtain a module name."
2217 (if (eq (current-buffer) (get-buffer (idlwave-shell-buffer)))
2218 ;; In IDL shell
2219 (nth 2 idlwave-shell-halt-frame)
2220 ;; In pro file
2221 (save-restriction
2222 (widen)
2223 (save-excursion
2224 (if (idlwave-prev-index-position)
2225 (upcase (idlwave-unit-name)))))))
2226
2227(defun idlwave-shell-clear-current-bp ()
2228 "Remove breakpoint at current line.
2229This command can be called from the shell buffer if IDL is currently stopped
2230at a breakpoint."
2231 (interactive)
2232 (let ((bp (idlwave-shell-find-bp (idlwave-shell-current-frame))))
2233 (if bp (idlwave-shell-clear-bp bp)
2234 ;; Try moving to beginning of statement
2235 (save-excursion
2236 (idlwave-shell-goto-frame)
2237 (idlwave-beginning-of-statement)
2238 (setq bp (idlwave-shell-find-bp (idlwave-shell-current-frame)))
2239 (if bp (idlwave-shell-clear-bp bp)
2240 (beep)
2241 (message "Cannot identify breakpoint for this line"))))))
2242
76959b77
S
2243(defun idlwave-shell-disable-all-bp (&optional enable)
2244 "Disable all breakpoints we know about.
2245If ENABLE is non-nil, enable them instead."
2246 (let ((bpl idlwave-shell-bp-alist))
2247 (while bpl
13ae1076 2248 (idlwave-shell-send-command
76959b77
S
2249 (concat "breakpoint,"
2250 (if enable "/enable," "/disable," )
2251 (idlwave-shell-bp-get (car bpl)))
2252 nil (idlwave-shell-hide-p 'breakpoint))
2253 (setq bpl (cdr bpl)))))
13ae1076 2254
8c7b4ec8
EZ
2255(defun idlwave-shell-to-here ()
2256 "Set a breakpoint with count 1 then continue."
2257 (interactive)
76959b77 2258 (idlwave-shell-disable-all-bp)
8c7b4ec8 2259 (idlwave-shell-break-here 1)
76959b77
S
2260 (idlwave-shell-cont)
2261 (idlwave-shell-disable-all-bp 'enable))
8c7b4ec8
EZ
2262
2263(defun idlwave-shell-break-in (&optional module)
2264 "Look for a module name near point and set a break point for it.
2265The command looks for an identifier near point and sets a breakpoint
2266for the first line of the corresponding module."
2267 (interactive)
2268 ;; get the identifier
2269 (let (module)
2270 (save-excursion
2271 (skip-chars-backward "a-zA-Z0-9_$")
2272 (if (looking-at idlwave-identifier)
2273 (setq module (match-string 0))
2274 (error "No identifier at point")))
2275 (idlwave-shell-send-command
2276 idlwave-shell-sources-query
2277 `(progn
2278 (idlwave-shell-sources-filter)
2279 (idlwave-shell-set-bp-in-module ,module))
2280 'hide)))
2281
2282(defun idlwave-shell-set-bp-in-module (module)
2283 "Set breakpoint in module. Assumes that `idlwave-shell-sources-alist'
2284contains an entry for that module."
13ae1076 2285 (let ((source-file (car-safe
8c7b4ec8
EZ
2286 (cdr-safe
2287 (assoc (upcase module)
2288 idlwave-shell-sources-alist))))
2289 buf)
2290 (if (or (not source-file)
2291 (not (file-regular-p source-file))
2292 (not (setq buf
2293 (or (idlwave-get-buffer-visiting source-file)
2294 (find-file-noselect source-file)))))
2295 (progn
2296 (message "The source file for module %s is probably not compiled"
2297 module)
2298 (beep))
2299 (save-excursion
2300 (set-buffer buf)
2301 (save-excursion
2302 (goto-char (point-min))
2303 (let ((case-fold-search t))
13ae1076 2304 (if (re-search-forward
8c7b4ec8
EZ
2305 (concat "^[ \t]*\\(pro\\|function\\)[ \t]+"
2306 (downcase module)
2307 "[ \t\n,]") nil t)
2308 (progn
2309 (goto-char (match-beginning 1))
2310 (message "Setting breakpoint for module %s" module)
2311 (idlwave-shell-break-here))
2312 (message "Cannot find module %s in file %s" module source-file)
2313 (beep))))))))
2314
2315(defun idlwave-shell-up ()
2316 "Run to end of current block.
2317Sets a breakpoint with count 1 at end of block, then continues."
2318 (interactive)
2319 (if (idlwave-shell-pc-frame)
2320 (save-excursion
2321 (idlwave-shell-goto-frame)
2322 ;; find end of subprogram
2323 (let ((eos (save-excursion
2324 (idlwave-beginning-of-subprogram)
2325 (idlwave-forward-block)
2326 (point))))
2327 (idlwave-backward-up-block -1)
2328 ;; move beyond end block line - IDL will not break there.
2329 ;; That is, you can put a breakpoint there but when IDL does
2330 ;; break it will report that it is at the next line.
2331 (idlwave-next-statement)
2332 (idlwave-end-of-statement)
2333 ;; Make sure we are not beyond subprogram
2334 (if (< (point) eos)
2335 ;; okay
2336 ()
2337 ;; Move back inside subprogram
2338 (goto-char eos)
2339 (idlwave-previous-statement))
2340 (idlwave-shell-to-here)))))
2341
2342(defun idlwave-shell-out ()
2343 "Attempt to run until this procedure exits.
2344Runs to the last statement and then steps 1 statement. Use the .out command."
2345 (interactive)
76959b77 2346 (idlwave-shell-send-command ".o" nil (idlwave-shell-hide-p 'debug)))
8c7b4ec8 2347
15e42531 2348(defun idlwave-shell-help-expression (arg)
8c7b4ec8 2349 "Print help on current expression. See `idlwave-shell-print'."
15e42531
CD
2350 (interactive "P")
2351 (idlwave-shell-print arg 'help))
8c7b4ec8 2352
5e72c6b2
S
2353(defmacro idlwave-shell-mouse-examine (help &optional ev)
2354 "Create a function for generic examination of expressions."
2355 `(lambda (event)
2356 "Expansion function for expression examination."
2357 (interactive "e")
2358 (let ((transient-mark-mode t)
2359 (zmacs-regions t)
13ae1076 2360 (tracker (if (featurep 'xemacs) 'mouse-track
5e72c6b2
S
2361 'mouse-drag-region)))
2362 (funcall tracker event)
2363 (idlwave-shell-print (if (idlwave-region-active-p) '(16) nil)
2364 ,help ,ev))))
2365
8c7b4ec8 2366(defun idlwave-shell-mouse-print (event)
5e72c6b2 2367 "Print value of variable at the mouse position, with `help'"
8c7b4ec8 2368 (interactive "e")
5e72c6b2 2369 (funcall (idlwave-shell-mouse-examine nil) event))
8c7b4ec8
EZ
2370
2371(defun idlwave-shell-mouse-help (event)
5e72c6b2 2372 "Print value of variable at the mouse position, with `print'."
8c7b4ec8 2373 (interactive "e")
5e72c6b2
S
2374 (funcall (idlwave-shell-mouse-examine 'help) event))
2375
2376(defun idlwave-shell-examine-select (event)
2377 "Pop-up a list to select from for examining the expression"
2378 (interactive "e")
2379 (funcall (idlwave-shell-mouse-examine nil event) event))
2380
2381(defmacro idlwave-shell-examine (help)
2382 "Create a function for key-driven expression examination."
2383 `(lambda ()
2384 (interactive)
2385 (idlwave-shell-print nil ,help)))
2386
2387(defun idlwave-shell-define-key-both (key hook)
2388 "Define a key in both the shell and buffer mode maps."
2389 (define-key idlwave-mode-map key hook)
2390 (define-key idlwave-shell-mode-map key hook))
2391
2392(defvar idlwave-shell-examine-label nil
2393 "Label to include with examine text if separate.")
2394
2395(defun idlwave-shell-print (arg &optional help ev)
13ae1076 2396 "Print current expression.
5e72c6b2
S
2397
2398With HELP non-nil, show help on expression. If HELP is a string,
2399the expression will be put in place of ___, e.g.:
2400
2401 print,size(___,/DIMENSIONS)
2402
2403Otherwise, print is called on the expression.
8c7b4ec8 2404
8c7b4ec8 2405An expression is an identifier plus 1 pair of matched parentheses
5e72c6b2
S
2406directly following the identifier - an array or function call.
2407Alternatively, an expression is the contents of any matched
2408parentheses when the open parenthesis is not directly preceded by an
8c7b4ec8
EZ
2409identifier. If point is at the beginning or within an expression
2410return the inner-most containing expression, otherwise, return the
15e42531
CD
2411preceding expression.
2412
5e72c6b2
S
2413With prefix arg ARG prompt for an expression.
2414
2415With double prefix arg, use the current region.
2416
2417If EV is a valid event passed, pop-up a list from
2418idlw-shell-examine-alist from which to select the help command text."
15e42531 2419 (interactive "P")
8c7b4ec8 2420 (save-excursion
5e72c6b2
S
2421 (let* ((process (get-buffer-process (current-buffer)))
2422 (process-mark (if process (process-mark process)))
13ae1076 2423 (stack-label
5e72c6b2
S
2424 (if (and (integerp idlwave-shell-calling-stack-index)
2425 (> idlwave-shell-calling-stack-index 0))
13ae1076
JB
2426 (format " [-%d:%s]"
2427 idlwave-shell-calling-stack-index
5e72c6b2
S
2428 idlwave-shell-calling-stack-routine)))
2429 expr beg end cmd examine-hook)
2430 (cond
2431 ((and (equal arg '(16))
2432 (< (- (region-end) (region-beginning)) 2000))
2433 (setq beg (region-beginning)
2434 end (region-end)))
2435 (arg
2436 (setq expr (read-string "Expression: ")))
2437 (t
76959b77 2438 (idlwave-with-special-syntax
05a1abfc
CD
2439 ;; Move to beginning of current or previous expression
2440 (if (looking-at "\\<\\|(")
2441 ;; At beginning of expression, don't move backwards unless
2442 ;; this is at the end of an indentifier.
2443 (if (looking-at "\\>")
2444 (backward-sexp))
2445 (backward-sexp))
2446 (if (looking-at "\\>")
2447 ;; Move to beginning of identifier - must be an array or
2448 ;; function expression.
2449 (backward-sexp))
2450 ;; Move to end of expression
2451 (setq beg (point))
2452 (forward-sexp)
2453 (while (looking-at "\\>[[(]\\|\\.")
2454 ;; an array
2455 (forward-sexp))
5e72c6b2 2456 (setq end (point)))))
13ae1076 2457
5e72c6b2
S
2458 ;; Get expression, but first move the begin mark if a
2459 ;; process-mark is inside the region, to keep the overlay from
2460 ;; wandering in the Shell.
2461 (when (and beg end)
2462 (if (and process-mark (> process-mark beg) (< process-mark end))
2463 (setq beg (marker-position process-mark)))
2464 (setq expr (buffer-substring beg end)))
2465
2466 ;; Show the overlay(s) and attach any necessary hooks and filters
ca660d22 2467 (when (and beg end idlwave-shell-expression-overlay)
13ae1076 2468 (move-overlay idlwave-shell-expression-overlay beg end
ca660d22 2469 (current-buffer))
13ae1076 2470 (add-hook 'pre-command-hook
5e72c6b2 2471 'idlwave-shell-delete-expression-overlay))
13ae1076 2472 (setq examine-hook
5e72c6b2
S
2473 (if idlwave-shell-separate-examine-output
2474 'idlwave-shell-examine-display
2475 'idlwave-shell-examine-highlight))
2476 (add-hook 'pre-command-hook
2477 'idlwave-shell-delete-output-overlay)
13ae1076 2478
5e72c6b2
S
2479 ;; Remove empty or comment-only lines
2480 (while (string-match "\n[ \t]*\\(;.*\\)?\r*\n" expr)
2481 (setq expr (replace-match "\n" t t expr)))
2482 ;; Concatenate continuation lines
2483 (while (string-match "[ \t]*\\$.*\\(;.*\\)?\\(\n[ \t]*\\|$\\)" expr)
2484 (setq expr (replace-match "" t t expr)))
2485 ;; Remove final newline
2486 (if (string-match "\n[ \t\r]*\\'" expr)
2487 (setq expr (replace-match "" t t expr)))
2488 ;; Pop-up the examine selection list, if appropriate
2489 (if (and ev idlwave-shell-examine-alist)
13ae1076
JB
2490 (let* ((help-cons
2491 (assoc
2492 (idlwave-popup-select
5e72c6b2
S
2493 ev (mapcar 'car idlwave-shell-examine-alist)
2494 "Examine with")
2495 idlwave-shell-examine-alist)))
2496 (setq help (cdr help-cons))
2497 (if idlwave-shell-separate-examine-output
13ae1076
JB
2498 (setq idlwave-shell-examine-label
2499 (concat
5e72c6b2
S
2500 (format "==>%s<==\n%s:" expr (car help-cons))
2501 stack-label "\n"))))
2502 (setq idlwave-shell-examine-label
2503 (concat
13ae1076 2504 (format "==>%s<==\n%s:" expr
5e72c6b2
S
2505 (cond ((null help) "print")
2506 ((stringp help) help)
2507 (t (symbol-name help))))
2508 stack-label "\n")))
2509
2510 ;; Send the command
2511 (if stack-label
ca660d22
CD
2512 (setq cmd (idlwave-retrieve-expression-from-level
2513 expr
2514 idlwave-shell-calling-stack-index
2515 idlwave-shell-calling-stack-routine
2516 help))
5e72c6b2
S
2517 (setq cmd (idlwave-shell-help-statement help expr)))
2518 ;(idlwave-shell-recenter-shell-window)
13ae1076
JB
2519 (idlwave-shell-send-command
2520 cmd
2521 examine-hook
5e72c6b2
S
2522 (if idlwave-shell-separate-examine-output 'hide)))))
2523
2524(defvar idlwave-shell-examine-window-alist nil
2525 "Variable to hold the win/height pairs for all *Examine* windows.")
2526
2527(defun idlwave-shell-examine-display ()
2528 "View the examine command output in a separate buffer."
2529 (let (win cur-beg cur-end)
2530 (save-excursion
2531 (set-buffer (get-buffer-create "*Examine*"))
2532 (use-local-map idlwave-shell-examine-map)
2533 (setq buffer-read-only nil)
2534 (goto-char (point-max))
2535 (save-restriction
2536 (narrow-to-region (point) (point))
2537 (if (string-match "^% Syntax error." idlwave-shell-command-output)
2538 (insert "% Syntax error.\n")
2539 (insert idlwave-shell-command-output)
2540 ;; Just take the last bit between the prompts (if more than one).
2541 (let* ((end (or
2542 (re-search-backward idlwave-shell-prompt-pattern nil t)
2543 (point-max)))
13ae1076 2544 (beg (progn
5e72c6b2 2545 (goto-char
13ae1076 2546 (or (progn (if (re-search-backward
5e72c6b2
S
2547 idlwave-shell-prompt-pattern nil t)
2548 (match-end 0)))
2549 (point-min)))
2550 (re-search-forward "\n")))
2551 (str (buffer-substring beg end)))
2552 (delete-region (point-min) (point-max))
2553 (insert str)
2554 (if idlwave-shell-examine-label
2555 (progn (goto-char (point-min))
2556 (insert idlwave-shell-examine-label)
2557 (setq idlwave-shell-examine-label nil)))))
2558 (setq cur-beg (point-min)
2559 cur-end (point-max))
2560 (setq buffer-read-only t)
2561 (move-overlay idlwave-shell-output-overlay cur-beg cur-end
2562 (current-buffer))
13ae1076 2563
5e72c6b2
S
2564 ;; Look for the examine buffer in all windows. If one is
2565 ;; found in a frame all by itself, use that, otherwise, switch
2566 ;; to or create an examine window in this frame, and resize if
2567 ;; it's a newly created window
2568 (let* ((winlist (get-buffer-window-list "*Examine*" nil 'visible)))
13ae1076
JB
2569 (setq win (idlwave-display-buffer
2570 "*Examine*"
5e72c6b2
S
2571 nil
2572 (let ((list winlist) thiswin)
2573 (catch 'exit
2574 (save-selected-window
2575 (while (setq thiswin (pop list))
2576 (select-window thiswin)
13ae1076 2577 (if (one-window-p)
5e72c6b2
S
2578 (throw 'exit (window-frame thiswin)))))))))
2579 (set-window-start win (point-min)) ; Ensure the point is visible.
2580 (save-selected-window
2581 (select-window win)
2582 (let ((elt (assoc win idlwave-shell-examine-window-alist)))
2583 (when (and (not (one-window-p))
2584 (or (not (memq win winlist)) ;a newly created window
2585 (eq (window-height) (cdr elt))))
2586 ;; Autosize it.
2587 (enlarge-window (- (/ (frame-height) 2)
2588 (window-height)))
2589 (shrink-window-if-larger-than-buffer)
2590 ;; Clean the window list of dead windows
2591 (setq idlwave-shell-examine-window-alist
2592 (delq nil
2593 (mapcar (lambda (x) (if (window-live-p (car x)) x))
2594 idlwave-shell-examine-window-alist)))
2595 ;; And add the new value.
2596 (if (setq elt (assoc win idlwave-shell-examine-window-alist))
2597 (setcdr elt (window-height))
13ae1076 2598 (add-to-list 'idlwave-shell-examine-window-alist
5e72c6b2
S
2599 (cons win (window-height)))))))))
2600 ;; Recenter for maximum output, after widened
2601 (save-selected-window
2602 (select-window win)
2603 (goto-char (point-max))
2604 (skip-chars-backward "\n")
2605 (recenter -1)))))
2606
2607(defvar idlwave-shell-examine-map (make-sparse-keymap))
2608(define-key idlwave-shell-examine-map "q" 'idlwave-shell-examine-display-quit)
2609(define-key idlwave-shell-examine-map "c" 'idlwave-shell-examine-display-clear)
2610
2611(defun idlwave-shell-examine-display-quit ()
2612 (interactive)
2613 (let ((win (selected-window)))
2614 (if (one-window-p)
2615 (delete-frame (window-frame win))
2616 (delete-window win))))
2617
2618(defun idlwave-shell-examine-display-clear ()
2619 (interactive)
13ae1076 2620 (save-excursion
5e72c6b2
S
2621 (let ((buf (get-buffer "*Examine*")))
2622 (when (bufferp buf)
2623 (set-buffer buf)
2624 (setq buffer-read-only nil)
2625 (erase-buffer)
2626 (setq buffer-read-only t)))))
ca660d22
CD
2627
2628(defun idlwave-retrieve-expression-from-level (expr level routine help)
2629 "Return IDL command to print the expression EXPR from stack level LEVEL.
2630
2631It does not seem possible to evaluate an expression on a differnt
2632level than the current. Therefore, this function retrieves *copies* of
2633the variables involved in the expression from the desired level in the
2634calling stack. The copies are given some unlikely names on the
2635*current* level, and the expression is then evaluated on the *current*
2636level.
2637
2638Since this function depends upon the undocumented IDL routine routine_names,
5e72c6b2 2639there is no guarantee that this will work with future versions of IDL."
ca660d22
CD
2640 (let ((prefix "___") ;; No real variables should starts with this.
2641 (fetch (- 0 level))
2642 (start 0)
2643 var tvar fetch-vars pre post)
2644
2645 ;; FIXME: In the following we try to find the variables in expression
5e72c6b2
S
2646 ;; This is quite empirical - I don't know in what situations this will
2647 ;; break. We will look for identifiers and exclude cases where we
2648 ;; know it is not a variable. To distinguish array references from
2649 ;; function calls, we require that arrays use [] instead of ()
13ae1076 2650
5e72c6b2
S
2651 (while (string-match
2652 "\\(\\`\\|[^a-zA-Z0-9$_]\\)\\([a-zA-Z][a-zA-Z0-9$_]*\\)\\([^a-zA-Z0-9$_]\\|\\'\\)" expr start)
2653 (setq var (match-string 2 expr)
2654 tvar (concat prefix var)
2655 start (match-beginning 2)
2656 pre (substring expr 0 (match-beginning 2))
2657 post (substring expr (match-end 2)))
2658 (cond
2659 ;; Exclude identifiers which are not variables
2660 ((string-match ",[ \t]*/\\'" pre)) ;; a `/' KEYWORD
2661 ((and (string-match "[,(][ \t]*\\'" pre)
2662 (string-match "\\`[ \t]*=" post))) ;; a `=' KEYWORD
2663 ((string-match "\\`(" post)) ;; a function
2664 ((string-match "->[ \t]*\\'" pre)) ;; a method
2665 ((string-match "\\.\\'" pre)) ;; structure member
2666 (t ;; seems to be a variable - arrange to get it and replace
2667 ;; its name in the expression with the temproary name.
2668 (push (cons var tvar) fetch-vars)
2669 (setq expr (concat pre tvar post))))
2670 (if (= start 0) (setq start 1)))
ca660d22
CD
2671 ;; Make a command line that first copies the relevant variables
2672 ;; and then prints the expression.
2673 (concat
2674 (mapconcat
2675 (lambda (x)
2676 (format "%s = routine_names('%s',fetch=%d)" (cdr x) (car x) fetch))
2677 (nreverse fetch-vars)
2678 " & ")
5e72c6b2
S
2679 "\n"
2680 (idlwave-shell-help-statement help expr)
ca660d22 2681 (format " ; [-%d:%s]" level routine))))
8c7b4ec8 2682
5e72c6b2
S
2683(defun idlwave-shell-help-statement (help expr)
2684 "Construct a help statement for printing expression EXPR.
2685
2686HELP can be non-nil for `help,', nil for 'print,' or any string into which
2687to insert expression in place of the marker ___, e.g.: print,
2688size(___,/DIMENSIONS)"
2689 (cond
2690 ((null help) (concat "print, " expr))
13ae1076 2691 ((stringp help)
5e72c6b2
S
2692 (if (string-match "\\(^\\|[^_]\\)\\(___\\)\\([^_]\\|$\\)" help)
2693 (concat (substring help 0 (match-beginning 2))
2694 expr
2695 (substring help (match-end 2)))))
2696 (t (concat "help, " expr))))
13ae1076 2697
5e72c6b2
S
2698
2699(defun idlwave-shell-examine-highlight ()
2700 "Highlight the most recent IDL output."
2701 (let* ((buffer (get-buffer (idlwave-shell-buffer)))
2702 (process (get-buffer-process buffer))
2703 (process-mark (if process (process-mark process)))
2704 output-begin output-end)
13ae1076 2705 (save-excursion
5e72c6b2
S
2706 (set-buffer buffer)
2707 (goto-char process-mark)
2708 (beginning-of-line)
2709 (setq output-end (point))
2710 (re-search-backward idlwave-shell-prompt-pattern nil t)
2711 (beginning-of-line 2)
2712 (setq output-begin (point)))
13ae1076 2713
5e72c6b2
S
2714 ;; First make sure the shell window is visible
2715 (idlwave-display-buffer (idlwave-shell-buffer)
2716 nil (idlwave-shell-shell-frame))
2717 (if (and idlwave-shell-output-overlay process-mark)
13ae1076 2718 (move-overlay idlwave-shell-output-overlay
5e72c6b2
S
2719 output-begin output-end buffer))))
2720
2721(defun idlwave-shell-delete-output-overlay ()
2722 (if (eq this-command 'idlwave-shell-mouse-nop)
2723 nil
2724 (condition-case nil
2725 (if idlwave-shell-output-overlay
2726 (delete-overlay idlwave-shell-output-overlay))
2727 (error nil))
2728 (remove-hook 'pre-command-hook 'idlwave-shell-delete-output-overlay)))
13ae1076 2729
8c7b4ec8 2730(defun idlwave-shell-delete-expression-overlay ()
5e72c6b2
S
2731 (if (eq this-command 'idlwave-shell-mouse-nop)
2732 nil
2733 (condition-case nil
2734 (if idlwave-shell-expression-overlay
2735 (delete-overlay idlwave-shell-expression-overlay))
2736 (error nil))
2737 (remove-hook 'pre-command-hook 'idlwave-shell-delete-expression-overlay)))
8c7b4ec8
EZ
2738
2739(defvar idlwave-shell-bp-alist nil
2740 "Alist of breakpoints.
2741A breakpoint is a cons cell \(\(file line\) . \(\(index module\) data\)\)
2742
2743The car is the frame for the breakpoint:
2744file - full path file name.
2745line - line number of breakpoint - integer.
2746
2747The first element of the cdr is a list of internal IDL data:
2748index - the index number of the breakpoint internal to IDL.
2749module - the module for breakpoint internal to IDL.
2750
2751Remaining elements of the cdr:
2752data - Data associated with the breakpoint by idlwave-shell currently
2753contains two items:
2754
2755count - number of times to execute breakpoint. When count reaches 0
2756the breakpoint is cleared and removed from the alist.
13ae1076 2757command - command to execute when breakpoint is reached, either a
8c7b4ec8
EZ
2758lisp function to be called with `funcall' with no arguments or a
2759list to be evaluated with `eval'.")
2760
2761(defun idlwave-shell-run-region (beg end &optional n)
2762 "Compile and run the region using the IDL process.
2763Copies the region to a temporary file `idlwave-shell-temp-pro-file'
2764and issues the IDL .run command for the file. Because the
2765region is compiled and run as a main program there is no
2766problem with begin-end blocks extending over multiple
2767lines - which would be a problem if `idlwave-shell-evaluate-region'
2768was used. An END statement is appended to the region if necessary.
2769
2770If there is a prefix argument, display IDL process."
2771 (interactive "r\nP")
2772 (let ((oldbuf (current-buffer)))
2773 (save-excursion
2774 (set-buffer (idlwave-find-file-noselect
5e72c6b2
S
2775 (idlwave-shell-temp-file 'pro) 'tmp))
2776 (set (make-local-variable 'comment-start-skip) ";+[ \t]*")
2777 (set (make-local-variable 'comment-start) ";")
8c7b4ec8
EZ
2778 (erase-buffer)
2779 (insert-buffer-substring oldbuf beg end)
2780 (if (not (save-excursion
2781 (idlwave-previous-statement)
2782 (idlwave-look-at "\\<end\\>")))
2783 (insert "\nend\n"))
2784 (save-buffer 0)))
76959b77
S
2785 (idlwave-shell-send-command (concat ".run " idlwave-shell-temp-pro-file)
2786 nil (idlwave-shell-hide-p 'run))
8c7b4ec8 2787 (if n
13ae1076 2788 (idlwave-display-buffer (idlwave-shell-buffer)
8c7b4ec8
EZ
2789 nil (idlwave-shell-shell-frame))))
2790
2791(defun idlwave-shell-evaluate-region (beg end &optional n)
2792 "Send region to the IDL process.
2793If there is a prefix argument, display IDL process.
2794Does not work for a region with multiline blocks - use
2795`idlwave-shell-run-region' for this."
2796 (interactive "r\nP")
2797 (idlwave-shell-send-command (buffer-substring beg end))
2798 (if n
13ae1076 2799 (idlwave-display-buffer (idlwave-shell-buffer)
8c7b4ec8
EZ
2800 nil (idlwave-shell-shell-frame))))
2801
15e42531
CD
2802(defun idlwave-shell-delete-temp-files ()
2803 "Delete the temporary files and kill associated buffers."
2804 (if (stringp idlwave-shell-temp-pro-file)
2805 (condition-case nil
2806 (let ((buf (idlwave-get-buffer-visiting
2807 idlwave-shell-temp-pro-file)))
2808 (if (buffer-live-p buf)
2809 (kill-buffer buf))
2810 (delete-file idlwave-shell-temp-pro-file))
2811 (error nil)))
2812 (if (stringp idlwave-shell-temp-rinfo-save-file)
2813 (condition-case nil
2814 (delete-file idlwave-shell-temp-rinfo-save-file)
2815 (error nil))))
2816
8c7b4ec8 2817(defun idlwave-display-buffer (buf not-this-window-p &optional frame)
76959b77
S
2818 (if (featurep 'xemacs)
2819 ;; The XEmacs version enforces the frame
2820 (display-buffer buf not-this-window-p frame)
2821 ;; For Emacs, we need to force the frame ourselves.
2822 (let ((this-frame (selected-frame)))
2823 (if (frame-live-p frame)
2824 (select-frame frame))
2825 (if (eq this-frame (selected-frame))
2826 ;; same frame: use display buffer, to make sure the current
2827 ;; window stays.
2828 (display-buffer buf)
2829 ;; different frame
2830 (if (one-window-p)
2831 ;; only window: switch
2832 (progn
2833 (switch-to-buffer buf)
2834 (selected-window)) ; must return the window.
2835 ;; several windows - use display-buffer
2836 (display-buffer buf not-this-window-p))))))
2837; (if (not (frame-live-p frame)) (setq frame nil))
2838; (display-buffer buf not-this-window-p frame))
8c7b4ec8 2839
15e42531 2840(defvar idlwave-shell-bp-buffer " *idlwave-shell-bp*"
8c7b4ec8
EZ
2841 "Scratch buffer for parsing IDL breakpoint lists and other stuff.")
2842
2843(defun idlwave-shell-bp-query ()
2844 "Reconcile idlwave-shell's breakpoint list with IDL's.
2845Queries IDL using the string in `idlwave-shell-bp-query'."
2846 (interactive)
2847 (idlwave-shell-send-command idlwave-shell-bp-query
2848 'idlwave-shell-filter-bp
2849 'hide))
2850
2851(defun idlwave-shell-bp-get (bp &optional item)
2852 "Get a value for a breakpoint.
2853BP has the form of elements in idlwave-shell-bp-alist.
2854Optional second arg ITEM is the particular value to retrieve.
2855ITEM can be 'file, 'line, 'index, 'module, 'count, 'cmd, or 'data.
2856'data returns a list of 'count and 'cmd.
2857Defaults to 'index."
2858 (cond
2859 ;; Frame
2860 ((eq item 'line) (nth 1 (car bp)))
2861 ((eq item 'file) (nth 0 (car bp)))
2862 ;; idlwave-shell breakpoint data
2863 ((eq item 'data) (cdr (cdr bp)))
2864 ((eq item 'count) (nth 0 (cdr (cdr bp))))
2865 ((eq item 'cmd) (nth 1 (cdr (cdr bp))))
76959b77 2866 ((eq item 'condition) (nth 2 (cdr (cdr bp))))
8c7b4ec8
EZ
2867 ;; IDL breakpoint info
2868 ((eq item 'module) (nth 1 (car (cdr bp))))
2869 ;; index - default
2870 (t (nth 0 (car (cdr bp))))))
2871
2872(defun idlwave-shell-filter-bp ()
2873 "Get the breakpoints from `idlwave-shell-command-output'.
2874Create `idlwave-shell-bp-alist' updating breakpoint count and command data
2875from previous breakpoint list."
2876 (save-excursion
2877 (set-buffer (get-buffer-create idlwave-shell-bp-buffer))
2878 (erase-buffer)
2879 (insert idlwave-shell-command-output)
2880 (goto-char (point-min))
15e42531 2881 (let ((old-bp-alist idlwave-shell-bp-alist)
5e72c6b2
S
2882 ;; Searching the breakpoints
2883 ;; In IDL 5.5, the breakpoint reporting format changed.
2884 (bp-re54 "^[ \t]*\\([0-9]+\\)[ \t]+\\(\\S-+\\)?[ \t]+\\([0-9]+\\)[ \t]+\\(\\S-+\\)")
76959b77 2885 (bp-re55 "^\\s-*\\([0-9]+\\)\\s-+\\([0-9]+\\)\\s-+\\(Uncompiled\\|Func=\\|Pro=\\)\\([a-zA-Z][a-zA-Z0-9$_:]*\\)\\(,[^\n]*\n\\)?\\s-+\\(\\S-+\\)")
13ae1076 2886 file line index module
5e72c6b2 2887 bp-re indmap)
8c7b4ec8 2888 (setq idlwave-shell-bp-alist (list nil))
5e72c6b2 2889 ;; Search for either header type, and set the correct regexp
13ae1076 2890 (when (or
5e72c6b2 2891 (if (re-search-forward "^\\s-*Index.*\n\\s-*-" nil t)
13ae1076 2892 (setq bp-re bp-re54 ; versions <= 5.4
5e72c6b2 2893 indmap '(1 2 3 4)))
13ae1076 2894 (if (re-search-forward
5e72c6b2
S
2895 "^\\s-*Index\\s-*Line\\s-*Attributes\\s-*File" nil t)
2896 (setq bp-re bp-re55 ; versions >= 5.5
76959b77 2897 indmap '(1 4 2 6))))
15e42531
CD
2898 ;; There seems to be a breakpoint listing here.
2899 ;; Parse breakpoint lines.
13ae1076 2900 ;; Breakpoints have the form
5e72c6b2 2901 ;; for IDL<=v5.4:
15e42531 2902 ;; Index Module Line File
13ae1076 2903 ;; All separated by whitespace.
15e42531 2904 ;; Module may be missing if the file is not compiled.
5e72c6b2
S
2905 ;; for IDL>=v5.5:
2906 ;; Index Line Attributes File
2907 ;; (attributes replaces module, "Uncompiled" included)
2908 (while (re-search-forward bp-re nil t)
2909 (setq index (match-string (nth 0 indmap))
2910 module (match-string (nth 1 indmap))
2911 line (string-to-int (match-string (nth 2 indmap)))
2912 file (idlwave-shell-file-name (match-string (nth 3 indmap))))
15e42531
CD
2913 ;; Add the breakpoint info to the list
2914 (nconc idlwave-shell-bp-alist
2915 (list (cons (list file line)
2916 (list
2917 (list index module)
2918 ;; idlwave-shell data: count, command
2919 nil nil))))))
8c7b4ec8
EZ
2920 (setq idlwave-shell-bp-alist (cdr idlwave-shell-bp-alist))
2921 ;; Update count, commands of breakpoints
2922 (mapcar 'idlwave-shell-update-bp old-bp-alist)))
2923 ;; Update the breakpoint overlays
2924 (idlwave-shell-update-bp-overlays)
2925 ;; Return the new list
2926 idlwave-shell-bp-alist)
2927
2928(defun idlwave-shell-update-bp (bp)
2929 "Update BP data in breakpoint list.
2930If BP frame is in `idlwave-shell-bp-alist' updates the breakpoint data."
2931 (let ((match (assoc (car bp) idlwave-shell-bp-alist)))
2932 (if match (setcdr (cdr match) (cdr (cdr bp))))))
2933
2934(defun idlwave-shell-set-bp-data (bp data)
2935 "Set the data of BP to DATA."
2936 (setcdr (cdr bp) data))
2937
2938(defun idlwave-shell-bp (frame &optional data module)
2939 "Create a breakpoint structure containing FRAME and DATA. Second
2940and third args, DATA and MODULE, are optional. Returns a breakpoint
2941of the format used in `idlwave-shell-bp-alist'. Can be used in commands
2942attempting match a breakpoint in `idlwave-shell-bp-alist'."
2943 (cons frame (cons (list nil module) data)))
2944
2945(defvar idlwave-shell-old-bp nil
2946 "List of breakpoints previous to setting a new breakpoint.")
2947
2948(defun idlwave-shell-sources-bp (bp)
2949 "Check `idlwave-shell-sources-alist' for source of breakpoint using BP.
2950If an equivalency is found, return the IDL internal source name.
2951Otherwise return the filename in bp."
2952 (let*
2953 ((bp-file (idlwave-shell-bp-get bp 'file))
2954 (bp-module (idlwave-shell-bp-get bp 'module))
2955 (internal-file-list (cdr (assoc bp-module idlwave-shell-sources-alist))))
2956 (if (and internal-file-list
2957 (equal bp-file (nth 0 internal-file-list)))
2958 (nth 1 internal-file-list)
2959 bp-file)))
2960
2961(defun idlwave-shell-set-bp (bp)
2962 "Try to set a breakpoint BP.
2963
2964The breakpoint will be placed at the beginning of the statement on the
2965line specified by BP or at the next IDL statement if that line is not
2966a statement.
76959b77 2967Determines IDL's internal representation for the breakpoint which may
13ae1076 2968have occurred at a different line then used with the breakpoint
8c7b4ec8 2969command."
13ae1076 2970
8c7b4ec8 2971 ;; Get and save the old breakpoints
13ae1076 2972 (idlwave-shell-send-command
8c7b4ec8
EZ
2973 idlwave-shell-bp-query
2974 '(progn
5e72c6b2
S
2975 (idlwave-shell-filter-bp)
2976 (setq idlwave-shell-old-bp idlwave-shell-bp-alist))
8c7b4ec8
EZ
2977 'hide)
2978 ;; Get sources for IDL compiled procedures followed by setting
2979 ;; breakpoint.
2980 (idlwave-shell-send-command
2981 idlwave-shell-sources-query
8a946354 2982 `(progn
5e72c6b2
S
2983 (idlwave-shell-sources-filter)
2984 (idlwave-shell-set-bp2 (quote ,bp)))
8c7b4ec8
EZ
2985 'hide))
2986
2987(defun idlwave-shell-set-bp2 (bp)
2988 "Use results of breakpoint and sources query to set bp.
2989Use the count argument with IDLs breakpoint command.
13ae1076 2990We treat a count of 1 as a temporary breakpoint.
8c7b4ec8
EZ
2991Counts greater than 1 use the IDL AFTER=count keyword to break
2992only after reaching the statement count times."
2993 (let*
2994 ((arg (idlwave-shell-bp-get bp 'count))
2995 (key (cond
8a946354
SS
2996 ((not (and arg (numberp arg))) "")
2997 ((= arg 1)
2998 ",/once")
2999 ((> arg 1)
3000 (format ",after=%d" arg))))
76959b77 3001 (condition (idlwave-shell-bp-get bp 'condition))
13ae1076 3002 (key (concat key
76959b77 3003 (if condition (concat ",CONDITION=\"" condition "\""))))
8c7b4ec8
EZ
3004 (line (idlwave-shell-bp-get bp 'line)))
3005 (idlwave-shell-send-command
13ae1076 3006 (concat "breakpoint,'"
8c7b4ec8
EZ
3007 (idlwave-shell-sources-bp bp) "',"
3008 (if (integerp line) (setq line (int-to-string line)))
3009 key)
3010 ;; Check for failure and look for breakpoint in IDL's list
8a946354
SS
3011 `(progn
3012 (if (idlwave-shell-set-bp-check (quote ,bp))
3013 (idlwave-shell-set-bp3 (quote ,bp))))
76959b77
S
3014 ;; hide output?
3015 (idlwave-shell-hide-p 'breakpoint)
8c7b4ec8
EZ
3016 'preempt)))
3017
3018(defun idlwave-shell-set-bp3 (bp)
3019 "Find the breakpoint in IDL's internal list of breakpoints."
3020 (idlwave-shell-send-command idlwave-shell-bp-query
8a946354
SS
3021 `(progn
3022 (idlwave-shell-filter-bp)
3023 (idlwave-shell-new-bp (quote ,bp)))
8c7b4ec8
EZ
3024 'hide
3025 'preempt))
3026
3027(defun idlwave-shell-find-bp (frame)
3028 "Return breakpoint from `idlwave-shell-bp-alist' for frame.
3029Returns nil if frame not found."
3030 (assoc frame idlwave-shell-bp-alist))
3031
3032(defun idlwave-shell-new-bp (bp)
3033 "Find the new breakpoint in IDL's list and update with DATA.
3034The actual line number for a breakpoint in IDL may be different than
3035the line number used with the IDL breakpoint command.
3036Looks for a new breakpoint index number in the list. This is
3037considered the new breakpoint if the file name of frame matches."
3038 (let ((obp-index (mapcar 'idlwave-shell-bp-get idlwave-shell-old-bp))
3039 (bpl idlwave-shell-bp-alist))
3040 (while (and (member (idlwave-shell-bp-get (car bpl)) obp-index)
3041 (setq bpl (cdr bpl))))
3042 (if (and
3043 (not bpl)
3044 ;; No additional breakpoint.
3045 ;; Need to check if we are just replacing a breakpoint.
3046 (setq bpl (assoc (car bp) idlwave-shell-bp-alist)))
3047 (setq bpl (list bpl)))
3048 (if (and bpl
3049 (equal (idlwave-shell-bp-get (setq bpl (car bpl)) 'file)
3050 (idlwave-shell-bp-get bp 'file)))
3051 ;; Got the breakpoint - add count, command to it.
3052 ;; This updates `idlwave-shell-bp-alist' because a deep copy was
3053 ;; not done for bpl.
3054 (idlwave-shell-set-bp-data bpl (idlwave-shell-bp-get bp 'data))
3055 (beep)
3056 (message "Failed to identify breakpoint in IDL"))))
3057
3058(defvar idlwave-shell-bp-overlays nil
3059 "List of overlays marking breakpoints")
3060
3061(defun idlwave-shell-update-bp-overlays ()
3062 "Update the overlays which mark breakpoints in the source code.
3063Existing overlays are recycled, in order to minimize consumption."
8c7b4ec8
EZ
3064 (when idlwave-shell-mark-breakpoints
3065 (let ((bp-list idlwave-shell-bp-alist)
3066 (ov-list idlwave-shell-bp-overlays)
3067 ov bp)
3068 ;; Delete the old overlays from their buffers
3069 (while (setq ov (pop ov-list))
3070 (delete-overlay ov))
3071 (setq ov-list idlwave-shell-bp-overlays
3072 idlwave-shell-bp-overlays nil)
3073 (while (setq bp (pop bp-list))
3074 (save-excursion
3075 (idlwave-shell-goto-frame (car bp))
3076 (let* ((end (progn (end-of-line 1) (point)))
3077 (beg (progn (beginning-of-line 1) (point)))
3078 (ov (or (pop ov-list)
3079 (idlwave-shell-make-new-bp-overlay))))
3080 (move-overlay ov beg end)
3081 (push ov idlwave-shell-bp-overlays)))))))
3082
3083(defvar idlwave-shell-bp-glyph)
3084(defun idlwave-shell-make-new-bp-overlay ()
3085 "Make a new overlay for highlighting breakpoints.
3086This stuff is stringly dependant upon the version of Emacs."
3087 (let ((ov (make-overlay 1 1)))
3088 (if (featurep 'xemacs)
3089 ;; This is XEmacs
3090 (progn
13ae1076 3091 (cond
8c7b4ec8
EZ
3092 ((eq (console-type) 'tty)
3093 ;; tty's cannot display glyphs
15e42531 3094 (set-extent-property ov 'face idlwave-shell-breakpoint-face))
8c7b4ec8
EZ
3095 ((and (memq idlwave-shell-mark-breakpoints '(t glyph))
3096 idlwave-shell-bp-glyph)
3097 ;; use the glyph
3098 (set-extent-property ov 'begin-glyph idlwave-shell-bp-glyph))
3099 (idlwave-shell-mark-breakpoints
3100 ;; use the face
15e42531 3101 (set-extent-property ov 'face idlwave-shell-breakpoint-face))
13ae1076 3102 (t
8c7b4ec8
EZ
3103 ;; no marking
3104 nil))
3105 (set-extent-priority ov -1)) ; make stop line face prevail
3106 ;; This is Emacs
3107 (cond
3108 (window-system
3109 (if (and (memq idlwave-shell-mark-breakpoints '(t glyph))
3110 idlwave-shell-bp-glyph) ; this var knows if glyph's possible
3111 ;; use a glyph
3112 (let ((string "@"))
3113 (put-text-property 0 1
ca660d22 3114 'display idlwave-shell-bp-glyph
8c7b4ec8
EZ
3115 string)
3116 (overlay-put ov 'before-string string))
15e42531 3117 (overlay-put ov 'face idlwave-shell-breakpoint-face)))
8c7b4ec8
EZ
3118 (idlwave-shell-mark-breakpoints
3119 ;; use a face
15e42531 3120 (overlay-put ov 'face idlwave-shell-breakpoint-face))
13ae1076 3121 (t
8c7b4ec8
EZ
3122 ;; No marking
3123 nil)))
3124 ov))
3125
3126(defun idlwave-shell-edit-default-command-line (arg)
3127 "Edit the current execute command."
3128 (interactive "P")
3129 (setq idlwave-shell-command-line-to-execute
3130 (read-string "IDL> " idlwave-shell-command-line-to-execute)))
3131
3132(defun idlwave-shell-execute-default-command-line (arg)
3133 "Execute a command line. On first use, ask for the command.
3134Also with prefix arg, ask for the command. You can also uase the command
3135`idlwave-shell-edit-default-command-line' to edit the line."
3136 (interactive "P")
3137 (if (or (not idlwave-shell-command-line-to-execute)
3138 arg)
13ae1076 3139 (setq idlwave-shell-command-line-to-execute
8c7b4ec8 3140 (read-string "IDL> " idlwave-shell-command-line-to-execute)))
ca660d22 3141 (idlwave-shell-reset 'hidden)
8c7b4ec8
EZ
3142 (idlwave-shell-send-command idlwave-shell-command-line-to-execute
3143 '(idlwave-shell-redisplay 'hide)))
3144
3145(defun idlwave-shell-save-and-run ()
3146 "Save file and run it in IDL.
3147Runs `save-buffer' and sends a '.RUN' command for the associated file to IDL.
3148When called from the shell buffer, re-run the file which was last handled by
13ae1076 3149one of the save-and-.. commands."
8c7b4ec8
EZ
3150 (interactive)
3151 (idlwave-shell-save-and-action 'run))
3152
3153(defun idlwave-shell-save-and-compile ()
3154 "Save file and run it in IDL.
3155Runs `save-buffer' and sends '.COMPILE' command for the associated file to IDL.
3156When called from the shell buffer, re-compile the file which was last handled by
3157one of the save-and-.. commands."
3158 (interactive)
3159 (idlwave-shell-save-and-action 'compile))
3160
3161(defun idlwave-shell-save-and-batch ()
3162 "Save file and batch it in IDL.
3163Runs `save-buffer' and sends a '@file' command for the associated file to IDL.
3164When called from the shell buffer, re-batch the file which was last handled by
13ae1076 3165one of the save-and-.. commands."
8c7b4ec8
EZ
3166 (interactive)
3167 (idlwave-shell-save-and-action 'batch))
3168
3169(defun idlwave-shell-save-and-action (action)
3170 "Save file and compile it in IDL.
3171Runs `save-buffer' and sends a '.RUN' command for the associated file to IDL.
3172When called from the shell buffer, re-compile the file which was last
3173handled by this command."
3174 ;; Remove the stop overlay.
3175 (if idlwave-shell-stop-line-overlay
3176 (delete-overlay idlwave-shell-stop-line-overlay))
15e42531 3177 (setq idlwave-shell-is-stopped nil)
8c7b4ec8
EZ
3178 (setq overlay-arrow-string nil)
3179 (let (buf)
3180 (cond
3181 ((eq major-mode 'idlwave-mode)
3182 (save-buffer)
3183 (setq idlwave-shell-last-save-and-action-file (buffer-file-name)))
3184 (idlwave-shell-last-save-and-action-file
3185 (if (setq buf (idlwave-get-buffer-visiting
3186 idlwave-shell-last-save-and-action-file))
3187 (save-excursion
3188 (set-buffer buf)
3189 (save-buffer))))
3190 (t (setq idlwave-shell-last-save-and-action-file
3191 (read-file-name "File: ")))))
3192 (if (file-regular-p idlwave-shell-last-save-and-action-file)
3193 (progn
3194 (idlwave-shell-send-command
3195 (concat (cond ((eq action 'run) ".run ")
3196 ((eq action 'compile) ".compile ")
3197 ((eq action 'batch) "@")
3198 (t (error "Unknown action %s" action)))
3199 idlwave-shell-last-save-and-action-file)
15e42531 3200 'idlwave-shell-maybe-update-routine-info
76959b77 3201 (idlwave-shell-hide-p 'run))
8c7b4ec8 3202 (idlwave-shell-bp-query))
13ae1076 3203 (let ((msg (format "No such file %s"
8c7b4ec8
EZ
3204 idlwave-shell-last-save-and-action-file)))
3205 (setq idlwave-shell-last-save-and-action-file nil)
3206 (error msg))))
3207
76959b77 3208(defun idlwave-shell-maybe-update-routine-info (&optional wait)
15e42531
CD
3209 "Update the routine info if the shell is not stopped at an error."
3210 (if (and (not idlwave-shell-is-stopped)
3211 (or (eq t idlwave-auto-routine-info-updates)
3212 (memq 'compile-buffer idlwave-auto-routine-info-updates))
3213 idlwave-query-shell-for-routine-info
3214 idlwave-routines)
76959b77 3215 (idlwave-shell-update-routine-info t nil 'wait)))
15e42531 3216
5e72c6b2 3217(defvar idlwave-shell-sources-query "help,/source,/full"
8c7b4ec8
EZ
3218 "IDL command to obtain source files for compiled procedures.")
3219
3220(defvar idlwave-shell-sources-alist nil
3221 "Alist of IDL procedure names and compiled source files.
3222Elements of the alist have the form:
3223
3224 (module name . (source-file-truename idlwave-internal-filename)).")
3225
3226(defun idlwave-shell-sources-query ()
3227 "Determine source files for IDL compiled procedures.
3228Queries IDL using the string in `idlwave-shell-sources-query'."
3229 (interactive)
3230 (idlwave-shell-send-command idlwave-shell-sources-query
3231 'idlwave-shell-sources-filter
3232 'hide))
3233
3234(defun idlwave-shell-sources-filter ()
3235 "Get source files from `idlwave-shell-sources-query' output.
13ae1076 3236Create `idlwave-shell-sources-alist' consisting of
8c7b4ec8
EZ
3237list elements of the form:
3238 (module name . (source-file-truename idlwave-internal-filename))."
3239 (save-excursion
3240 (set-buffer (get-buffer-create idlwave-shell-bp-buffer))
3241 (erase-buffer)
3242 (insert idlwave-shell-command-output)
3243 (goto-char (point-min))
3244 (let (cpro cfun)
3245 (if (re-search-forward "Compiled Procedures:" nil t)
3246 (progn
3247 (forward-line) ; Skip $MAIN$
3248 (setq cpro (point))))
3249 (if (re-search-forward "Compiled Functions:" nil t)
3250 (progn
3251 (setq cfun (point))
3252 (setq idlwave-shell-sources-alist
3253 (append
3254 ;; compiled procedures
3255 (progn
3256 (beginning-of-line)
3257 (narrow-to-region cpro (point))
3258 (goto-char (point-min))
3259 (idlwave-shell-sources-grep))
3260 ;; compiled functions
3261 (progn
3262 (widen)
3263 (goto-char cfun)
3264 (idlwave-shell-sources-grep)))))))))
3265
3266(defun idlwave-shell-sources-grep ()
3267 (save-excursion
3268 (let ((al (list nil)))
3269 (while (and
3270 (not (progn (forward-line) (eobp)))
3271 (re-search-forward
3272 "\\s-*\\(\\S-+\\)\\s-+\\(\\S-+\\)" nil t))
3273 (nconc al
3274 (list
3275 (cons
3276 (buffer-substring ; name
3277 (match-beginning 1) (match-end 1))
3278 (let ((internal-filename
3279 (buffer-substring ; source
3280 (match-beginning 2) (match-end 2))))
3281 (list
3282 (idlwave-shell-file-name internal-filename)
3283 internal-filename))
3284 ))))
3285 (cdr al))))
3286
8c7b4ec8
EZ
3287(defun idlwave-shell-clear-all-bp ()
3288 "Remove all breakpoints in IDL."
3289 (interactive)
3290 (idlwave-shell-send-command
3291 idlwave-shell-bp-query
3292 '(progn
3293 (idlwave-shell-filter-bp)
3294 (mapcar 'idlwave-shell-clear-bp idlwave-shell-bp-alist))
3295 'hide))
3296
3297(defun idlwave-shell-list-all-bp ()
3298 "List all breakpoints in IDL."
3299 (interactive)
3300 (idlwave-shell-send-command
3301 idlwave-shell-bp-query))
3302
3303(defvar idlwave-shell-error-last 0
3304 "Position of last syntax error in `idlwave-shell-error-buffer'.")
3305
3306(defun idlwave-shell-goto-next-error ()
3307 "Move point to next IDL syntax error."
3308 (interactive)
3309 (let (frame col)
3310 (save-excursion
3311 (set-buffer idlwave-shell-error-buffer)
3312 (goto-char idlwave-shell-error-last)
3313 (if (or (re-search-forward idlwave-shell-syntax-error nil t)
3314 (re-search-forward idlwave-shell-other-error nil t))
3315 (progn
3316 (setq frame
3317 (list
3318 (save-match-data
3319 (idlwave-shell-file-name
3320 (buffer-substring (match-beginning 1) (match-end 1))))
3321 (string-to-int
3322 (buffer-substring (match-beginning 2)
3323 (match-end 2)))))
3324 ;; Try to find the column of the error
3325 (save-excursion
3326 (setq col
3327 (if (re-search-backward "\\^" nil t)
3328 (current-column)
3329 0)))))
3330 (setq idlwave-shell-error-last (point)))
3331 (if frame
3332 (progn
3333 (idlwave-shell-display-line frame col))
3334 (beep)
3335 (message "No more errors."))))
3336
3337(defun idlwave-shell-file-name (name)
15e42531 3338 "If `idlwave-shell-use-truename' is non-nil, convert file name to true name.
8c7b4ec8
EZ
3339Otherwise, just expand the file name."
3340 (let ((def-dir (if (eq major-mode 'idlwave-shell-mode)
3341 default-directory
3342 idlwave-shell-default-directory)))
5e72c6b2
S
3343 (if idlwave-shell-use-truename
3344 (file-truename name def-dir)
8c7b4ec8
EZ
3345 (expand-file-name name def-dir))))
3346
8c7b4ec8
EZ
3347;; Keybindings --------------------------------------------------------------
3348
3349(defvar idlwave-shell-mode-map (copy-keymap comint-mode-map)
3350 "Keymap for idlwave-mode.")
3351(defvar idlwave-shell-mode-prefix-map (make-sparse-keymap))
3352(fset 'idlwave-shell-mode-prefix-map idlwave-shell-mode-prefix-map)
3353
3354;(define-key idlwave-shell-mode-map "\M-?" 'comint-dynamic-list-completions)
3355;(define-key idlwave-shell-mode-map "\t" 'comint-dynamic-complete)
3356(define-key idlwave-shell-mode-map "\t" 'idlwave-shell-complete)
3357(define-key idlwave-shell-mode-map "\M-\t" 'idlwave-shell-complete)
3358(define-key idlwave-shell-mode-map "\C-c\C-s" 'idlwave-shell)
3359(define-key idlwave-shell-mode-map "\C-c?" 'idlwave-routine-info)
76959b77 3360(define-key idlwave-shell-mode-map "\C-g" 'idlwave-keyboard-quit)
15e42531 3361(define-key idlwave-shell-mode-map "\M-?" 'idlwave-context-help)
76959b77 3362(define-key idlwave-shell-mode-map [(control meta ?\?)] 'idlwave-online-help)
8c7b4ec8 3363(define-key idlwave-shell-mode-map "\C-c\C-i" 'idlwave-update-routine-info)
15e42531
CD
3364(define-key idlwave-shell-mode-map "\C-c\C-y" 'idlwave-shell-char-mode-loop)
3365(define-key idlwave-shell-mode-map "\C-c\C-x" 'idlwave-shell-send-char)
8c7b4ec8
EZ
3366(define-key idlwave-shell-mode-map "\C-c=" 'idlwave-resolve)
3367(define-key idlwave-shell-mode-map "\C-c\C-v" 'idlwave-find-module)
15e42531 3368(define-key idlwave-shell-mode-map "\C-c\C-k" 'idlwave-kill-autoloaded-buffers)
8c7b4ec8
EZ
3369(define-key idlwave-shell-mode-map idlwave-shell-prefix-key
3370 'idlwave-shell-debug-map)
05a1abfc
CD
3371(define-key idlwave-shell-mode-map [(up)] 'idlwave-shell-up-or-history)
3372(define-key idlwave-shell-mode-map [(down)] 'idlwave-shell-down-or-history)
15e42531
CD
3373(define-key idlwave-mode-map "\C-c\C-y" 'idlwave-shell-char-mode-loop)
3374(define-key idlwave-mode-map "\C-c\C-x" 'idlwave-shell-send-char)
5e72c6b2
S
3375
3376;; The mouse bindings for PRINT and HELP
3377(idlwave-shell-define-key-both
13ae1076
JB
3378 (if (featurep 'xemacs)
3379 [(shift button2)]
5e72c6b2
S
3380 [(shift down-mouse-2)])
3381 'idlwave-shell-mouse-print)
3382(idlwave-shell-define-key-both
13ae1076
JB
3383 (if (featurep 'xemacs)
3384 [(control meta button2)]
5e72c6b2 3385 [(control meta down-mouse-2)])
15e42531 3386 'idlwave-shell-mouse-help)
5e72c6b2
S
3387(idlwave-shell-define-key-both
3388 (if (featurep 'xemacs)
3389 [(control shift button2)]
3390 [(control shift down-mouse-2)])
3391 'idlwave-shell-examine-select)
3392;; Add this one from the idlwave-mode-map
13ae1076 3393(define-key idlwave-shell-mode-map
5e72c6b2
S
3394 (if (featurep 'xemacs)
3395 [(shift button3)]
3396 [(shift mouse-3)])
15e42531
CD
3397 'idlwave-mouse-context-help)
3398
5e72c6b2 3399;; For Emacs, we need to turn off the button release events.
13ae1076 3400(defun idlwave-shell-mouse-nop (event)
5e72c6b2
S
3401 (interactive "e"))
3402(unless (featurep 'xemacs)
3403 (idlwave-shell-define-key-both
3404 [(shift mouse-2)] 'idlwave-shell-mouse-nop)
3405 (idlwave-shell-define-key-both
3406 [(shift control mouse-2)] 'idlwave-shell-mouse-nop)
3407 (idlwave-shell-define-key-both
3408 [(control meta mouse-2)] 'idlwave-shell-mouse-nop))
8c7b4ec8 3409
13ae1076 3410
8c7b4ec8
EZ
3411;; The following set of bindings is used to bind the debugging keys.
3412;; If `idlwave-shell-activate-prefix-keybindings' is non-nil, the first key
3413;; in the list gets bound the C-c C-d prefix map.
05a1abfc 3414;; If `idlwave-shell-debug-modifiers' is non-nil, the second key
13ae1076 3415;; in the list gets bound with the specified modifiers in both
05a1abfc
CD
3416;; `idlwave-mode-map' and `idlwave-shell-mode-map'.
3417
13ae1076
JB
3418;; Used keys: abcdef hi klmnopqrs u wxyz
3419;; Unused keys: g j t v
05a1abfc
CD
3420(let* ((specs
3421 '(([(control ?b)] ?b idlwave-shell-break-here)
3422 ([(control ?i)] ?i idlwave-shell-break-in)
3423 ([(control ?d)] ?d idlwave-shell-clear-current-bp)
3424 ([(control ?a)] ?a idlwave-shell-clear-all-bp)
3425 ([(control ?s)] ?s idlwave-shell-step)
3426 ([(control ?n)] ?n idlwave-shell-stepover)
3427 ([(control ?k)] ?k idlwave-shell-skip)
3428 ([(control ?u)] ?u idlwave-shell-up)
3429 ([(control ?o)] ?o idlwave-shell-out)
3430 ([(control ?m)] ?m idlwave-shell-return)
3431 ([(control ?h)] ?h idlwave-shell-to-here)
3432 ([(control ?r)] ?r idlwave-shell-cont)
3433 ([(control ?y)] ?y idlwave-shell-execute-default-command-line)
3434 ([(control ?z)] ?z idlwave-shell-reset)
3435 ([(control ?q)] ?q idlwave-shell-quit)
3436 ([(control ?p)] ?p idlwave-shell-print)
3437 ([(??)] ?? idlwave-shell-help-expression)
3438 ([(control ?c)] ?c idlwave-shell-save-and-run)
3439 ([( ?@)] ?@ idlwave-shell-save-and-batch)
3440 ([(control ?x)] ?x idlwave-shell-goto-next-error)
3441 ([(control ?e)] ?e idlwave-shell-run-region)
3442 ([(control ?w)] ?w idlwave-shell-resync-dirs)
3443 ([(control ?l)] ?l idlwave-shell-redisplay)
3444 ([(control ?t)] ?t idlwave-shell-toggle-toolbar)
3445 ([(control up)] up idlwave-shell-stack-up)
3446 ([(control down)] down idlwave-shell-stack-down)
3447 ([(control ?f)] ?f idlwave-shell-window)))
3448 (mod (cond ((and idlwave-shell-debug-modifiers
3449 (listp idlwave-shell-debug-modifiers)
3450 (not (equal '() idlwave-shell-debug-modifiers)))
3451 idlwave-shell-debug-modifiers)
3452 (idlwave-shell-activate-alt-keybindings
3453 '(alt))))
3454 (shift (memq 'shift mod))
3455 (mod-noshift (delete 'shift (copy-sequence mod)))
3456 s k1 c2 k2 cmd)
8c7b4ec8
EZ
3457 (while (setq s (pop specs))
3458 (setq k1 (nth 0 s)
05a1abfc 3459 c2 (nth 1 s)
8c7b4ec8
EZ
3460 cmd (nth 2 s))
3461 (when idlwave-shell-activate-prefix-keybindings
3462 (and k1 (define-key idlwave-shell-mode-prefix-map k1 cmd)))
05a1abfc
CD
3463 (when (and mod window-system)
3464 (if (char-or-string-p c2)
3465 (setq k2 (vector (append mod-noshift
3466 (list (if shift (upcase c2) c2)))))
3467 (setq k2 (vector (append mod (list c2)))))
3468 (define-key idlwave-mode-map k2 cmd)
3469 (define-key idlwave-shell-mode-map k2 cmd))))
8c7b4ec8
EZ
3470
3471;; Enter the prefix map at the two places.
3472(fset 'idlwave-debug-map idlwave-shell-mode-prefix-map)
3473(fset 'idlwave-shell-debug-map idlwave-shell-mode-prefix-map)
3474
3475;; The Menus --------------------------------------------------------------
3476
3477(defvar idlwave-shell-menu-def
3478 '("Debug"
3479 ["Save and .RUN" idlwave-shell-save-and-run
3480 (or (eq major-mode 'idlwave-mode)
3481 idlwave-shell-last-save-and-action-file)]
3482 ["Save and .COMPILE" idlwave-shell-save-and-compile
3483 (or (eq major-mode 'idlwave-mode)
3484 idlwave-shell-last-save-and-action-file)]
3485 ["Save and @Batch" idlwave-shell-save-and-batch
3486 (or (eq major-mode 'idlwave-mode)
3487 idlwave-shell-last-save-and-action-file)]
3488 ["Goto Next Error" idlwave-shell-goto-next-error t]
3489 "--"
3490 ["Execute Default Cmd" idlwave-shell-execute-default-command-line t]
3491 ["Edit Default Cmd" idlwave-shell-edit-default-command-line t]
3492 "--"
3493 ["Set Breakpoint" idlwave-shell-break-here
3494 (eq major-mode 'idlwave-mode)]
3495 ["Break in Module" idlwave-shell-break-in t]
3496 ["Clear Breakpoint" idlwave-shell-clear-current-bp t]
3497 ["Clear All Breakpoints" idlwave-shell-clear-all-bp t]
3498 ["List All Breakpoints" idlwave-shell-list-all-bp t]
3499 "--"
3500 ["Step (into)" idlwave-shell-step t]
3501 ["Step (over)" idlwave-shell-stepover t]
3502 ["Skip One Statement" idlwave-shell-skip t]
3503 ["Continue" idlwave-shell-cont t]
3504 ("Continue to"
3505 ["End of Block" idlwave-shell-up t]
3506 ["End of Subprog" idlwave-shell-return t]
3507 ["End of Subprog+1" idlwave-shell-out t]
3508 ["Here (Cursor Line)" idlwave-shell-to-here
3509 (eq major-mode 'idlwave-mode)])
3510 "--"
3511 ["Print expression" idlwave-shell-print t]
3512 ["Help on expression" idlwave-shell-help-expression t]
13ae1076 3513 ["Evaluate Region" idlwave-shell-evaluate-region
8c7b4ec8
EZ
3514 (eq major-mode 'idlwave-mode)]
3515 ["Run Region" idlwave-shell-run-region (eq major-mode 'idlwave-mode)]
3516 "--"
3517 ["Redisplay" idlwave-shell-redisplay t]
3518 ["Stack Up" idlwave-shell-stack-up t]
3519 ["Stack Down" idlwave-shell-stack-down t]
3520 "--"
3521 ["Update Working Dir" idlwave-shell-resync-dirs t]
3522 ["Reset IDL" idlwave-shell-reset t]
3523 "--"
3524 ["Toggle Toolbar" idlwave-shell-toggle-toolbar t]
3525 ["Exit IDL" idlwave-shell-quit t]))
05a1abfc 3526
15e42531
CD
3527(setq idlwave-shell-menu-def
3528 '("Debug"
3529 ("Compile & Run"
3530 ["Save and .RUN" idlwave-shell-save-and-run
3531 (or (eq major-mode 'idlwave-mode)
3532 idlwave-shell-last-save-and-action-file)]
3533 ["Save and .COMPILE" idlwave-shell-save-and-compile
3534 (or (eq major-mode 'idlwave-mode)
3535 idlwave-shell-last-save-and-action-file)]
3536 ["Save and @Batch" idlwave-shell-save-and-batch
3537 (or (eq major-mode 'idlwave-mode)
3538 idlwave-shell-last-save-and-action-file)]
3539 ["Goto Next Error" idlwave-shell-goto-next-error t]
3540 "--"
3541 ["Run Region" idlwave-shell-run-region (eq major-mode 'idlwave-mode)]
3542 "--"
3543 ["Execute Default Cmd" idlwave-shell-execute-default-command-line t]
3544 ["Edit Default Cmd" idlwave-shell-edit-default-command-line t])
3545 ("Breakpoints"
3546 ["Set Breakpoint" idlwave-shell-break-here
3547 (eq major-mode 'idlwave-mode)]
3548 ["Break in Module" idlwave-shell-break-in t]
3549 ["Clear Breakpoint" idlwave-shell-clear-current-bp t]
3550 ["Clear All Breakpoints" idlwave-shell-clear-all-bp t]
3551 ["List All Breakpoints" idlwave-shell-list-all-bp t])
05a1abfc 3552 ("Continue/Step"
15e42531
CD
3553 ["Step (into)" idlwave-shell-step t]
3554 ["Step (over)" idlwave-shell-stepover t]
3555 ["Skip One Statement" idlwave-shell-skip t]
3556 ["Continue" idlwave-shell-cont t]
3557 ["... to End of Block" idlwave-shell-up t]
3558 ["... to End of Subprog" idlwave-shell-return t]
3559 ["... to End of Subprog+1" idlwave-shell-out t]
3560 ["... to Here (Cursor Line)" idlwave-shell-to-here
3561 (eq major-mode 'idlwave-mode)])
3562 ("Print Expression"
3563 ["Print expression" idlwave-shell-print t]
3564 ["Help on expression" idlwave-shell-help-expression t]
13ae1076 3565 ["Evaluate Region" idlwave-shell-evaluate-region
15e42531
CD
3566 (eq major-mode 'idlwave-mode)]
3567 "--"
3568 ["Redisplay" idlwave-shell-redisplay t]
3569 ["Stack Up" idlwave-shell-stack-up t]
3570 ["Stack Down" idlwave-shell-stack-down t])
3571 ("Input Mode"
3572 ["Send one char" idlwave-shell-send-char t]
3573 ["Temporary Character Mode" idlwave-shell-char-mode-loop t]
3574 "--"
3575 ["Use Input Mode Magic"
3576 (setq idlwave-shell-use-input-mode-magic
3577 (not idlwave-shell-use-input-mode-magic))
3578 :style toggle :selected idlwave-shell-use-input-mode-magic])
3579 "--"
3580 ["Update Working Dir" idlwave-shell-resync-dirs t]
3581 ["Reset IDL" idlwave-shell-reset t]
3582 "--"
3583 ["Toggle Toolbar" idlwave-shell-toggle-toolbar t]
3584 ["Exit IDL" idlwave-shell-quit t]))
8c7b4ec8
EZ
3585
3586(if (or (featurep 'easymenu) (load "easymenu" t))
3587 (progn
3588 (easy-menu-define
3589 idlwave-shell-mode-menu idlwave-shell-mode-map "IDL shell menus"
3590 idlwave-shell-menu-def)
13ae1076 3591 (easy-menu-define
8c7b4ec8
EZ
3592 idlwave-mode-debug-menu idlwave-mode-map "IDL debugging menus"
3593 idlwave-shell-menu-def)
3594 (save-excursion
3595 (mapcar (lambda (buf)
3596 (set-buffer buf)
3597 (if (eq major-mode 'idlwave-mode)
3598 (progn
3599 (easy-menu-remove idlwave-mode-debug-menu)
3600 (easy-menu-add idlwave-mode-debug-menu))))
3601 (buffer-list)))))
3602
3603;; The Breakpoint Glyph -------------------------------------------------------
3604
3605(defvar idlwave-shell-bp-glyph nil
3606 "The glyph to mark breakpoint lines in the source code.")
3607
3608(let ((image-string "/* XPM */
3609static char * file[] = {
3610\"14 12 3 1\",
5e72c6b2 3611\" c None s backgroundColor\",
8c7b4ec8
EZ
3612\". c #4B4B4B4B4B4B\",
3613\"R c #FFFF00000000\",
3614\" \",
3615\" \",
3616\" RRRR \",
3617\" RRRRRR \",
3618\" RRRRRRRR \",
3619\" RRRRRRRR \",
3620\" RRRRRRRR \",
3621\" RRRRRRRR \",
3622\" RRRRRR \",
3623\" RRRR \",
3624\" \",
3625\" \"};"))
13ae1076 3626
8c7b4ec8
EZ
3627 (setq idlwave-shell-bp-glyph
3628 (cond ((and (featurep 'xemacs)
3629 (featurep 'xpm))
3630 (make-glyph image-string))
3631 ((and (not (featurep 'xemacs))
3632 (fboundp 'image-type-available-p)
3633 (image-type-available-p 'xpm))
5e72c6b2 3634 (list 'image :type 'xpm :data image-string :ascent 'center))
8c7b4ec8
EZ
3635 (t nil))))
3636
3637(provide 'idlw-shell)
a98f98c0 3638(provide 'idlwave-shell)
8c7b4ec8
EZ
3639
3640;;; Load the toolbar when wanted by the user.
3641
13ae1076 3642(autoload 'idlwave-toolbar-toggle "idlw-toolbar"
ca660d22
CD
3643 "Toggle the IDLWAVE toolbar")
3644(autoload 'idlwave-toolbar-add-everywhere "idlw-toolbar"
3645 "Add IDLWAVE toolbar")
8c7b4ec8
EZ
3646(defun idlwave-shell-toggle-toolbar ()
3647 "Toggle the display of the debugging toolbar."
3648 (interactive)
ca660d22 3649 (idlwave-toolbar-toggle))
8c7b4ec8 3650
ca660d22
CD
3651(if idlwave-shell-use-toolbar
3652 (add-hook 'idlwave-shell-mode-hook 'idlwave-toolbar-add-everywhere))
8c7b4ec8 3653;;; idlw-shell.el ends here