From defb2c8b45383bd7ad3ebd9351d811e5bdaca3a5 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Thu, 17 Oct 2024 17:24:04 +0200 Subject: [PATCH] Drop IDLWAVE --- doc/emacs/programs.texi | 11 +- doc/lispref/loading.texi | 13 - doc/misc/Makefile.in | 4 +- doc/misc/idlwave.texi | 4255 ---------- etc/TODO | 5 - lisp/files.el | 2 - lisp/info-look.el | 1 - lisp/info.el | 4 +- lisp/org/ol-info.el | 2 +- lisp/progmodes/idlw-complete-structtag.el | 243 - lisp/progmodes/idlw-help.el | 1357 --- lisp/progmodes/idlw-shell.el | 4490 ---------- lisp/progmodes/idlw-toolbar.el | 931 --- lisp/progmodes/idlwave.el | 9081 --------------------- 14 files changed, 8 insertions(+), 20391 deletions(-) delete mode 100644 doc/misc/idlwave.texi delete mode 100644 lisp/progmodes/idlw-complete-structtag.el delete mode 100644 lisp/progmodes/idlw-help.el delete mode 100644 lisp/progmodes/idlw-shell.el delete mode 100644 lisp/progmodes/idlw-toolbar.el delete mode 100644 lisp/progmodes/idlwave.el diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index 2e047857ea0..78b5dfbf548 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi @@ -83,7 +83,6 @@ mode for the C programming language is @code{c-mode}. @cindex Javascript mode @cindex Awk mode @cindex C# mode -@cindex IDLWAVE mode @cindex JSON mode @cindex SQL mode @cindex TypeScript mode @@ -93,7 +92,7 @@ mode for the C programming language is @code{c-mode}. @cindex TOML mode Emacs has programming language modes for Lisp, Scheme, the Scheme-based DSSSL expression language, Ada, ASM, AWK, C, C++, C#, -Elixir, Fortran, Icon, IDL (CORBA), HEEx, IDLWAVE, Java, Javascript, +Elixir, Fortran, Icon, IDL (CORBA), HEEx, Java, Javascript, Lua, M4, Makefiles, Metafont (@TeX{}'s companion for font creation), Modula2, Object Pascal, Objective-C, Octave, Pascal, Perl, PHP, Pike, PostScript, Prolog, Python, Ruby, Simula, SQL, Tcl, TypeScript, @@ -142,14 +141,12 @@ For instance, entering C mode runs the hooks @code{prog-mode-hook} and @ifnottex Separate manuals are available for the modes for Ada (@pxref{Top,, Ada Mode, ada-mode, Ada Mode}), C/C++/Objective C/Java/Corba -IDL/Pike/AWK (@pxref{Top, , CC Mode, ccmode, CC Mode}), Octave, VHDL, -and IDLWAVE (@pxref{Top,, IDLWAVE, idlwave, IDLWAVE User Manual}). +IDL/Pike/AWK (@pxref{Top, , CC Mode, ccmode, CC Mode}), Octave, and VHDL. @end ifnottex @iftex The Emacs distribution contains Info manuals for the major modes for -Ada, C/C++/Objective C/Java/Corba IDL/Pike/AWK, Octave, VHDL, and -IDLWAVE@. For Fortran mode, @pxref{Fortran,,, emacs-xtra, Specialized -Emacs Features}. +Ada, C/C++/Objective C/Java/Corba IDL/Pike/AWK, Octave, and VHDL. For +Fortran mode, @pxref{Fortran,,, emacs-xtra, Specialized Emacs Features}. @end iftex @node Defuns diff --git a/doc/lispref/loading.texi b/doc/lispref/loading.texi index 75b9d11028a..d60a06fb957 100644 --- a/doc/lispref/loading.texi +++ b/doc/lispref/loading.texi @@ -887,19 +887,6 @@ already. If not, it loads the feature from the appropriate file. This file should call @code{provide} at the top level to add the feature to @code{features}; if it fails to do so, @code{require} signals an error. - For example, in @file{idlwave.el}, the definition for -@code{idlwave-complete-filename} includes the following code: - -@example -(defun idlwave-complete-filename () - "Use the comint stuff to complete a file name." - (require 'comint) - (let* ((comint-file-name-chars "~/A-Za-z0-9+@@:_.$#%=@{@}\\-") - (comint-completion-addsuffix nil) - ...) - (comint-dynamic-complete-filename))) -@end example - @noindent The expression @code{(require 'comint)} loads the file @file{comint.el} if it has not yet been loaded, ensuring that diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in index 0e10e17f653..5653d03ea76 100644 --- a/doc/misc/Makefile.in +++ b/doc/misc/Makefile.in @@ -50,8 +50,6 @@ GZIP_PROG = @GZIP_PROG@ HTML_OPTS = --no-split --html -# Options used only when making info output. -# (Note that idlwave, info used --nosplit even without the .info extension.) INFO_OPTS= --no-split INSTALL = @INSTALL@ @@ -70,7 +68,7 @@ DOCMISC_W32 = @DOCMISC_W32@ INFO_COMMON = auth autotype calc ccmode cl dbus dired-x \ ediff efaq eglot eieio emacs-gnutls \ emacs-mime epa erc ert eshell eudc eww flymake forms gnus \ - htmlfontify idlwave ido info.info mairix-el message \ + htmlfontify ido info.info mairix-el message \ modus-themes newsticker nxml-mode octave-mode org pcl-cvs pgg \ rcirc reftex remember sasl sc ses sieve smtpmail \ speedbar todo-mode tramp transient url use-package \ diff --git a/doc/misc/idlwave.texi b/doc/misc/idlwave.texi deleted file mode 100644 index 845c9dbd690..00000000000 --- a/doc/misc/idlwave.texi +++ /dev/null @@ -1,4255 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c %**start of header -@setfilename ../../info/idlwave.info -@settitle IDLWAVE User Manual -@include docstyle.texi -@synindex ky cp -@syncodeindex vr cp -@syncodeindex fn cp -@set VERSION 6.1 -@set EDITION 6.1 -@set IDLVERSION 6.3 -@set NSYSROUTINES 4346 -@set DATE April, 2007 -@set AUTHOR J.D. Smith & Carsten Dominik -@set MAINTAINER J.D. Smith -@c %**end of header -@finalout - -@copying -This file documents IDLWAVE, a major mode for editing IDL files with -Emacs, and interacting with an IDL shell run as a subprocess. - -This is edition @value{EDITION} of the IDLWAVE User Manual for IDLWAVE -@value{VERSION}. - -Copyright @copyright{} 1999--2024 Free Software Foundation, Inc. - -@quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with the Front-Cover Texts being ``A GNU Manual'', -and with the Back-Cover Texts as in (a) below. A copy of the license -is included in the section entitled ``GNU Free Documentation License''. - -(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and -modify this GNU manual.'' -@end quotation -@end copying - -@dircategory Emacs editing modes -@direntry -* IDLWAVE: (idlwave). Major mode and shell for IDL files. -@end direntry - -@titlepage -@title IDLWAVE User Manual -@subtitle Emacs major mode and shell for IDL -@subtitle Edition @value{EDITION}, @value{DATE} -@author by J.D. Smith & Carsten Dominik -@page -@vskip 0pt plus 1filll -@insertcopying -@end titlepage - -@contents - -@ifnottex -@node Top -@top IDLWAVE - -IDLWAVE is a package which supports editing source code written in the -Interactive Data Language (IDL), and running IDL as an inferior shell. - -@insertcopying -@end ifnottex - -@menu -* Introduction:: What IDLWAVE is, and what it is not -* IDLWAVE in a Nutshell:: One page quick-start guide -* Getting Started:: Tutorial -* The IDLWAVE Major Mode:: The mode for editing IDL programs -* The IDLWAVE Shell:: The mode for running IDL as an inferior program -* Acknowledgments:: Who did what -* Sources of Routine Info:: How does IDLWAVE know about routine XYZ -* HTML Help Browser Tips:: -* Configuration Examples:: The user is king -* Windows and macOS:: What still works, and how -* Troubleshooting:: When good computers turn bad -* GNU Free Documentation License:: The license for this documentation. -* Index:: Fast access - -@detailmenu - --- The Detailed Node Listing --- - -Getting Started (Tutorial) - -* Lesson I---Development Cycle:: -* Lesson II---Customization:: -* Lesson III---User Catalog:: - -The IDLWAVE Major Mode - -* Code Formatting:: Making code look nice -* Routine Info:: Calling Sequence and Keyword List -* Online Help:: One key press from source to help -* Completion:: Completing routine names and Keywords -* Routine Source:: Finding routines, the easy way -* Resolving Routines:: Force the Shell to compile a routine -* Code Templates:: Frequent code constructs -* Abbreviations:: Abbreviations for common commands -* Actions:: Changing case, Padding, End checking -* Doc Header:: Inserting a standard header -* Motion Commands:: Moving through the structure of a program -* Misc Options:: Things that fit nowhere else - -Code Formatting - -* Code Indentation:: Reflecting the logical structure -* Continued Statement Indentation:: -* Comment Indentation:: Special indentation for comment lines -* Continuation Lines:: Splitting statements over lines -* Syntax Highlighting:: Font-lock support -* Octals and Highlighting:: Why "123 causes problems - -Online Help - -* Help with HTML Documentation:: -* Help with Source:: - -Completion - -* Case of Completed Words:: CaseOFcomPletedWords -* Object Method Completion and Class Ambiguity:: obj->Method, what? -* Object Method Completion in the Shell:: -* Class and Keyword Inheritance:: obj->Method, _EXTRA=e -* Structure Tag Completion:: Completing state.Tag - -Actions - -* Block Boundary Check:: Is the END statement correct? -* Padding Operators:: Enforcing space around @samp{=} etc -* Case Changes:: Enforcing upper case keywords - -The IDLWAVE Shell - -* Starting the Shell:: How to launch IDL as a subprocess -* Using the Shell:: Interactively working with the Shell -* Commands Sent to the Shell:: -* Debugging IDL Programs:: -* Examining Variables:: -* Custom Expression Examination:: - -Debugging IDL Programs - -* A Tale of Two Modes:: -* Debug Key Bindings:: -* Breakpoints and Stepping:: -* Compiling Programs:: -* Walking the Calling Stack:: -* Electric Debug Mode:: - -Sources of Routine Info - -* Routine Definitions:: Where IDL Routines are defined. -* Routine Information Sources:: So how does IDLWAVE know about... -* Catalogs:: -* Load-Path Shadows:: Routines defined in several places -* Documentation Scan:: Scanning the IDL Manuals - -Catalogs - -* Library Catalogs:: -* User Catalog:: - -@end detailmenu -@end menu - -@node Introduction -@chapter Introduction -@cindex Introduction -@cindex CORBA (Common Object Request Broker Architecture) -@cindex Interface Definition Language -@cindex Interactive Data Language -@cindex @file{cc-mode.el} -@cindex @file{idl.el} -@cindex @file{idl-shell.el} -@cindex Feature overview - -IDLWAVE is a package which supports editing source files written in -the Interactive Data Language (IDL), and running IDL as an inferior shell@footnote{IDLWAVE can also be used -for editing source files for the related WAVE/CL language, but with only -limited support.}. It is a feature-rich replacement for the IDLDE -development environment included with IDL, and uses the full power of -Emacs to make editing and running IDL programs easier, quicker, and more -structured. - -IDLWAVE consists of two main parts: a major mode for editing IDL -source files (@code{idlwave-mode}) and a mode for running the IDL -program as an inferior shell (@code{idlwave-shell-mode}). Although -one mode can be used without the other, both work together closely to -form a complete development environment. Here is a brief summary of -what IDLWAVE does: - -@itemize @bullet -@item -Smart code indentation and automatic-formatting. -@item -Three level syntax highlighting support. -@item -Context-sensitive display of calling sequences and keywords for more -than 1000 native IDL routines, extensible to any additional number of -local routines, and already available with many pre-scanned libraries. -@item -Fast, context-sensitive online HTML help, or source-header help for -undocumented routines. -@item -Context sensitive completion of routine names, keywords, system -variables, class names and much more. -@item -Easy insertion of code templates and abbreviations of common constructs. -@item -Automatic corrections to enforce a variety of customizable coding -standards. -@item -Integrity checks and auto-termination of logical blocks. -@item -Routine name space conflict search with likelihood-of-use ranking. -@item -Support for @file{imenu}. -@item -Documentation support. -@item -Running IDL as an inferior Shell with history search, command line -editing and all the completion and routine info capabilities present in -IDL source buffers. -@item -Full handling of debugging with breakpoints, with interactive setting -of break conditions, and easy stepping through code. -@item -Compilation, execution and interactive single-keystroke debugging of -programs directly from the source buffer. -@item -Quick, source-guided navigation of the calling stack, with variable -inspection, etc. -@item -Examining variables and expressions with a mouse click. -@item -And much, much more... -@end itemize - -@c Dead links, 2014/06. -@ignore -@ifnottex -@cindex Screenshots -Here are a number of screenshots showing IDLWAVE in action: - -@itemize @bullet -@item -@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_nav.gif,An IDLWAVE buffer} -@item -@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_keys.gif,A keyword being completed} -@item -@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_help.gif,Online help text.} -@item -@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_ri.gif,Routine information displayed} -@item -@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_bp.gif,Debugging code -stopped at a breakpoint} -@end itemize -@end ifnottex -@end ignore - -IDLWAVE is the distant successor to the @file{idl.el} and -@file{idl-shell.el} files written by Chris Chase. The modes and files -had to be renamed because of a name space conflict with CORBA's -@code{idl-mode}, defined in Emacs in the file @file{cc-mode.el}. - -In this manual, each section ends with a list of related user options. -Don't be confused by the sheer number of options available: in most -cases the default settings are just fine. The variables are listed here -to make sure you know where to look if you want to change anything. For -a full description of what a particular variable does and how to -configure it, see the documentation string of that variable (available -with @kbd{C-h v}). Some configuration examples are also given in the -appendix. - -@node IDLWAVE in a Nutshell -@chapter IDLWAVE in a Nutshell -@cindex Summary of important commands -@cindex IDLWAVE in a Nutshell -@cindex Nutshell, IDLWAVE in a - -@subheading Editing IDL Programs - -@multitable @columnfractions .15 .85 -@item @key{TAB} -@tab Indent the current line relative to context. -@item @kbd{C-M-\} -@tab Re-indent all lines in the current region. -@item @kbd{C-M-q} -@tab Re-indent all lines in the current routine. -@item @kbd{C-u @key{TAB}} -@tab Re-indent all lines in the current statement. -@item @kbd{M-@key{RET}} -@tab Start a continuation line, splitting the current line at point. -@item @kbd{M-;} -@tab Start new comment at line beginning or after code, or (un)comment -highlighted region. -@item @kbd{M-q} -@tab Fill the current comment paragraph. -@item @kbd{C-c ?} -@tab Display calling sequence and keywords for the procedure or function call -at point. -@item @kbd{M-?} -@tab Load context sensitive online help for nearby routine, keyword, etc. -@item @kbd{M-@key{TAB}} -@tab Complete a procedure name, function name or keyword in the buffer. -@item @kbd{C-c C-i} -@tab Update IDLWAVE's knowledge about functions and procedures. -@item @kbd{C-c C-v} -@tab Visit the source code of a procedure/function. -@item @kbd{C-u C-c C-v} -@tab Visit the source code of a procedure/function in this buffer. -@item @kbd{C-c C-h} -@tab Insert a standard documentation header. -@item @kbd{C-c @key{RET}} -@tab Insert a new timestamp and history item in the documentation header. -@end multitable - -@subheading Running the IDLWAVE Shell, Debugging Programs - -@multitable @columnfractions .15 .85 -@item @kbd{C-c C-s} -@tab Start IDL as a subprocess and/or switch to the shell buffer. -@item @key{Up}, @kbd{M-p} -@tab Cycle back through IDL command history. -@item @key{Down},@kbd{M-n} -@tab Cycle forward. -@item @kbd{@key{TAB}} -@tab Complete a procedure name, function name or keyword in the shell buffer. -@item @kbd{C-c C-d C-c} -@tab Save and compile the source file in the current buffer. -@item @kbd{C-c C-d C-e} -@tab Compile and run the current region. -@item @kbd{C-c C-d C-x} -@tab Go to next syntax error. -@item @kbd{C-c C-d C-v} -@tab Switch to electric debug mode. -@item @kbd{C-c C-d C-b} -@tab Set a breakpoint at the nearest viable source line. -@item @kbd{C-c C-d C-d} -@tab Clear the nearest breakpoint. -@item @kbd{C-c C-d [} -@tab Go to the previous breakpoint. -@item @kbd{C-c C-d ]} -@tab Go to the next breakpoint. -@item @kbd{C-c C-d C-p} -@tab Print the value of the expression near point in IDL. -@end multitable - -@subheading Commonly used Settings in @file{.emacs} -@lisp -;; Change the indentation preferences -;; Start autoloading routine info after 2 idle seconds -(setq idlwave-init-rinfo-when-idle-after 2) -;; Pad operators with spaces -(setq idlwave-do-actions t - idlwave-surround-by-blank t) -;; Syntax Highlighting -(add-hook 'idlwave-mode-hook 'turn-on-font-lock) -;; Automatically start the shell when needed -(setq idlwave-shell-automatic-start t) -;; Bind debugging commands with CONTROL and SHIFT modifiers -(setq idlwave-shell-debug-modifiers '(control shift)) -@end lisp - -@html - -@end html - -@node Getting Started -@chapter Getting Started (Tutorial) -@cindex Quick-Start -@cindex Tutorial -@cindex Getting Started - -@menu -* Lesson I---Development Cycle:: -* Lesson II---Customization:: -* Lesson III---User Catalog:: -@end menu - -@node Lesson I---Development Cycle -@section Lesson I: Development Cycle - -The purpose of this tutorial is to guide you through a very basic -development cycle using IDLWAVE@. We will paste a simple program into -a buffer and use the shell to compile, debug and run it. On the way -we will use many of the important IDLWAVE commands. Note, however, -that IDLWAVE has many more capabilities than covered here, which can -be discovered by reading the entire manual, or hovering over the -shoulder of your nearest IDLWAVE guru for a few days. - -It is assumed that you have access to Emacs with the full -IDLWAVE package including online help. We also assume that you are -familiar with Emacs and can read the nomenclature of key presses in -Emacs (in particular, @kbd{C} stands for @key{CONTROL} and @kbd{M} for -@key{META} (often the @key{ALT} key carries this functionality)). - -Open a new source file by typing: - -@example -@kbd{C-x C-f tutorial.pro @key{RET}} -@end example - -A buffer for this file will pop up, and it should be in IDLWAVE mode, -indicated in the mode line just below the editing window. Also, the -menu bar should contain @samp{IDLWAVE}. - -Now cut-and-paste the following code, also available as -@file{tutorial.pro} in the IDLWAVE distribution. - -@example -function daynr,d,m,y - ;; compute a sequence number for a date - ;; works 1901-2099. - if y lt 100 then y = y+1900 - if m le 2 then delta = 1 else delta = 0 - m1 = m + delta*12 + 1 - y1 = y * delta - return, d + floor(m1*30.6)+floor(y1*365.25)+5 -end - -function weekday,day,month,year - ;; compute weekday number for date - nr = daynr(day,month,year) - return, nr mod 7 -end - -pro plot_wday,day,month - ;; Plot the weekday of a date in the first 10 years of this century. - years = 2000,+indgen(10) - wdays = intarr(10) - for i=0,n_elements(wdays)-1 do begin - wdays[i] = weekday(day,month,years[i]) - end - plot,years,wdays,YS=2,YT="Wday (0=Sunday)" -end -@end example - -The indentation probably looks funny, since it's different from the -settings you use, so use the @key{TAB} key in each line to -automatically line it up (or, more quickly, @emph{select} the entire -buffer with @kbd{C-x h}, and indent the whole region with -@kbd{C-M-\}). Notice how different syntactical elements are -highlighted in different colors, if you have set up support for -font-lock. - -Let's check out two particular editing features of IDLWAVE@. Place the -cursor after the @code{end} statement of the @code{for} loop and press -@key{SPC}. IDLWAVE blinks back to the beginning of the block and -changes the generic @code{end} to the specific @code{endfor} -automatically (as long as the variable @code{idlwave-expand-generic-end} -is turned on; @pxref{Lesson II---Customization}). Now place the -cursor in any line you would like to split and press @kbd{M-@key{RET}}. -The line is split at the cursor position, with the continuation @samp{$} -and indentation all taken care of. Use @kbd{C-/} to undo the last -change. - -The procedure @code{plot_wday} is supposed to plot the day of the week -of a given date for the first 10 years of the 21st century. As in -most code, there are a few bugs, which we are going to use IDLWAVE to -help us fix. - -First, let's launch the IDLWAVE shell. You do this with the command -@kbd{C-c C-s}. The Emacs window will split or another window will popup -to display IDL running in a shell interaction buffer. Type a few -commands like @code{print,!PI} to convince yourself that you can work -there just as well as in a terminal, or the IDLDE@. Use the arrow keys -to cycle through your command history. Are we having fun now? - -Now go back to the source window and type @kbd{C-c C-d C-c} to compile -the program. If you watch the shell buffer, you see that IDLWAVE types -@samp{.run "tutorial.pro"} for you. But the compilation fails because -there is a comma in the line @samp{years=...}. The line with the error -is highlighted and the cursor positioned at the error, so remove the -comma (you should only need to hit @kbd{Delete}!). Compile again, using -the same keystrokes as before. Notice that the file is automatically -saved for you. This time everything should work fine, and you should -see the three routines compile. - -Now we want to use the command to plot the day of the week on January -1st. We could type the full command ourselves, but why do that? Go -back to the shell window, type @samp{plot_} and hit @key{TAB}. After -a bit of a delay (while IDLWAVE initializes its routine info database, -if necessary), the window will split to show all procedures it knows -starting with that string, and @w{@code{plot_wday}} should be one of -them. Saving the buffer alerted IDLWAVE about this new routine. -Click with the middle mouse button on @code{plot_wday} and it will be -copied to the shell buffer, or if you prefer, add @samp{w} to -@samp{plot_} to make it unambiguous (depending on what other routines -starting with @samp{plot_} you have installed on your system), hit -@key{TAB} again, and the full routine name will be completed. Now -provide the two arguments: - -@example -plot_wday,1,1 -@end example - -@noindent and press @key{RET}. This fails with an error message telling -you the @code{YT} keyword to plot is ambiguous. What are the allowed -keywords again? Go back to the source window and put the cursor into -the ``plot'' line and press @kbd{C-c ?}. This shows the routine info -window for the plot routine, which contains a list of keywords, along -with the argument list. Oh, we wanted @code{YTITLE}. Fix that up. -Recompile with @kbd{C-c C-d C-c}. Jump back into the shell with -@kbd{C-c C-s}, press the @key{UP} arrow to recall the previous command -and execute again. - -This time we get a plot, but it is pretty ugly: the points are all -connected with a line. Hmm, isn't there a way for @code{plot} to use -symbols instead? What was that keyword? Position the cursor on the -plot line after a comma (where you'd normally type a keyword), and hit -@kbd{M-@key{Tab}}. A long list of plot's keywords appears. Aha, -there it is, @code{PSYM}. Middle click to insert it. An @samp{=} -sign is included for you too. Now what were the values of @code{PSYM} -supposed to be? With the cursor on or after the keyword, press -@kbd{M-?} for online help (alternatively, you could have right clicked -on the colored keyword itself in the completion list). A browser will -pop up showing the HTML documentation for the @code{PYSM} keyword. -OK, let's use diamonds=4. Fix this, recompile (you know the command -by now: @kbd{C-c C-d C-c}), go back to the shell (if it's vanished, -you know what to do: @kbd{C-c C-s}) and execute again. Now things -look pretty good. - -Let's try a different day. How about April fool's day? - -@example -plot_wday,1,4 -@end example - -Oops, this looks very wrong. All April Fool's days cannot be Fridays! -We've got a bug in the program, perhaps in the @code{daynr} function. -Let's put a breakpoint on the last line there. Position the cursor on -the @samp{return, d+...} line and press @kbd{C-c C-d C-b}. IDL sets a -breakpoint (as you see in the shell window), and the break line is -indicated. Back to the shell buffer, re-execute the previous command. -IDL stops at the line with the breakpoint. Now hold down the SHIFT -key and click with the middle mouse button on a few variables there: -@samp{d}, @samp{y}, @samp{m}, @samp{y1}, etc. Maybe @code{d} isn't -the correct type. CONTROL-SHIFT middle-click on it for help. Well, -it's an integer, so that's not the problem. Aha, @samp{y1} is zero, -but it should be the year, depending on delta. Shift click -@samp{delta} to see that it's 0. Below, we see the offending line: -@samp{y1=y*delta...} the multiplication should have been a minus sign! -Hit @kbd{q} to exit the debugging mode, and fix the line to read: - -@example -y1 = y - delta -@end example - -Now remove all breakpoints: @kbd{C-c C-d C-a}. Recompile and rerun the -command. Everything should now work fine. How about those leap years? -Change the code to plot 100 years and see that every 28 years, the -sequence of weekdays repeats. - -@node Lesson II---Customization -@section Lesson II: Customization - -Emacs is probably the most customizable piece of software ever written, -and it would be a shame if you did not make use of this to adapt IDLWAVE -to your own preferences. Customizing Emacs or IDLWAVE is accomplished -by setting Lisp variables in the @file{.emacs} file in your home -directory---but do not be dismayed; for the most part, you can just -copy and work from the examples given here. - -Let's first use a boolean variable. These are variables which you turn -on or off, much like a checkbox. A value of @samp{t} means on, a value -of @samp{nil} means off. Copy the following line into your -@file{.emacs} file, exit and restart Emacs. - -@lisp -(setq idlwave-reserved-word-upcase t) -@end lisp - -When this option is turned on, each reserved word you type into an IDL -source buffer will be converted to upper case when you press @key{SPC} -or @key{RET} right after the word. Try it out! @samp{if} changes to -@samp{IF}, @samp{begin} to @samp{BEGIN}. If you don't like this -behavior, remove the option again from your @file{.emacs} file and -restart Emacs. - -You likely have your own indentation preferences for IDL code. For -example, some may prefer to indent the main block of an IDL program -slightly from the margin and use only 3 spaces as indentation between -@code{BEGIN} and @code{END}. Try the following lines in @file{.emacs}: - -@lisp -(setq idlwave-main-block-indent 1) -(setq idlwave-block-indent 3) -(setq idlwave-end-offset -3) -@end lisp - -Restart Emacs, and re-indent the program we developed in the first part -of this tutorial with @kbd{C-c h} and @kbd{C-M-\}. You may want to keep -these lines in @file{.emacs}, with values adjusted to your liking. If -you want to get more information about any of these variables, type, -e.g., @kbd{C-h v idlwave-main-block-indent @key{RET}}. To find which -variables can be customized, look for items marked @samp{User Option:} -throughout this manual. - -If you cannot seem to master this Lisp customization in @file{.emacs}, -there is another, more user-friendly way to customize all the IDLWAVE -variables. You can access it through the IDLWAVE menu in one of the -@file{.pro} buffers, menu item @code{Customize->Browse IDLWAVE -Group}. Here you'll be presented with all the various variables grouped -into categories. You can navigate the hierarchy (e.g., @samp{IDLWAVE -Code Formatting->Idlwave Abbrev And Indent Action->Idlwave Expand -Generic End} to turn on @code{END} expansion), read about the variables, -change them, and ``Save for Future Sessions''. Few of these variables -need customization, but you can exercise considerable control over -IDLWAVE's functionality with them. - -You may also find the key bindings used for the debugging commands too -long and complicated. Often we have heard complaints along the lines -of, ``Do I really have to go through the finger gymnastics of @kbd{C-c -C-d C-c} to run a simple command?'' Due to Emacs rules and -conventions, shorter bindings cannot be set by default, but you can -easily enable them. First, there is a way to assign all debugging -commands in a single sweep to another simpler combination. The only -problem is that we have to use something which Emacs does not need for -other important commands. One good option is to execute debugging -commands by holding down @key{CONTROL} and @key{SHIFT} while pressing -a single character: @kbd{C-S-b} for setting a breakpoint, @kbd{C-S-c} -for compiling the current source file, @kbd{C-S-a} for deleting all -breakpoints (try it, it's easier). You can enable this with: - -@lisp -(setq idlwave-shell-debug-modifiers '(shift control)) -@end lisp - -@noindent If you have a special keyboard with, for example, a -@key{SUPER} key, you could even shorten that: - -@lisp -(setq idlwave-shell-debug-modifiers '(super)) -@end lisp - -@noindent to get compilation on @kbd{S-c}. Often, a modifier key like -@key{SUPER} or @key{HYPER} is bound or can be bound to an otherwise -unused key on your keyboard; consult your system documentation. - -You can also assign specific commands to keys. This you must do in the -@emph{mode-hook}, a special function which is run when a new IDLWAVE -buffer gets set up. The possibilities for key customization are -endless. Here we set function keys f4-f8 to common debugging commands. - -@lisp -;; First for the source buffer -(add-hook 'idlwave-mode-hook - (lambda () - (local-set-key [f4] 'idlwave-shell-retall) - (local-set-key [f5] 'idlwave-shell-break-here) - (local-set-key [f6] 'idlwave-shell-clear-current-bp) - (local-set-key [f7] 'idlwave-shell-cont) - (local-set-key [f8] 'idlwave-shell-clear-all-bp))) -;; Then for the shell buffer -(add-hook 'idlwave-shell-mode-hook - (lambda () - (local-set-key [f4] 'idlwave-shell-retall) - (local-set-key [f5] 'idlwave-shell-break-here) - (local-set-key [f6] 'idlwave-shell-clear-current-bp) - (local-set-key [f7] 'idlwave-shell-cont) - (local-set-key [f8] 'idlwave-shell-clear-all-bp))) -@end lisp - -@node Lesson III---User Catalog -@section Lesson III: User and Library Catalogs - -We have already used the routine info display in the first part of this -tutorial. This was the invoked using @kbd{C-c ?}, and displays -information about the IDL routine near the cursor position. Wouldn't it -be nice to have the same kind of information available for your own -routines and for the huge amount of code in major libraries like JHUAPL -or the IDL-Astro library? In many cases, you may already have this -information. Files named @file{.idlwave_catalog} in library directories -contain scanned information on the routines in that directory; many -popular libraries ship with these ``library catalogs'' pre-scanned. -Users can scan their own routines in one of two ways: either using the -supplied tool to scan directories and build their own -@file{.idlwave_catalog} files, or using the built-in method to create a -single ``user catalog'', which we'll show here. @xref{Catalogs}, for -more information on choosing which method to use. - -To build a user catalog, select @code{Routine Info/Select Catalog -Directories} from the IDLWAVE entry in the menu bar. If necessary, -start the shell first with @kbd{C-c C-s} (@pxref{Starting the Shell}). -IDLWAVE will find out about the IDL @code{!PATH} variable and offer a -list of directories on the path. Simply select them all (or whichever -you want; directories with existing library catalogs will not be -selected by default) and click on the @samp{Scan&Save} button. Then -go for a cup of coffee while IDLWAVE collects information for each and -every IDL routine on your search path. All this information is -written to the file @file{~/.emacs.d/idlwave/idlusercat.el} -and will from now on automatically load whenever you use -IDLWAVE@. You may find it necessary to rebuild the catalog on occasion -as your local libraries change, or build a library catalog for those -directories instead. Invoke routine info (@kbd{C-c ?}) or completion -(@kbd{M-@key{TAB}}) on any routine or partial routine name you know to -be located in the library. E.g., if you have scanned the IDL-Astro -library: - -@example - a=readf@kbd{M-@key{TAB}} -@end example - -expands to ``readfits(''. Then try - -@example - a=readfits(@kbd{C-c ?} -@end example - -and you get: - -@example -Usage: Result = READFITS(filename, header, heap) -... -@end example - -I hope you made it until here. Now you are set to work with IDLWAVE@. -On the way you will want to change other things, and to learn more -about the possibilities not discussed in this short tutorial. Read -the manual, look at the documentation strings of interesting variables -(with @kbd{C-h v idlwave<-variable-name> @key{RET}}) and ask the -remaining questions on the newsgroup @code{comp.lang.idl-pvwave}. - -@node The IDLWAVE Major Mode -@chapter The IDLWAVE Major Mode -@cindex IDLWAVE major mode -@cindex Major mode, @code{idlwave-mode} - -The IDLWAVE major mode supports editing IDL source files. In this -chapter we describe the main features of the mode and how to customize -them. - -@menu -* Code Formatting:: Making code look nice -* Routine Info:: Calling Sequence and Keyword List -* Online Help:: One key press from source to help -* Completion:: Completing routine names and Keywords -* Routine Source:: Finding routines, the easy way -* Resolving Routines:: Force the Shell to compile a routine -* Code Templates:: Frequent code constructs -* Abbreviations:: Abbreviations for common commands -* Actions:: Changing case, Padding, End checking -* Doc Header:: Inserting a standard header -* Motion Commands:: Moving through the structure of a program -* Misc Options:: Things that fit nowhere else -@end menu - -@node Code Formatting -@section Code Formatting -@cindex Code formatting -@cindex Formatting, of code - -@menu -* Code Indentation:: Reflecting the logical structure -* Continued Statement Indentation:: -* Comment Indentation:: Special indentation for comment lines -* Continuation Lines:: Splitting statements over lines -* Syntax Highlighting:: Font-lock support -* Octals and Highlighting:: Why "123 causes problems -@end menu - -The IDL language, with its early roots in FORTRAN, modern -implementation in C, and liberal borrowing of features of many vector -and other languages along its 25+ year history, has inherited an -unusual mix of syntax elements. Left to his or her own devices, a -novice IDL programmer will often conjure code which is very difficult -to read and impossible to adapt. Much can be gleaned from studying -available IDL code libraries for coding style pointers, but, due to -the variety of IDL syntax elements, replicating this style can be -challenging at best. Luckily, IDLWAVE understands the structure of -IDL code very well, and takes care of almost all formatting issues for -you. After configuring it to match your coding standards, you can -rely on it to help keep your code neat and organized. - - -@node Code Indentation -@subsection Code Indentation -@cindex Code indentation -@cindex Indentation - -Like all Emacs programming modes, IDLWAVE performs code indentation. -The @key{TAB} key indents the current line relative to context. -@key{LFD} insert a newline and indents the new line. The indentation is -governed by a number of variables. IDLWAVE indents blocks (between -@code{PRO}/@code{FUNCTION}/@code{BEGIN} and @code{END}), and -continuation lines. - -@cindex Foreign code, adapting -@cindex Indentation, of foreign code -@kindex C-M-\ -To re-indent a larger portion of code (e.g., when working with foreign -code written with different conventions), use @kbd{C-M-\} -(@code{indent-region}) after marking the relevant code. Useful marking -commands are @kbd{C-x h} (the entire file) or @kbd{C-M-h} (the current -subprogram). The command @kbd{C-M-q} reindents the entire current -routine. @xref{Actions}, for information how to impose additional -formatting conventions on foreign code. - -@defopt idlwave-main-block-indent (@code{2}) -Extra indentation for the main block of code. That is the block between -the FUNCTION/PRO statement and the END statement for that program -unit. -@end defopt - -@defopt idlwave-block-indent (@code{3}) -Extra indentation applied to block lines. If you change this, you -probably also want to change @code{idlwave-end-offset}. -@end defopt - -@defopt idlwave-end-offset (@code{-3}) -Extra indentation applied to block END lines. A value equal to negative -@code{idlwave-block-indent} will make END lines line up with the block -BEGIN lines. -@end defopt - -@node Continued Statement Indentation -@subsection Continued Statement Indentation -@cindex Indentation, continued statement -@cindex Continued statement indentation -Continuation lines (following a line ending with @code{$}) can receive a -fixed indentation offset from the main level, but in several situations -IDLWAVE can use a special form of indentation which aligns continued -statements more naturally. Special indentation is calculated for -continued routine definition statements and calls, enclosing parentheses -(like function calls, structure/class definitions, explicit structures -or lists, etc.), and continued assignments. An attempt is made to line -up with the first non-whitespace character after the relevant opening -punctuation mark (@code{,},@code{(},@code{@{},@code{[},@code{=}). For -lines without any non-comment characters on the line with the opening -punctuation, the continued line(s) are aligned just past the -punctuation. An example: - -@example -function foo, a, b, $ - c, d - bar = sin( a + b + $ - c + d) -end -@end example -@noindent - -The only drawback to this special continued statement indentation is -that it consumes more space, e.g., for long function names or left hand -sides of an assignment: - -@example -function thisfunctionnameisverylongsoitwillleavelittleroom, a, b, $ - c, d -@end example - -You can instruct IDLWAVE when to avoid using this special continuation -indentation by setting the variable -@code{idlwave-max-extra-continuation-indent}, which specifies the -maximum additional indentation beyond the basic indent to be -tolerated, otherwise defaulting to a fixed-offset from the enclosing -indent (the size of which offset is set in -@code{idlwave-continuation-indent}). As a special case, continuations -of routine calls without any arguments or keywords will @emph{not} -align the continued line, under the assumption that you continued -because you needed the space. - -Also, since the indentation level can be somewhat dynamic in continued -statements with special continuation indentation, especially if -@code{idlwave-max-extra-continuation-indent} is small, the key -@kbd{C-u @key{TAB}} will re-indent all lines in the current statement. -Note that @code{idlwave-indent-to-open-paren}, if non-@code{nil}, -overrides the @code{idlwave-max-extra-continuation-indent} limit, for -parentheses only, forcing them always to line up. - - -@defopt idlwave-continuation-indent (@code{2}) -Extra indentation applied to normal continuation lines. -@end defopt - -@defopt idlwave-max-extra-continuation-indent (@code{20}) -The maximum additional indentation (over the basic continuation-indent) -that will be permitted for special continues. To effectively disable -special continuation indentation, set to @code{0}. To enable it -constantly, set to a large number (like @code{100}). Note that the -indentation in a long continued statement never decreases from line to -line, outside of nested parentheses statements. -@end defopt - -@defopt idlwave-indent-to-open-paren (@code{t}) -Non-@code{nil} means indent continuation lines to innermost open -parenthesis, regardless of whether the -@code{idlwave-max-extra-continuation-indent} limit is satisfied. -@end defopt - -@node Comment Indentation -@subsection Comment Indentation -@cindex Comment indentation -@cindex Hanging paragraphs -@cindex Paragraphs, filling -@cindex Paragraphs, hanging - -In IDL, lines starting with a @samp{;} are called @emph{comment lines}. -Comment lines are indented as follows: - -@multitable @columnfractions .1 .90 -@item @code{;;;} -@tab The indentation of lines starting with three semicolons remains -unchanged. -@item @code{;;} -@tab Lines starting with two semicolons are indented like the surrounding code. -@item @code{;} -@tab Lines starting with a single semicolon are indented to a minimum column. -@end multitable - -@noindent -The indentation of comments starting in column 0 is never changed. - -@defopt idlwave-no-change-comment -The indentation of a comment starting with this regexp will not be -changed. -@end defopt - -@defopt idlwave-begin-line-comment -A comment anchored at the beginning of line. -@end defopt - -@defopt idlwave-code-comment -A comment that starts with this regexp is indented as if it is a part of -IDL code. -@end defopt - -@node Continuation Lines -@subsection Continuation Lines and Filling -@cindex Continuation lines -@cindex Line splitting -@cindex String splitting -@cindex Splitting, of lines - -@kindex M-RET -In IDL, a newline character terminates a statement unless preceded by a -@samp{$}. If you would like to start a continuation line, use -@kbd{M-@key{RET}}, which calls the command @code{idlwave-split-line}. -It inserts the continuation character @samp{$}, terminates the line and -indents the new line. The command @kbd{M-@key{RET}} can also be invoked -inside a string to split it at that point, in which case the @samp{+} -concatenation operator is used. - -@cindex Filling -@cindex @code{auto-fill-mode} -@cindex Hanging paragraphs -When filling comment paragraphs, IDLWAVE overloads the normal filling -functions and uses a function which creates the hanging paragraphs -customary in IDL routine headers. When @code{auto-fill-mode} is turned -on (toggle with @kbd{C-c C-a}), comments will be auto-filled. If the -first line of a paragraph contains a match for -@code{idlwave-hang-indent-regexp} (a dash-space by default), subsequent -lines are positioned to line up after it, as in the following example. - -@example -@group -;================================= -; x - an array containing -; lots of interesting numbers. -; -; y - another variable where -; a hanging paragraph is used -; to describe it. -;================================= -@end group -@end example - -@kindex M-q -You can also refill a comment at any time paragraph with @kbd{M-q}. -Comment delimiting lines as in the above example, consisting of one or -more @samp{;} followed by one or more of the characters @samp{+=-_*}, -are kept in place, as is. - -@defopt idlwave-fill-comment-line-only (@code{t}) -Non-@code{nil} means auto fill will only operate on comment lines. -@end defopt - -@defopt idlwave-auto-fill-split-string (@code{t}) -Non-@code{nil} means auto fill will split strings with the IDL @samp{+} -operator. -@end defopt - -@defopt idlwave-split-line-string (@code{t}) -Non-@code{nil} means @code{idlwave-split-line} will split strings with -@samp{+}. -@end defopt - -@defopt idlwave-hanging-indent (@code{t}) -Non-@code{nil} means comment paragraphs are indented under the hanging -indent given by @code{idlwave-hang-indent-regexp} match in the first -line of the paragraph. -@end defopt - -@defopt idlwave-hang-indent-regexp (@code{"- "}) -Regular expression matching the position of the hanging indent -in the first line of a comment paragraph. -@end defopt - -@defopt idlwave-use-last-hang-indent (@code{nil}) -Non-@code{nil} means use last match on line for -@code{idlwave-indent-regexp}. -@end defopt - -@node Syntax Highlighting -@subsection Syntax Highlighting -@cindex Syntax highlighting -@cindex Highlighting of syntax -@cindex Font lock - -Highlighting of keywords, comments, strings etc.@: can be accomplished -with @code{font-lock}. If you are using @code{global-font-lock-mode}, -or have @code{font-lock-mode} turned on in any other buffer, -it should also automatically work in IDLWAVE buffers. If you'd -prefer invoking font-lock individually by mode, you can enforce it in -@code{idlwave-mode} with the following line in your @file{.emacs}: - -@lisp -(add-hook 'idlwave-mode-hook 'turn-on-font-lock) -@end lisp - -@noindent IDLWAVE supports 3 increasing levels of syntax highlighting. -The variable @code{font-lock-maximum-decoration} determines which level -is selected. Individual categories of special tokens can be selected -for highlighting using the variable -@code{idlwave-default-font-lock-items}. - -@defopt idlwave-default-font-lock-items -Items which should be fontified on the default fontification level -2. -@end defopt - -@node Octals and Highlighting -@subsection Octals and Highlighting -@cindex Syntax highlighting, Octals -@cindex Highlighting of syntax, Octals - -A rare syntax highlighting problem results from an extremely unfortunate -notation for octal numbers in IDL: @code{"123}. This unpaired quotation -mark is very difficult to parse, given that it can be mixed on a single -line with any number of strings. Emacs will incorrectly identify this -as a string, and the highlighting of following lines of code can be -distorted, since the string is never terminated. - -One solution to this involves terminating the mistakenly identified -string yourself by providing a closing quotation mark in a comment: - -@example - string("305B) + $ ;" <--- for font-lock - ' is an Angstrom.' -@end example - -@noindent A far better solution is to abandon this notation for octals -altogether, and use the more sensible alternative IDL provides: - -@example - string('305'OB) + ' is an Angstrom.' -@end example - -@noindent This simultaneously solves the font-lock problem and is more -consistent with the notation for hexadecimal numbers, e.g., @code{'C5'XB}. - -@node Routine Info -@section Routine Info -@cindex Routine info -@cindex Updating routine info -@cindex Scanning buffers for routine info -@cindex Buffers, scanning for routine info -@cindex Shell, querying for routine info - -@kindex C-c C-i -IDL comes bundled with more than one thousand procedures, functions -and object methods, and large libraries typically contain hundreds or -even thousands more (each with a few to tens of keywords and -arguments). This large command set can make it difficult to remember -the calling sequence and keywords for the routines you use, but -IDLWAVE can help. It builds up routine information from a wide -variety of sources; IDLWAVE in fact knows far more about the -@samp{.pro} routines on your system than IDL itself! It maintains a -list of all built-in routines, with calling sequences and -keywords@footnote{This list is created by scanning the IDL manuals and -might contain (very few) errors. Please report any errors to the -maintainer, so that they can be fixed.}. It also scans Emacs buffers -for routine definitions, queries the IDLWAVE-Shell for information -about routines currently compiled there, and automatically locates -library and user-created catalogs. This information is updated -automatically, and so should usually be current. To force a global -update and refresh the routine information, use @kbd{C-c C-i} -(@code{idlwave-update-routine-info}). - -@kindex C-c ? -To display the information about a routine, press @kbd{C-c ?}, which -calls the command @code{idlwave-routine-info}. When the current cursor -position is on the name or in the argument list of a procedure or -function, information will be displayed about the routine. For example, -consider the indicated cursor positions in the following line: - -@example -plot,x,alog(x+5*sin(x) + 2), - | | | | | | | | - 1 2 3 4 5 6 7 8 -@end example - -@cindex Default routine, for info and help -On positions 1,2 and 8, information about the @samp{plot} procedure will -be shown. On positions 3,4, and 7, the @samp{alog} function will be -described, while positions 5 and 6 will investigate the @samp{sin} -function. - -When you ask for routine information about an object method, and the -method exists in several classes, IDLWAVE queries for the class of the -object, unless the class is already known through a text property on the -@samp{->} operator (@pxref{Object Method Completion and Class -Ambiguity}), or by having been explicitly included in the call -(e.g., @code{a->myclass::Foo}). - -@cindex Calling sequences -@cindex Keywords of a routine -@cindex Routine source information -The description displayed contains the calling sequence, the list of -keywords and the source location of this routine. It looks like this: - -@example -Usage: XMANAGER, NAME, ID -Keywords: BACKGROUND CATCH CLEANUP EVENT_HANDLER GROUP_LEADER - JUST_REG MODAL NO_BLOCK -Source: SystemLib [LCSB] /soft1/idl53/lib/xmanager.pro -@end example - -@cindex Categories, of routines -@cindex Load-path shadows -@cindex Shadows, load-path -@cindex IDL variable @code{!PATH} -@cindex @code{!PATH}, IDL variable -@cindex IDL variable @code{!DIR} -@cindex @code{!DIR}, IDL variable - -If a definition of this routine exists in several files accessible to -IDLWAVE, several @samp{Source} lines will point to the different -files. This may indicate that your routine is shadowing a system -library routine, which may or may not be what you want -(@pxref{Load-Path Shadows}). The information about the calling -sequence and keywords is derived from the first source listed. -Library routines are available only if you have scanned your local IDL -directories or are using pre-scanned libraries (@pxref{Catalogs}). -The source entry consists of a @emph{source category}, a set of -@emph{flags} and the path to the @emph{source file}. The following -default categories exist: - -@multitable @columnfractions .15 .85 -@item @i{System} -@tab A system routine of unknown origin. When the system library has -been scanned as part of a catalog (@pxref{Catalogs}), this category -will automatically split into the next two. -@item @i{Builtin} -@tab A builtin system routine with no source code available. -@item @i{SystemLib} -@tab A library system routine in the official lib directory @file{!DIR/lib}. -@item @i{Obsolete} -@tab A library routine in the official lib directory @file{!DIR/lib/obsolete}. -@item @i{Library} -@tab A routine in a file on IDL's search path @code{!PATH}. -@item @i{Other} -@tab Any other routine with a file not known to be on the search path. -@item @i{Unresolved} -@tab An otherwise unknown routine the shell lists as unresolved -(referenced, but not compiled). -@end multitable - -Any routines discovered in library catalogs (@pxref{Library -Catalogs}), will display the category assigned during creation, -e.g., @samp{NasaLib}. For routines not discovered in this way, you can -create additional categories based on the routine's filename using the -variable @code{idlwave-special-lib-alist}. - -@cindex Flags, in routine info -@cindex Duplicate routines -@cindex Multiply defined routines -@cindex Routine definitions, multiple -The flags @code{[LCSB]} indicate the source of the information IDLWAVE -has regarding the file: from a library catalog (@w{@code{[L---]}}), -from a user catalog (@w{@code{[-C--]}}, from the IDL Shell -(@w{@code{[--S-]}}) or from an Emacs buffer (@w{@code{[---B]}}). -Combinations are possible (a compiled library routine visited in a -buffer might read @w{@code{[L-SB]}}). If a file contains multiple -definitions of the same routine, the file name will be prefixed with -@samp{(Nx)} where @samp{N} is the number of definitions. - -@cindex Online Help from the routine info buffer -@cindex Active text, in routine info -@cindex Inserting keywords, from routine info -@cindex Source file, access from routine info -Some of the text in the @file{*Help*} routine info buffer will be active -(it is highlighted when the mouse moves over it). Typically, clicking -with the right mouse button invokes online help lookup, and clicking -with the middle mouse button inserts keywords or visits files: - -@multitable @columnfractions 0.15 0.85 -@item @i{Usage} -@tab If online help is installed, a click with the @emph{right} mouse -button on the @i{Usage:} line will access the help for the -routine (@pxref{Online Help}). -@item @i{Keyword} -@tab Online help about keywords is also available with the -@emph{right} mouse button. Clicking on a keyword with the @emph{middle} -mouse button will insert this keyword in the buffer from where -@code{idlwave-routine-info} was called. Holding down @key{SHIFT} while -clicking also adds the initial @samp{/}. -@item @i{Source} -@tab Clicking with the @emph{middle} mouse button on a @samp{Source} line -finds the source file of the routine and visits it in another window. -Another click on the same line switches back to the buffer from which -@kbd{C-c ?} was called. If you use the @emph{right} mouse button, the -source will not be visited by a buffer, but displayed in the online help -window. -@item @i{Classes} -@tab The @i{Classes} line is only included in the routine info window if -the current class inherits from other classes. You can click with the -@emph{middle} mouse button to display routine info about the current -method in other classes on the inheritance chain, if such a method -exists there. -@end multitable - -@defopt idlwave-resize-routine-help-window (@code{t}) -Non-@code{nil} means resize the Routine-info @file{*Help*} window to -fit the content. -@end defopt - -@defopt idlwave-special-lib-alist -Alist of regular expressions matching special library directories. -@end defopt - -@defopt idlwave-rinfo-max-source-lines (@code{5}) -Maximum number of source files displayed in the Routine Info window. -@end defopt - - -@html - -@end html -@node Online Help -@section Online Help - -@cindex Online Help -@cindex @file{idlw-help.txt} -@cindex @file{idlw-help.el} -@cindex Installing online help -@cindex Online Help, Installation -@cindex Speed, of online help -@cindex XML Help Catalog - -For IDL system routines, extensive documentation is supplied with IDL@. -IDLWAVE can access the HTML version of this documentation very quickly -and accurately, based on the local context. This can be @emph{much} -faster than using the IDL online help application, because IDLWAVE -usually gets you to the right place in the documentation directly---e.g., -a specific keyword of a routine---without any additional browsing -and scrolling. - -For this online help to work, an HTML version of the IDL documentation -is required. Beginning with IDL 6.2, HTML documentation is distributed -directly with IDL, along with an XML-based catalog of routine -information. By default, IDLWAVE automatically attempts to convert this -XML catalog into a format Emacs can more easily understand, and caches -this information in your @code{idlwave_config_directory} -(@file{~/.emacs.d/idlwave/}, by default). It also re-scans the XML catalog if -it is newer than the current cached version. You can force rescan with -the menu entry @code{IDLWAVE->Routine Info->Rescan XML Help Catalog}. - -Before IDL 6.2, the HTML help was not distributed with IDL, and was not -part of the standalone IDLWAVE distribution, but had to be downloaded -separately. This is no longer necessary: all help and routine -information is supplied with IDL versions 6.2 and later. - -There are a variety of options for displaying the HTML help: see below. -Help for routines without HTML documentation is also available, by using -the routine documentation header and/or routine source. - -@kindex M-? -In any IDL program (or, as with most IDLWAVE commands, in the IDL -Shell), press @kbd{M-?} (@code{idlwave-context-help}), or click with -@kbd{S-mouse-3} to access context sensitive online help. The following -locations are recognized context for help: - -@cindex Context, for online help -@multitable @columnfractions .25 .75 -@item @i{Routine names} -@tab The name of a routine (function, procedure, method). -@item @i{Keyword Parameters} -@tab A keyword parameter of a routine. -@item @i{System Variables} -@tab System variables like @code{!DPI}. -@item @i{System Variable Tags} -@tab System variables tags like @code{!D.X_SIZE}. -@item @i{IDL Statements} -@tab Statements like @code{PRO}, @code{REPEAT}, @code{COMPILE_OPT}, etc. -@item @i{IDL Controls} -@tab Control structures like @code{FOR}, @code{SWITCH}, etc. -@item @i{Class names} -@tab A class name in an @code{OBJ_NEW} call. -@item @i{Class Init Keywords} -@tab Beyond the class name in an @code{OBJ_NEW} call. -@item @i{Executive Command} -@tab An executive command like @code{.RUN}. Mostly useful in the shell. -@item @i{Structure Tags} -@tab Structure tags like @code{state.xsize} -@item @i{Class Tags} -@tab Class tags like @code{self.value}. -@item @i{Default} -@tab The routine that would be selected for routine info display. -@end multitable - -@cindex @code{OBJ_NEW}, special online help -Note that the @code{OBJ_NEW} function is special in that the help -displayed depends on the cursor position. If the cursor is on the -@samp{OBJ_NEW}, this function is described. If it is on the class -name inside the quotes, the documentation for the class is pulled up. -If the cursor is @emph{after} the class name, anywhere in the argument -list, the documentation for the corresponding @code{Init} method and -its keywords is targeted. - -Apart from an IDLWAVE buffer or shell, there are two more places from -which online help can be accessed. - -@itemize @bullet -@item -Online help for routines and keywords can be accessed through the -Routine Info display. Click with @kbd{mouse-3} on an item to see the -corresponding help (@pxref{Routine Info}). -@item -When using completion and Emacs pops up a @file{*Completions*} buffer -with possible completions, clicking with @kbd{mouse-3} on a completion -item invokes help on that item (@pxref{Completion}). Items for which -help is available in the online system documentation (vs. just the -program source itself) will be emphasized (e.g., colored blue). -@end itemize -@noindent -In both cases, a blue face indicates that the item is documented in -the IDL manual, but an attempt will be made to visit non-blue items -directly in the originating source file. - - -@menu -* Help with HTML Documentation:: -* Help with Source:: -@end menu - -@node Help with HTML Documentation -@subsection Help with HTML Documentation -@cindex HTML Help -@cindex Help using HTML manuals -@cindex IDL manual, HTML version -@cindex IDL Assistant - -Help using the HTML documentation is invoked with the built-in Emacs -command @code{browse-url}, which displays the relevant help topic in a -browser of your choosing. Beginning with version 6.2, IDL comes with -the help browser @emph{IDL Assistant}, which it uses by default for -displaying online help on all supported platforms. This browser -offers topical searches, an index, and is also now the default and -recommended IDLWAVE help browser. The variable -@code{idlwave-help-use-assistant} controls whether this browser is -used. Note that, due to limitations in the Assistant, invoking help -within IDLWAVE and @code{? topic} within IDL will result in two -running copies of Assistant. - -Aside from the IDL Assistant, there are many possible browsers to choose -among, with differing advantages and disadvantages. The variable -@code{idlwave-help-browser-function} controls which browser help is sent -to (as long as @code{idlwave-help-use-assistant} is not set). This -function is used to set the variable @code{browse-url-browser-function} -locally for IDLWAVE help only. Customize the latter variable to see -what choices of browsers your system offers. Certain browsers like EWW -(@pxref{Top, EWW,, eww, The Emacs Web Wowser Manual}) are run within Emacs, -and use Emacs buffers to display the HTML help. This can be convenient, -especially on small displays, and images can even be displayed in-line -on newer Emacs versions. However, better formatting results are often -achieved with external browsers, like Mozilla. IDLWAVE assumes any -browser function containing "w3" is displayed in a local buffer. If you -are using another Emacs-local browser for which this is not true, set -the variable @code{idlwave-help-browser-is-local}. - -With IDL 6.2 or later, it is important to ensure that the variable -@code{idlwave-system-directory} is set (@pxref{Catalogs}). One easy way -to ensure this is to run the IDL Shell (@kbd{C-c C-s}). It will be -queried for this directory, and the results will be cached to file for -subsequent use. - -@xref{HTML Help Browser Tips}, for more information on selecting and -configuring a browser for use with IDL's HTML help system. - -@defopt idlwave-html-system-help-location @file{help/online_help} -Relative directory of the system-supplied HTML help directory, -considered with respect to @code{idlwave-system-directory}. Relevant -for IDL 6.2 and greater. Should not change. -@end defopt - -@defopt idlwave-html-help-location @file{/usr/local/etc/} -The directory where the @file{idl_html_help} HTML directory live. -Obsolete and ignored for IDL 6.2 and greater -(@code{idlwave-html-system-help-location} is used instead). -@end defopt - -@defopt idlwave-help-use-assistant @code{t} -If set, use the IDL Assistant if possible for online HTML help, -otherwise use the browser function specified in -@code{idlwave-help-browser-function}. -@end defopt - -@defopt idlwave-help-browser-function -The browser function to use to display IDLWAVE HTML help. Should be -one of the functions available for setting -@code{browse-url-browser-function}, which see. -@end defopt - -@defopt idlwave-help-browser-is-local -Is the browser selected in @code{idlwave-help-browser-function} run in a -local Emacs buffer or window? Defaults to @code{t} if the function -contains "-w3". -@end defopt - -@defopt idlwave-help-link-face -The face for links to IDLWAVE online help. -@end defopt - -@node Help with Source -@subsection Help with Source -@cindex Help using routine source - -@cindex Source code, as online help -@cindex DocLib header, as online help -For routines which are not documented in an HTML manual (for example -personal or library routines), the source code itself is used as help -text. If the requested information can be found in a (more or less) -standard DocLib file header, IDLWAVE shows the header (scrolling down to -a keyword, if appropriate). Otherwise the routine definition statement -(@code{pro}/@code{function}) is shown. The doclib header sections which -are searched for include @samp{NAME} and @samp{KEYWORDS}. Localization -support can be added by customizing the @code{idlwave-help-doclib-name} -and @code{idlwave-help-doclib-keyword} variables. - -@cindex Structure tags, in online help -@cindex Class tags, in online help -Help is also available for class structure tags (@code{self.TAG}), and -generic structure tags, if structure tag completion is enabled -(@pxref{Structure Tag Completion}). This is implemented by visiting the -tag within the class or structure definition source itself. Help is not -available on built-in system class tags. - -The help window is normally displayed in the same frame, but can be -popped-up in a separate frame. The following commands can be used to -navigate inside the help system for source files: - -@multitable @columnfractions .15 .85 -@item @kbd{@key{SPACE}} -@tab Scroll forward one page. -@item @kbd{@key{RET}} -@tab Scroll forward one line. -@item @kbd{@key{DEL}} -@tab Scroll back one page. -@item @kbd{h} -@tab Jump to DocLib Header of the routine whose source is displayed -as help. -@item @kbd{H} -@tab Jump to the first DocLib Header in the file. -@item @kbd{.} @r{(Dot)} -@tab Jump back and forth between the routine definition (the -@code{pro}/@code{function} statement) and the description of the help -item in the DocLib header. -@item @kbd{F} -@tab Fontify the buffer like source code. See the variable @code{idlwave-help-fontify-source-code}. -@item @kbd{q} -@tab Kill the help window. -@end multitable - - -@defopt idlwave-help-use-dedicated-frame (@code{nil}) -Non-@code{nil} means use a separate frame for Online Help if possible. -@end defopt - -@defopt idlwave-help-frame-parameters -The frame parameters for the special Online Help frame. -@end defopt - -@defopt idlwave-max-popup-menu-items (@code{20}) -Maximum number of items per pane in pop-up menus. -@end defopt - -@defopt idlwave-extra-help-function -Function to call for help if the normal help fails. -@end defopt - -@defopt idlwave-help-fontify-source-code (@code{nil}) -Non-@code{nil} means fontify source code displayed as help. -@end defopt - -@defopt idlwave-help-source-try-header (@code{t}) -Non-@code{nil} means try to find help in routine header when -displaying source file. -@end defopt - -@defopt idlwave-help-doclib-name (@code{"name"}) -The case-insensitive heading word in doclib headers to locate the -@emph{name} section. Can be a regexp, e.g., @code{"\\(name\\|nom\\)"}. -@end defopt - -@defopt idlwave-help-doclib-keyword (@code{"KEYWORD"}) -The case-insensitive heading word in doclib headers to locate the -@emph{keywords} section. Can be a regexp. -@end defopt - - -@node Completion -@section Completion -@cindex Completion -@cindex Keyword completion -@cindex Method completion -@cindex Object method completion -@cindex Class name completion -@cindex Function name completion -@cindex Procedure name completion - -@kindex M-TAB -@kindex C-c C-i -IDLWAVE offers completion for class names, routine names, keywords, -system variables, system variable tags, class structure tags, regular -structure tags and file names. As in many programming modes, completion -is bound to @kbd{M-@key{TAB}} (or simply @kbd{@key{TAB}} in the IDLWAVE -Shell; @pxref{Using the Shell}). Completion uses exactly the same -internal information as routine info, so when necessary (rarely) it can -be updated with @kbd{C-c C-i} (@code{idlwave-update-routine-info}). - -The completion function is context sensitive and figures out what to -complete based on the location of the point. Here are example lines and -what @kbd{M-@key{TAB}} would try to complete when the cursor is on the -position marked with a @samp{_}: - -@example -plo_ @r{Procedure} -x = a_ @r{Function} -plot,xra_ @r{Keyword of @code{plot} procedure} -plot,x,y,/x_ @r{Keyword of @code{plot} procedure} -plot,min(_ @r{Keyword of @code{min} function} -obj -> a_ @r{Object method (procedure)} -a[2,3] = obj -> a_ @r{Object method (function)} -x = obj_new('IDL_ @r{Class name} -x = obj_new('MyCl',a_ @r{Keyword to @code{Init} method in class @code{MyCl}} -pro A_ @r{Class name} -pro _ @r{Fill in @code{Class::} of first method in this file} -!v_ @r{System variable} -!version.t_ @r{Structure tag of system variable} -self.g_ @r{Class structure tag in methods} -state.w_ @r{Structure tag, if tag completion enabled} -name = 'a_ @r{File name (default inside quotes)} -@end example - -@cindex Completion, ambiguity -@cindex Completion, forcing function name -The only place where completion is ambiguous is procedure/function -@emph{keywords} versus @emph{functions}. After @samp{plot,x,_}, IDLWAVE -will always assume a keyword to @samp{plot}. However, a function is -also a possible completion here. You can force completion of a function -name at such a location by using a prefix arg: @kbd{C-u M-@key{TAB}}. - -Giving two prefix arguments (@kbd{C-u C-u M-@key{TAB}}) prompts for a -regular expression to search among the commands to be completed. As -an example, completing a blank line in this way will allow you to -search for a procedure matching a regexp. - -@cindex Scrolling the @file{*Completions*} window -@cindex Completion, scrolling -@cindex Completion, Online Help -@cindex Online Help in @file{*Completions*} buffer -If the list of completions is too long to fit in the -@file{*Completions*} window, the window can be scrolled by pressing -@kbd{M-@key{TAB}} repeatedly. Online help (if installed) for each -possible completion is available by clicking with @kbd{mouse-3} on the -item. Items for which system online help (from the IDL manual) is -available will be emphasized (e.g., colored blue). For other items, the -corresponding source code or DocLib header will be used as the help -text. - -@cindex Completion, canceling -@cindex Canceling completion -Completion is not a blocking operation; you are free to continue -editing, enter commands, or simply ignore the @file{*Completions*} -buffer during a completion operation. If, however, the most recent -command was a completion, @kbd{C-g} will remove the buffer and restore -the window configuration. You can also remove the buffer at any time -with no negative consequences. - -@defopt idlwave-keyword-completion-adds-equal (@code{t}) -Non-@code{nil} means completion automatically adds @samp{=} after -completed keywords. -@end defopt - -@defopt idlwave-function-completion-adds-paren (@code{t}) -Non-@code{nil} means completion automatically adds @samp{(} after -completed function. A value of 2 means also add the closing -parenthesis and position the cursor between the two. -@end defopt - -@defopt idlwave-completion-restore-window-configuration (@code{t}) -Non-@code{nil} means restore window configuration after successful -completion. -@end defopt - -@defopt idlwave-highlight-help-links-in-completion (@code{t}) -Non-@code{nil} means highlight completions for which system help is -available. -@end defopt - -@menu -* Case of Completed Words:: CaseOFcomPletedWords -* Object Method Completion and Class Ambiguity:: obj->Method, what? -* Object Method Completion in the Shell:: -* Class and Keyword Inheritance:: obj->Method, _EXTRA=e -* Structure Tag Completion:: Completing state.Tag -@end menu - -@node Case of Completed Words -@subsection Case of Completed Words -@cindex Case of completed words -@cindex Mixed case completion -IDL is a case-insensitive language, so casing is a matter of style -only. IDLWAVE helps maintain a consistent casing style for completed -items. The case of the completed words is determined by what is -already in the buffer. As an exception, when the partial word being -completed is all lower case, the completion will be lower case as -well. If at least one character is upper case, the string will be -completed in upper case or mixed case, depending on the value of the -variable @code{idlwave-completion-case}. The default is to use upper -case for procedures, functions and keywords, and mixed case for object -class names and methods, similar to the conventions in the IDL -manuals. For instance, to enable mixed-case completion for routines -in addition to classes and methods, you need an entry such as -@code{(routine . preserve)} in that variable. To enable total control -over the case of completed items, independent of buffer context, set -@code{idlwave-completion-force-default-case} to non-@code{nil}. - -@defopt idlwave-completion-case -Association list setting the case (UPPER/lower/Capitalized/MixedCase...) -of completed words. -@end defopt - -@defopt idlwave-completion-force-default-case (@code{nil}) -Non-@code{nil} means completion will always honor the settings in -@code{idlwave-completion-case}. When @code{nil} (the default), entirely lower -case strings will always be completed to lower case, no matter what the -settings in @code{idlwave-completion-case}. -@end defopt - -@defopt idlwave-complete-empty-string-as-lower-case (@code{nil}) -Non-@code{nil} means the empty string is considered lower case for -completion. -@end defopt - -@node Object Method Completion and Class Ambiguity -@subsection Object Method Completion and Class Ambiguity -@cindex Object methods -@cindex Class ambiguity -@cindex @code{self} object, default class -An object method is not uniquely determined without the object's class. -Since the class is almost always omitted in the calling source (as -required to obtain the true benefits of object-based programming), -IDLWAVE considers all available methods in all classes as possible -method name completions. The combined list of keywords of the current -method in @emph{all} known classes which contain that method will be -considered for keyword completion. In the @file{*Completions*} buffer, -the matching classes will be shown next to each item (see option -@code{idlwave-completion-show-classes}). As a special case, the class -of an object called @samp{self} is always taken to be the class of the -current routine, when in an IDLWAVE buffer. All inherits classes are -considered as well. - -@cindex Forcing class query. -@cindex Class query, forcing -You can also call @code{idlwave-complete} with a prefix arg: @kbd{C-u -M-@key{TAB}}. IDLWAVE will then prompt you for the class in order to -narrow down the number of possible completions. The variable -@code{idlwave-query-class} can be configured to make such prompting the -default for all methods (not recommended), or selectively for very -common methods for which the number of completing keywords would be too -large (e.g., @code{Init,SetProperty,GetProperty}). - -@cindex Saving object class on @code{->} -@cindex @code{->} -After you have specified the class for a particular statement (e.g., when -completing the method), IDLWAVE can remember it for the rest of the -editing session. Subsequent completions in the same statement -(e.g., keywords) can then reuse this class information. This works by -placing a text property on the method invocation operator @samp{->}, -after which the operator will be shown in a different face (bold by -default). The variable @code{idlwave-store-inquired-class} can be used -to turn it off or on. - -@defopt idlwave-completion-show-classes (@code{1}) -Non-@code{nil} means show up to that many classes in -@file{*Completions*} buffer when completing object methods and -keywords. -@end defopt - -@defopt idlwave-completion-fontify-classes (@code{t}) -Non-@code{nil} means fontify the classes in completions buffer. -@end defopt - -@defopt idlwave-query-class (@code{nil}) -Association list governing query for object classes during completion. -@end defopt - -@defopt idlwave-store-inquired-class (@code{t}) -Non-@code{nil} means store class of a method call as text property on -@samp{->}. -@end defopt - -@defopt idlwave-class-arrow-face -Face to highlight object operator arrows @samp{->} which carry a saved -class text property. -@end defopt - -@node Object Method Completion in the Shell -@subsection Object Method Completion in the Shell -@cindex Method Completion in Shell -In the IDLWAVE Shell (@pxref{The IDLWAVE Shell}), objects on which -methods are being invoked have a special property: they must exist as -variables, and so their class can be determined (for instance, using the -@code{obj_class()} function). In the Shell, when attempting completion, -routine info, or online help within a method routine, a query is sent to -determine the class of the object. If this query is successful, the -class found will be used to select appropriate completions, routine -info, or help. If unsuccessful, information from all known classes will -be used (as in the buffer). - -@node Class and Keyword Inheritance -@subsection Class and Keyword Inheritance -@cindex Inheritance, class -@cindex Keyword inheritance -@cindex Inheritance, keyword - -Class inheritance affects which methods are called in IDL@. An object of -a class which inherits methods from one or more superclasses can -override that method by defining its own method of the same name, extend -the method by calling the method(s) of its superclass(es) in its -version, or inherit the method directly by making no modifications. -IDLWAVE examines class definitions during completion and routine -information display, and records all inheritance information it finds. -This information is displayed if appropriate with the calling sequence -for methods (@pxref{Routine Info}), as long as variable -@code{idlwave-support-inheritance} is non-@code{nil}. - -In many class methods, @emph{keyword} inheritance (@code{_EXTRA} and -@code{_REF_EXTRA}) is used hand-in-hand with class inheritance and -method overriding. E.g., in a @code{SetProperty} method, this technique -allows a single call @code{obj->SetProperty} to set properties up the -entire class inheritance chain. This is often referred to as -@emph{chaining}, and is characterized by chained method calls like -@w{@code{self->MySuperClass::SetProperty,_EXTRA=e}}. - -IDLWAVE can accommodate this special synergy between class and keyword -inheritance: if @code{_EXTRA} or @code{_REF_EXTRA} is detected among a -method's keyword parameters, all keywords of superclass versions of -the method being considered can be included in completion. There is -of course no guarantee that this type of keyword chaining actually -occurs, but for some methods it's a very convenient assumption. The -variable @code{idlwave-keyword-class-inheritance} can be used to -configure which methods have keyword inheritance treated in this -simple, class-driven way. By default, only @code{Init} and -@code{(Get|Set)Property} are. The completion buffer will label -keywords based on their originating class. - -@defopt idlwave-support-inheritance (@code{t}) -Non-@code{nil} means consider inheritance during completion, online help etc. -@end defopt - -@defopt idlwave-keyword-class-inheritance -A list of regular expressions to match methods for which simple -class-driven keyword inheritance will be used for Completion. -@end defopt - -@node Structure Tag Completion -@subsection Structure Tag Completion -@cindex Completion, structure tag -@cindex Structure tag completion - -In many programs, especially those involving widgets, large structures -(e.g., the @samp{state} structure) are used to communicate among -routines. It is very convenient to be able to complete structure tags, -in the same way as for instance variables (tags) of the @samp{self} -object (@pxref{Object Method Completion and Class Ambiguity}). Add-in -code for structure tag completion is available in the form of a loadable -completion module: @file{idlw-complete-structtag.el}. Tag completion in -structures is highly ambiguous (much more so than @samp{self} -completion), so @code{idlw-complete-structtag} makes an unusual and very -specific assumption: the exact same variable name is used to refer to -the structure in all parts of the program. This is entirely unenforced -by the IDL language, but is a typical convention. If you consistently -refer to the same structure with the same variable name -(e.g., @samp{state}), structure tags which are read from its definition -in the same file can be used for completion. - -Structure tag completion is not enabled by default. To enable it, -simply add the following to your @file{.emacs}: - -@lisp -(with-eval-after-load 'idlwave - (require 'idlw-complete-structtag)) -@end lisp - -Once enabled, you'll also be able to access online help on the structure -tags, using the usual methods (@pxref{Online Help}). In addition, -structure variables in the shell will be queried for tag names, similar -to the way object variables in the shell are queried for method names. -So, e.g.: - -@example -IDL> st.[Tab] -@end example - -@noindent will complete with all structure fields of the structure -@code{st}. - -@node Routine Source -@section Routine Source -@cindex Routine source file -@cindex Module source file -@cindex Source file, of a routine -@kindex C-c C-v -In addition to clicking on a @i{Source:} line in the routine info -window, there is another way to quickly visit the source file of a -routine. The command @kbd{C-c C-v} (@code{idlwave-find-module}) asks -for a module name, offering the same default as -@code{idlwave-routine-info} would have used, taken from nearby buffer -contents. In the minibuffer, specify a complete routine name (including -any class part). IDLWAVE will display the source file in another -window, positioned at the routine in question. You can also limit this -to a routine in the current buffer only, with completion, and a -context-sensitive default, by using a single prefix (@kbd{C-u C-c C-v}) -or the convenience binding @kbd{C-c C-t}. - -@cindex Buffers, killing -@cindex Killing autoloaded buffers -Since getting the source of a routine into a buffer is so easy with -IDLWAVE, too many buffers visiting different IDL source files are -sometimes created. The special command @kbd{C-c C-k} -(@code{idlwave-kill-autoloaded-buffers}) can be used to easily remove -these buffers. - -@node Resolving Routines -@section Resolving Routines -@cindex @code{RESOLVE_ROUTINE} -@cindex Compiling library modules -@cindex Routines, resolving - -The key sequence @kbd{C-c =} calls the command @code{idlwave-resolve} -and sends the line @samp{RESOLVE_ROUTINE, '@var{routine_name}'} to IDL -in order to resolve (compile) it. The default routine to be resolved is -taken from context, but you get a chance to edit it. Usually this is -not necessary, since IDL automatically discovers routines on its path. - -@code{idlwave-resolve} is one way to get a library module within reach -of IDLWAVE's routine info collecting functions. A better way is to -keep routine information available in catalogs (@pxref{Catalogs}). -Routine info on modules will then be available without the need to -compile the modules first, and even without a running shell. - -@xref{Sources of Routine Info}, for more information on the ways IDLWAVE -collects data about routines, and how to update this information. - -@node Code Templates -@section Code Templates -@cindex Code templates -@cindex Templates - -IDLWAVE can insert IDL code templates into the buffer. For a few -templates, this is done with direct key bindings: - -@multitable @columnfractions .15 .85 -@item @kbd{C-c C-c} -@tab @code{CASE} statement template -@item @kbd{C-c C-f} -@tab @code{FOR} loop template -@item @kbd{C-c C-r} -@tab @code{REPEAT} loop template -@item @kbd{C-c C-w} -@tab @code{WHILE} loop template -@end multitable - -All code templates are also available as abbreviations -(@pxref{Abbreviations}). - -@node Abbreviations -@section Abbreviations -@cindex Abbreviations - -Special abbreviations exist to enable rapid entry of commonly used -commands. Emacs abbreviations are expanded by typing text into the -buffer and pressing @key{SPC} or @key{RET}. The special abbreviations -used to insert code templates all start with a @samp{\} (the backslash), -or, optionally, any other character set in -@code{idlwave-abbrev-start-char}. IDLWAVE ensures that abbreviations are -only expanded where they should be (i.e., not in a string or comment), -and permits the point to be moved after an abbreviation expansion: -very useful for positioning the mark inside of parentheses, etc. - -Special abbreviations are pre-defined for code templates and other -useful items. To visit the full list of abbreviations, use @kbd{M-x -idlwave-list-abbrevs}. - -Template abbreviations: - -@multitable @columnfractions .15 .85 -@item @code{\pr} -@tab @code{PROCEDURE} template -@item @code{\fu} -@tab @code{FUNCTION} template -@item @code{\c} -@tab @code{CASE} statement template -@item @code{\f} -@tab @code{FOR} loop template -@item @code{\r} -@tab @code{REPEAT} loop template -@item @code{\w} -@tab @code{WHILE} loop template -@item @code{\i} -@tab @code{IF} statement template -@item @code{\elif} -@tab @code{IF-ELSE} statement template -@end multitable - -String abbreviations: - -@multitable @columnfractions .15 .85 -@item @code{\ap} -@tab @code{arg_present()} -@item @code{\b} -@tab @code{begin} -@item @code{\cb} -@tab @code{byte()} -@item @code{\cc} -@tab @code{complex()} -@item @code{\cd} -@tab @code{double()} -@item @code{\cf} -@tab @code{float()} -@item @code{\cl} -@tab @code{long()} -@item @code{\co} -@tab @code{common} -@item @code{\cs} -@tab @code{string()} -@item @code{\cx} -@tab @code{fix()} -@item @code{\e} -@tab @code{else} -@item @code{\ec} -@tab @code{endcase} -@item @code{\ee} -@tab @code{endelse} -@item @code{\ef} -@tab @code{endfor} -@item @code{\ei} -@tab @code{endif else if} -@item @code{\el} -@tab @code{endif else} -@item @code{\en} -@tab @code{endif} -@item @code{\er} -@tab @code{endrep} -@item @code{\es} -@tab @code{endswitch} -@item @code{\ew} -@tab @code{endwhile} -@item @code{\g} -@tab @code{goto,} -@item @code{\h} -@tab @code{help,} -@item @code{\ik} -@tab @code{if keyword_set() then} -@item @code{\iap} -@tab @code{if arg_present() then} -@item @code{\ine} -@tab @code{if n_elements() eq 0 then} -@item @code{\inn} -@tab @code{if n_elements() ne 0 then} -@item @code{\k} -@tab @code{keyword_set()} -@item @code{\n} -@tab @code{n_elements()} -@item @code{\np} -@tab @code{n_params()} -@item @code{\oi} -@tab @code{on_ioerror,} -@item @code{\or} -@tab @code{openr,} -@item @code{\ou} -@tab @code{openu,} -@item @code{\ow} -@tab @code{openw,} -@item @code{\p} -@tab @code{print,} -@item @code{\pt} -@tab @code{plot,} -@item @code{\pv} -@tab @code{ptr_valid()} -@item @code{\re} -@tab @code{read,} -@item @code{\rf} -@tab @code{readf,} -@item @code{\rt} -@tab @code{return} -@item @code{\ru} -@tab @code{readu,} -@item @code{\s} -@tab @code{size()} -@item @code{\sc} -@tab @code{strcompress()} -@item @code{\sl} -@tab @code{strlowcase()} -@item @code{\sm} -@tab @code{strmid()} -@item @code{\sn} -@tab @code{strlen()} -@item @code{\sp} -@tab @code{strpos()} -@item @code{\sr} -@tab @code{strtrim()} -@item @code{\st} -@tab @code{strput()} -@item @code{\su} -@tab @code{strupcase()} -@item @code{\t} -@tab @code{then} -@item @code{\u} -@tab @code{until} -@item @code{\wc} -@tab @code{widget_control,} -@item @code{\wi} -@tab @code{widget_info()} -@item @code{\wu} -@tab @code{writeu,} -@end multitable - -@noindent You can easily add your own abbreviations or override existing -abbrevs with @code{define-abbrev} in your mode hook, using the -convenience function @code{idlwave-define-abbrev}: - -@lisp -(add-hook 'idlwave-mode-hook - (lambda () - (idlwave-define-abbrev "wb" "widget_base()" - (idlwave-keyword-abbrev 1)) - (idlwave-define-abbrev "ine" "IF N_Elements() EQ 0 THEN" - (idlwave-keyword-abbrev 11)))) -@end lisp - -Notice how the abbreviation (here @emph{wb}) and its expansion -(@emph{widget_base()}) are given as arguments, and the single argument to -@code{idlwave-keyword-abbrev} (here @emph{1}) specifies how far back to -move the point upon expansion (in this example, to put it between the -parentheses). - -The abbreviations are expanded in upper or lower case, depending upon -the variables @code{idlwave-abbrev-change-case} and, for reserved word -templates, @code{idlwave-reserved-word-upcase} (@pxref{Case Changes}). - -@defopt idlwave-abbrev-start-char (@code{"\"}) -A single character string used to start abbreviations in abbrev mode. -Beware of common characters which might naturally occur in sequence with -abbreviation strings. -@end defopt - -@defopt idlwave-abbrev-move (@code{t}) -Non-@code{nil} means the abbrev hook can move point, e.g., to end up -between the parentheses of a function call. -@end defopt - -@node Actions -@section Actions -@cindex Actions -@cindex Coding standards, enforcing - -@emph{Actions} are special formatting commands which are executed -automatically while you write code in order to check the structure of -the program or to enforce coding standards. Most actions which have -been implemented in IDLWAVE are turned off by default, assuming that the -average user wants her code the way she writes it. But if you are a -lazy typist and want your code to adhere to certain standards, actions -can be helpful. - -Actions can be applied in three ways: - -@itemize @bullet -@item -Some actions are applied directly while typing. For example, pressing -@samp{=} can run a check to make sure that this operator is surrounded -by spaces and insert these spaces if necessary. Pressing @key{SPC} -after a reserved word can call a command to change the word to upper -case. -@item -When a line is re-indented with @key{TAB}, actions can be applied to the -entire line. To enable this, the variable @code{idlwave-do-actions} -must be non-@code{nil}. -@item -@cindex Foreign code, adapting -@cindex Actions, applied to foreign code -Actions can also be applied to a larger piece of code, e.g., to convert -foreign code to your own style. To do this, mark the relevant part of -the code and execute @kbd{M-x expand-region-abbrevs}. Useful marking -commands are @kbd{C-x h} (the entire file) or @kbd{C-M-h} (the current -subprogram). @xref{Code Indentation}, for information how to adjust the -indentation of the code. -@end itemize - -@defopt idlwave-do-actions (@code{nil}) -Non-@code{nil} means performs actions when indenting. Individual action -settings are described below and set separately. -@end defopt - -@menu -* Block Boundary Check:: Is the END statement correct? -* Padding Operators:: Enforcing space around @samp{=} etc -* Case Changes:: Enforcing upper case keywords -@end menu - -@node Block Boundary Check -@subsection Block Boundary Check -@cindex Block boundary check -@cindex @code{END} type checking -@cindex @code{END}, automatic insertion -@cindex @code{END}, expanding -@cindex Block, closing -@cindex Closing a block - -Whenever you type an @code{END} statement, IDLWAVE finds the -corresponding start of the block and the cursor blinks back to that -location for a second. If you have typed a specific @code{END}, like -@code{ENDIF} or @code{ENDCASE}, you get a warning if that terminator -does not match the type of block it terminates. - -Set the variable @code{idlwave-expand-generic-end} in order to have all -generic @code{END} statements automatically expanded to the appropriate -type. You can also type @kbd{C-c ]} to close the current block by -inserting the appropriate @code{END} statement. - -@defopt idlwave-show-block (@code{t}) -Non-@code{nil} means point blinks to block beginning for -@code{idlwave-show-begin}. -@end defopt - -@defopt idlwave-expand-generic-end (@code{t}) -Non-@code{nil} means expand generic END to ENDIF/ENDELSE/ENDWHILE etc. -@end defopt - -@defopt idlwave-reindent-end (@code{t}) -Non-@code{nil} means re-indent line after END was typed. -@end defopt - -@node Padding Operators -@subsection Padding Operators -@cindex Padding operators with spaces -@cindex Operators, padding with spaces -@cindex Space, around operators - -Some operators can be automatically surrounded by spaces. This can -happen when the operator is typed, or later when the line is indented. -IDLWAVE can pad the operators @samp{<}, @samp{>}, @samp{,}, @samp{=}, -and @samp{->}, as well as the modified assignment operators -(@samp{AND=}, @samp{OR=}, etc.). This feature is turned off by default. -If you want to turn it on, customize the variables -@code{idlwave-surround-by-blank} and @code{idlwave-do-actions} and turn -both on. You can also define similar actions for other operators by -using the function @code{idlwave-action-and-binding} in the mode hook. -For example, to enforce space padding of the @samp{+} and @samp{*} -operators (outside of strings and comments, of course), try this in -@file{.emacs} - -@lisp -(add-hook 'idlwave-mode-hook - (lambda () - (setq idlwave-surround-by-blank t) ; Turn this type of actions on - (idlwave-action-and-binding "*" '(idlwave-surround 1 1)) - (idlwave-action-and-binding "+" '(idlwave-surround 1 1)))) -@end lisp - -Note that the modified assignment operators which begin with a word -(@samp{AND=}, @samp{OR=}, @samp{NOT=}, etc.)@: require a leading space to -be recognized (e.g., @code{vAND=4} would be interpreted as a variable -@code{vAND}). Also note that since, e.g., @code{>} and @code{>=} are -both valid operators, it is impossible to surround both by blanks while -they are being typed. Similarly with @code{&} and @code{&&}. For -these, a compromise is made: the padding is placed on the left, and if -the longer operator is keyed in, on the right as well (otherwise you -must insert spaces to pad right yourself, or press simply press Tab to -repad everything if @code{idlwave-do-actions} is on). - -@defopt idlwave-surround-by-blank (@code{nil}) -Non-@code{nil} means enable @code{idlwave-surround}. If non-@code{nil}, -@samp{=}, @samp{<}, @samp{>}, @samp{&}, @samp{,}, @samp{->}, and the -modified assignment operators (@samp{AND=}, @samp{OR=}, etc.)@: are -surrounded with spaces by @code{idlwave-surround}. -@end defopt - -@defopt idlwave-pad-keyword (@code{t}) -Non-@code{nil} means space-pad the @samp{=} in keyword assignments. -@end defopt - -@node Case Changes -@subsection Case Changes -@cindex Case changes -@cindex Upcase, enforcing for reserved words -@cindex Downcase, enforcing for reserved words - -Actions can be used to change the case of reserved words or expanded -abbreviations by customizing the variables -@code{idlwave-abbrev-change-case} and -@code{idlwave-reserved-word-upcase}. If you want to change the case of -additional words automatically, put something like the following into -your @file{.emacs} file: - -@lisp -(add-hook 'idlwave-mode-hook - (lambda () - ;; Capitalize system vars - (idlwave-action-and-binding idlwave-sysvar '(capitalize-word 1) t) - ;; Capitalize procedure name - (idlwave-action-and-binding "\\<\\(pro\\|function\\)\\>[ \t]*\\<" - '(capitalize-word 1) t) - ;; Capitalize common block name - (idlwave-action-and-binding "\\[ \t]+\\<" - '(capitalize-word 1) t))) -@end lisp - -For more information, see the documentation string for the function -@code{idlwave-action-and-binding}. For information on controlling the -case of routines, keywords, classes, and methods as they are completed, see -@ref{Completion}. - -@defopt idlwave-abbrev-change-case (@code{nil}) -Non-@code{nil} means all abbrevs will be forced to either upper or lower -case. Valid values are @code{nil}, @code{t}, and @code{down}. -@end defopt - -@defopt idlwave-reserved-word-upcase (@code{nil}) -Non-@code{nil} means reserved words will be made upper case via abbrev -expansion. -@end defopt - - -@node Doc Header -@section Documentation Header -@cindex Documentation header -@cindex DocLib header -@cindex Modification timestamp -@cindex Header, for file documentation -@cindex Timestamp, in doc header. -@cindex Changelog, in doc header. - -@kindex C-c C-h -@kindex C-c C-m -The command @kbd{C-c C-h} inserts a standard routine header into the -buffer, with the usual fields for documentation (a different header can -be specified with @code{idlwave-file-header}). One of the keywords is -@samp{MODIFICATION HISTORY} under which the changes to a routine can be -recorded. The command @kbd{C-c C-m} jumps to the @samp{MODIFICATION -HISTORY} of the current routine or file and inserts the user name with a -timestamp. - -@defopt idlwave-file-header -The doc-header template or a path to a file containing it. -@end defopt - -@defopt idlwave-header-to-beginning-of-file (@code{nil}) -Non-@code{nil} means the documentation header will always be at start -of file. -@end defopt - -@defopt idlwave-timestamp-hook -The hook function used to update the timestamp of a function. -@end defopt - -@defopt idlwave-doc-modifications-keyword -The modifications keyword to use with the log documentation commands. -@end defopt - -@defopt idlwave-doclib-start -Regexp matching the start of a document library header. -@end defopt - -@defopt idlwave-doclib-end -Regexp matching the start of a document library header. -@end defopt - -@node Motion Commands -@section Motion Commands -@cindex Motion commands -@cindex Program structure, moving through -@cindex Code structure, moving through -@cindex @file{Imenu} -@cindex Function definitions, jumping to -@cindex Procedure definitions, jumping to - -IDLWAVE supports @file{Imenu}, a package -which make it easy to jump to the definitions of functions and -procedures in the current file with a pop-up selection. To bind -@file{Imenu} to a mouse-press, use in your @file{.emacs}: - -@lisp -(define-key global-map [S-down-mouse-3] 'imenu) -@end lisp - -@cindex @file{Speedbar}, Emacs package - -In addition, @file{Speedbar} support allows convenient navigation of a -source tree of IDL routine files, quickly stepping to routine -definitions. See @code{Tools->Display Speedbar}. - -Several commands allow you to move quickly through the structure of an -IDL program: - -@multitable @columnfractions .15 .85 -@item @kbd{C-M-a} -@tab Beginning of subprogram -@item @kbd{C-M-e} -@tab End of subprogram -@item @kbd{C-c @{} -@tab Beginning of block (stay inside the block) -@item @kbd{C-c @}} -@tab End of block (stay inside the block) -@item @kbd{C-M-n} -@tab Forward block (on same level) -@item @kbd{C-M-p} -@tab Backward block (on same level) -@item @kbd{C-M-d} -@tab Down block (enters a block) -@item @kbd{C-M-u} -@tab Backward up block (leaves a block) -@item @kbd{C-c C-n} -@tab Next Statement -@end multitable - - -@node Misc Options -@section Miscellaneous Options -@cindex Hooks - -@defopt idlwave-help-application -The external application providing reference help for programming. -@end defopt - -@defopt idlwave-startup-message (@code{t}) -Non-@code{nil} means display a startup message when @code{idlwave-mode}' -is first called. -@end defopt - -@defopt idlwave-mode-hook -Normal hook. Executed when a buffer is put into @code{idlwave-mode}. -@end defopt - -@node The IDLWAVE Shell -@chapter The IDLWAVE Shell -@cindex IDLWAVE shell -@cindex Major mode, @code{idlwave-shell-mode} -@cindex IDL, as Emacs subprocess -@cindex Subprocess of Emacs, IDL -@cindex Comint, Emacs package -@cindex Windows -@cindex macOS - -The IDLWAVE shell is an Emacs major mode which permits running the IDL -program as an inferior process of Emacs, and works closely with the -IDLWAVE major mode in buffers. It can be used to work with IDL -interactively, to compile and run IDL programs in Emacs buffers and to -debug these programs. The IDLWAVE shell is built on @file{comint}, an -Emacs packages which handles the communication with the IDL program. -Unfortunately, IDL for Windows does not have command-prompt versions and -thus do not allow the interaction with Emacs, so the IDLWAVE shell -currently works under only Unix and macOS. - -@menu -* Starting the Shell:: How to launch IDL as a subprocess -* Using the Shell:: Interactively working with the Shell -* Commands Sent to the Shell:: -* Debugging IDL Programs:: -* Examining Variables:: -* Custom Expression Examination:: -@end menu - -@node Starting the Shell -@section Starting the Shell -@cindex Starting the shell -@cindex Shell, starting -@cindex Dedicated frame, for shell buffer -@cindex Frame, for shell buffer -@cindex Subprocess of Emacs, IDL - -@kindex C-c C-s -The IDLWAVE shell can be started with the command @kbd{M-x -idlwave-shell}. In @code{idlwave-mode} the function is bound to -@kbd{C-c C-s}. It creates a buffer @file{*idl*} which is used to -interact with the shell. If the shell is already running, @kbd{C-c -C-s} will simply switch to the shell buffer. The command @kbd{C-c -C-l} (@code{idlwave-shell-recenter-shell-window}) displays the shell -window without selecting it. The shell can also be started -automatically when another command tries to send a command to it. To -enable auto start, set the variable -@code{idlwave-shell-automatic-start} to @code{t}. - -In order to create a separate frame for the IDLWAVE shell buffer, call -@code{idlwave-shell} with a prefix argument: @kbd{C-u C-c C-s} or -@kbd{C-u C-c C-l}. If you always want a dedicated frame for the shell -window, configure the variable -@code{idlwave-shell-use-dedicated-frame}. - -To launch a quick IDLWAVE shell directly from a shell prompt without -an IDLWAVE buffer (e.g., as a replacement for running inside an -xterm), define a system alias with the following content: - -@example -emacs -geometry 80x32 -eval "(idlwave-shell 'quick)" -@end example - -Replace the @samp{-geometry 80x32} option with @samp{-nw} if you prefer -the Emacs process to run directly inside the terminal window. - -@cindex ENVI -@cindex IDL> Prompt - -To use IDLWAVE with ENVI or other custom packages which change the -@samp{IDL> } prompt, you must change the -@code{idlwave-shell-prompt-pattern}, which defaults to @samp{"^ ?IDL> -"}. Normally, you can just replace the @samp{IDL} in this expression -with the prompt you see. A suitable pattern which matches the prompt -for both ENVI and IDL simultaneously is @samp{"^ ?\\(ENVI\\|IDL\\)> "}. - -@defopt idlwave-shell-explicit-file-name (@file{idl}) -This is the command to run IDL. -@end defopt - -@defopt idlwave-shell-command-line-options -A list of command line options for calling the IDL program. -@end defopt - -@defopt idlwave-shell-prompt-pattern -Regexp to match IDL prompt at beginning of a line. -@end defopt - -@defopt idlwave-shell-process-name -Name to be associated with the IDL process. -@end defopt - -@defopt idlwave-shell-automatic-start (@code{nil}) -Non-@code{nil} means attempt to invoke idlwave-shell if not already -running. -@end defopt - -@defopt idlwave-shell-initial-commands -Initial commands, separated by newlines, to send to IDL. -@end defopt - -@defopt idlwave-shell-save-command-history (@code{t}) -Non-@code{nil} means preserve command history between sessions. -@end defopt - -@defopt idlwave-shell-command-history-file (@file{~/.emacs.d/idlwave/.idlwhist}) -The file in which the command history of the idlwave shell is saved. -Unless it's an absolute path, it goes in -@code{idlwave-config-directory}. -@end defopt - -@defopt idlwave-shell-use-dedicated-frame (@code{nil}) -Non-@code{nil} means IDLWAVE should use a special frame to display the -shell buffer. -@end defopt - -@defopt idlwave-shell-use-dedicated-window (@code{nil}) -Non-@code{nil} means use a dedicated window for the shell, taking care -not it replace it with other buffers. -@end defopt - -@defopt idlwave-shell-frame-parameters -The frame parameters for a dedicated idlwave-shell frame. -@end defopt - -@defopt idlwave-shell-raise-frame (@code{t}) -Non-@code{nil} means @code{idlwave-shell} raises the frame showing the shell -window. -@end defopt - -@defopt idlwave-shell-temp-pro-prefix -The prefix for temporary IDL files used when compiling regions. -@end defopt - -@cindex Hooks -@defopt idlwave-shell-mode-hook -Hook for customizing @code{idlwave-shell-mode}. -@end defopt - -@node Using the Shell -@section Using the Shell -@cindex Comint -@cindex Shell, basic commands - -The IDLWAVE shell works in the same fashion as other shell modes in -Emacs. It provides command history, command line editing and job -control. The @key{UP} and @key{DOWN} arrows cycle through the input -history just like in an X terminal@footnote{This is different from -normal Emacs/Comint behavior, but more like an xterm. If you prefer the -default comint functionality, check the variable -@code{idlwave-shell-arrows-do-history}.}. The history is preserved -between emacs and IDL sessions. Here is a list of commonly used -commands: - -@multitable @columnfractions .12 .88 -@item @key{UP}, @kbd{M-p} -@tab Cycle backwards in input history -@item @key{DOWN}, @kbd{M-n} -@tab Cycle forwards in input history -@item @kbd{M-r} -@tab Previous input matching a regexp -@item @kbd{M-s} -@tab Next input matching a regexp -@item @kbd{return} -@tab Send input or copy line to current prompt -@item @kbd{C-c C-a} -@tab Beginning of line; skip prompt -@item @kbd{C-c C-u} -@tab Kill input to beginning of line -@item @kbd{C-c C-w} -@tab Kill word before cursor -@item @kbd{C-c C-c} -@tab Send ^C -@item @kbd{C-c C-z} -@tab Send ^Z -@item @kbd{C-c C-\} -@tab Send ^\ -@item @kbd{C-c C-o} -@tab Delete last batch of process output -@item @kbd{C-c C-r} -@tab Show last batch of process output -@item @kbd{C-c C-l} -@tab List input history -@end multitable - -In addition to these standard @file{comint} commands, -@code{idlwave-shell-mode} provides many of the same commands which -simplify writing IDL code available in IDLWAVE buffers. This includes -abbreviations, online help, and completion. See @ref{Routine Info} and -@ref{Online Help} and @ref{Completion} for more information on these -commands. - -@cindex Completion, in the shell -@cindex Routine info, in the shell -@cindex Online Help, in the shell -@multitable @columnfractions .12 .88 -@item @kbd{@key{TAB}} -@tab Completion of file names (between quotes and after executive -commands @samp{.run} and @samp{.compile}), routine names, class names, -keywords, system variables, system variable tags etc. -(@code{idlwave-shell-complete}). -@item @kbd{M-@key{TAB}} -@tab Same as @key{TAB} -@item @kbd{C-c ?} -@tab Routine Info display (@code{idlwave-routine-info}) -@item @kbd{M-?} -@tab IDL online help on routine (@code{idlwave-routine-info-from-idlhelp}) -@item @kbd{C-c C-i} -@tab Update routine info from buffers and shell -(@code{idlwave-update-routine-info}) -@item @kbd{C-c C-v} -@tab Find the source file of a routine (@code{idlwave-find-module}) -@item @kbd{C-c C-t} -@tab Find the source file of a routine in the currently visited file -(@code{idlwave-find-module-this-file}). -@item @kbd{C-c =} -@tab Compile a library routine (@code{idlwave-resolve}) -@end multitable - -@defopt idlwave-shell-arrows-do-history (@code{t}) -Non-@code{nil} means @key{UP} and @key{DOWN} arrows move through command -history like xterm. -@end defopt - -@defopt idlwave-shell-comint-settings -Alist of special settings for the comint variables in the IDLWAVE Shell. -@end defopt - -@defopt idlwave-shell-file-name-chars -The characters allowed in file names, as a string. Used for file name -completion. -@end defopt - -@defopt idlwave-shell-graphics-window-size -Size of IDL graphics windows popped up by special IDLWAVE command. -@end defopt - -@cindex Input mode -@cindex Character input mode (Shell) -@cindex Line input mode (Shell) -@cindex Magic spells, for input mode -@cindex Spells, magic -IDLWAVE works in line input mode: You compose a full command line, using -all the power Emacs gives you to do this. When you press @key{RET}, the -whole line is sent to IDL@. Sometimes it is necessary to send single -characters (without a newline), for example when an IDL program is -waiting for single character input with the @code{GET_KBRD} function. -You can send a single character to IDL with the command @kbd{C-c C-x} -(@code{idlwave-shell-send-char}). When you press @kbd{C-c C-y} -(@code{idlwave-shell-char-mode-loop}), IDLWAVE runs a blocking loop -which accepts characters and immediately sends them to IDL@. The loop -can be exited with @kbd{C-g}. It terminates also automatically when the -current IDL command is finished. Check the documentation of the two -variables described below for a way to make IDL programs trigger -automatic switches of the input mode. - -@defopt idlwave-shell-use-input-mode-magic (@code{nil}) -Non-@code{nil} means IDLWAVE should check for input mode spells in -output. -@end defopt - -@defopt idlwave-shell-input-mode-spells -The three regular expressions which match the magic spells for input -modes. -@end defopt - -@node Commands Sent to the Shell -@section Commands Sent to the Shell -@cindex Commands in shell, showing -@cindex Showing commands in shell - -The IDLWAVE buffers and shell interact very closely. In addition to the -normal commands you enter at the @code{IDL>} prompt, many other special -commands are sent to the shell, sometimes as a direct result of invoking -a key command, menu item, or toolbar button, but also automatically, as -part of the normal flow of information updates between the buffer and -shell. - -The commands sent include @code{breakpoint}, @code{.step} and other -debug commands (@pxref{Debugging IDL Programs}), @code{.run} and other -compilation statements (@pxref{Compiling Programs}), examination -commands like @code{print} and @code{help} (@pxref{Examining -Variables}), and other special purpose commands designed to keep -information on the running shell current. - -By default, much of this background shell input and output is hidden -from the user, but this is configurable. The custom variable -@code{idlwave-abbrev-show-commands} allows you to configure which -commands sent to the shell are shown there. For a related customization -for separating the output of @emph{examine} commands, see @ref{Examining -Variables}. - -@defopt idlwave-shell-show-commands (@code{'(run misc breakpoint)}) -A list of command types to echo in the shell when sent. Possible values -are @code{run} for @code{.run}, @code{.compile} and other run commands, -@code{misc} for lesser used commands like @code{window}, -@code{retall},@code{close}, etc., @code{breakpoint} for breakpoint -setting and clearing commands, and @code{debug} for other debug, -stepping, and continue commands. In addition, if the variable is set to -the single symbol @code{'everything}, all the copious shell input is -displayed (which is probably only useful for debugging purposes). -N.B. For hidden commands which produce output by side-effect, that -output remains hidden (e.g., stepping through a @code{print} command). -As a special case, any error message in the output will be displayed -(e.g., stepping to an error). -@end defopt - -@node Debugging IDL Programs -@section Debugging IDL Programs -@cindex Debugging -@cindex Key bindings for debugging -@cindex Toolbar - -Programs can be compiled, run, and debugged directly from the source -buffer in Emacs, walking through arbitrarily deeply nested code, -printing expressions and skipping up and down the calling stack along -the way. IDLWAVE makes compiling and debugging IDL programs far less -cumbersome by providing a full-featured, key/menu/toolbar-driven -interface to commands like @code{breakpoint}, @code{.step}, -@code{.run}, etc. It can even perform complex debug operations not -natively supported by IDL (like continuing to the line at the cursor). - -The IDLWAVE shell installs key bindings both in the shell buffer and -in all IDL code buffers of the current Emacs session, so debug -commands work in both places (in the shell, commands operate on the -last file compiled). On Emacs versions which support it, a debugging -toolbar is also installed. The toolbar display can be toggled with -@kbd{C-c C-d C-t} (@code{idlwave-shell-toggle-toolbar}). - - -@defopt idlwave-shell-use-toolbar (@code{t}) -Non-@code{nil} means use the debugging toolbar in all IDL related -buffers. -@end defopt - -@menu -* A Tale of Two Modes:: -* Debug Key Bindings:: -* Breakpoints and Stepping:: -* Compiling Programs:: -* Walking the Calling Stack:: -* Electric Debug Mode:: -@end menu - - -@node A Tale of Two Modes -@subsection A Tale of Two Modes -@cindex Electric Debug Mode -@cindex Debugging Interface - -The many debugging, compiling, and examination commands provided in -IDLWAVE are available simultaneously through two different interfaces: -the original, multi-key command interface, and the new Electric Debug -Mode. The functionality they offer is similar, but the way you interact -with them is quite different. The main difference is that, in Electric -Debug Mode, the source buffers are made read-only, and single -key-strokes are used to step through, examine expressions, set and -remove breakpoints, etc. The same variables, prefix arguments, and -settings apply to both versions, and both can be used interchangeably. -By default, when breakpoints are hit, Electric Debug Mode is enabled. -The traditional interface is described first. @xref{Electric Debug -Mode}, for more on that mode. Note that electric debug mode can be -prevented from activating automatically by customizing the variable -@code{idlwave-shell-automatic-electric-debug}. - -@node Debug Key Bindings -@subsection Debug Key Bindings -@kindex C-c C-d -@cindex Key bindings - -The standard debugging key bindings are always available by default on -the prefix key @kbd{C-c C-d}, so, for example, setting a breakpoint is -done with @kbd{C-c C-d C-b}, and compiling a source file with @kbd{C-c -C-d C-c}. You can also easily configure IDLWAVE to use one or more -modifier keys not in use by other commands, in lieu of the prefix -@kbd{C-c C-d} (though these bindings will typically also be available; -see @code{idlwave-shell-activate-prefix-keybindings}). For -example, if you include in @file{.emacs}: - -@lisp -(setq idlwave-shell-debug-modifiers '(control shift)) -@end lisp - -@noindent a breakpoint can then be set by pressing @kbd{b} while holding down -@kbd{shift} and @kbd{control} keys, i.e., @kbd{C-S-b}. Compiling a -source file will be on @kbd{C-S-c}, deleting a breakpoint @kbd{C-S-d}, -etc. In the remainder of this chapter we will assume that the -@kbd{C-c C-d} bindings are active, but each of these bindings will -have an equivalent shortcut if modifiers are given in the -@code{idlwave-shell-debug-modifiers} variable (@pxref{Lesson -II---Customization}). A much simpler and faster form of debugging for -running code is also available by default; see @ref{Electric Debug -Mode}. - -@defopt idlwave-shell-prefix-key (@kbd{C-c C-d}) -The prefix key for the debugging map -@code{idlwave-shell-mode-prefix-map}. -@end defopt - -@defopt idlwave-shell-activate-prefix-keybindings (@code{t}) -Non-@code{nil} means debug commands will be bound to the prefix -key, like @kbd{C-c C-d C-b}. -@end defopt - -@defopt idlwave-shell-debug-modifiers (@code{nil}) -List of modifier keys to use for additional, alternative binding of -debugging commands in the shell and source buffers. Can be one or -more of @code{control}, @code{meta}, @code{super}, @code{hyper}, -@code{alt}, and @code{shift}. -@end defopt - -@node Breakpoints and Stepping -@subsection Breakpoints and Stepping -@cindex Breakpoints -@cindex Stepping -@cindex Execution, controlled - -@kindex C-c C-d C-b -@kindex C-c C-d C-b -IDLWAVE helps you set breakpoints and step through code. Setting a -breakpoint in the current line of the source buffer is accomplished -with @kbd{C-c C-d C-b} (@code{idlwave-shell-break-here}). With a -prefix arg of 1 (i.e., @kbd{C-1 C-c C-d C-b}), the breakpoint gets a -@code{/ONCE} keyword, meaning that it will be deleted after first use. -With a numeric prefix greater than one (e.g., @kbd{C-4 C-c C-d C-b}), -the breakpoint will only be active the @code{nth} time it is hit. -With a single non-numeric prefix (i.e., @kbd{C-u C-c C-d C-b}), prompt -for a condition: an IDL expression to be evaluated and trigger the -breakpoint only if true. To clear the breakpoint in the current line, -use @kbd{C-c C-d C-d} (@code{idlwave-clear-current-bp}). When -executed from the shell window, the breakpoint where IDL is currently -stopped will be deleted. To clear all breakpoints, use @kbd{C-c C-d -C-a} (@code{idlwave-clear-all-bp}). Breakpoints can also be disabled -and re-enabled: @kbd{C-c C-d C-\} -(@code{idlwave-shell-toggle-enable-current-bp}). - -Breakpoint lines are highlighted or indicated with an icon in the source -code (different icons for conditional, after, and other break types). -Disabled breakpoints are @emph{grayed out} by default. Note that IDL -places breakpoints as close as possible on or after the line you -specify. IDLWAVE queries the shell for the actual breakpoint location -which was set, so the exact line you specify may not be marked. You can -re-sync the breakpoint list and update the display at any time (e.g., if -you add or remove some on the command line) using @kbd{C-c C-d C-l}. - -In recent IDLWAVE versions, the breakpoint line is highlighted when the -mouse is moved over it, and a tooltip pops up describing the break -details. @kbd{mouse-3} on the breakpoint line pops up a menu of -breakpoint actions, including clearing, disabling, and adding or -changing break conditions or ``after'' break count. - -Once the program has stopped somewhere, you can step through it. The -most important stepping commands are @kbd{C-c C-d C-s} to execute one -line of IDL code ("step into"); @kbd{C-c C-d C-n} to step a single line, -treating procedure and function calls as a single step ("step over"); -@kbd{C-c C-d C-h} to continue execution to the line at the cursor and -@kbd{C-c C-d C-r} to continue execution. @xref{Commands Sent to the -Shell}, for information on displaying or hiding the breakpoint and -stepping commands the shell receives. Here is a summary of the -breakpoint and stepping commands: - -@multitable @columnfractions .23 .77 -@item @kbd{C-c C-d C-b} -@tab Set breakpoint (@code{idlwave-shell-break-here}) -@item @kbd{C-c C-d C-i} -@tab Set breakpoint in module named here (@code{idlwave-shell-break-in}) -@item @kbd{C-c C-d C-d} -@tab Clear current breakpoint (@code{idlwave-shell-clear-current-bp}) -@item @kbd{C-c C-d C-a} -@tab Clear all breakpoints (@code{idlwave-shell-clear-all-bp}) -@item @kbd{C-c C-d [} -@tab Go to the previous breakpoint (@code{idlwave-shell-goto-previous-bp}) -@item @kbd{C-c C-d ]} -@tab Go to the next breakpoint (@code{idlwave-shell-goto-next-bp}) -@item @kbd{C-c C-d C-\} -@tab Disable/Enable current breakpoint (@code{idlwave-shell-toggle-enable-current-bp}) -@item @kbd{C-c C-d C-j} -@tab Set a breakpoint at the beginning of the enclosing routine. -@item @kbd{C-c C-d C-s} -@tab Step, into function calls (@code{idlwave-shell-step}) -@item @kbd{C-c C-d C-n} -@tab Step, over function calls (@code{idlwave-shell-stepover}) -@item @kbd{C-c C-d C-k} -@tab Skip one statement (@code{idlwave-shell-skip}) -@item @kbd{C-c C-d C-u} -@tab Continue to end of block (@code{idlwave-shell-up}) -@item @kbd{C-c C-d C-m} -@tab Continue to end of function (@code{idlwave-shell-return}) -@item @kbd{C-c C-d C-o} -@tab Continue past end of function (@code{idlwave-shell-out}) -@item @kbd{C-c C-d C-h} -@tab Continue to line at cursor position (@code{idlwave-shell-to-here}) -@item @kbd{C-c C-d C-r} -@tab Continue execution to next breakpoint, if any (@code{idlwave-shell-cont}) -@item @kbd{C-c C-d C-up} -@tab Show higher level in calling stack (@code{idlwave-shell-stack-up}) -@item @kbd{C-c C-d C-down} -@tab Show lower level in calling stack (@code{idlwave-shell-stack-down}) -@end multitable - -All of these commands have equivalents in Electric Debug Mode, which -provides faster single-key access (@pxref{Electric Debug Mode}). - -The line where IDL is currently stopped, at breakpoints, halts, and -errors, etc., is marked with a color overlay or arrow, depending on the -setting in @code{idlwave-shell-mark-stop-line}. If an overlay face is -used to mark the stop line (as it is by default), when stepping through -code, the face color is temporarily changed to gray, until IDL completes -the next command and moves to the new line. - -@defopt idlwave-shell-mark-breakpoints (@code{t}) -Non-@code{nil} means mark breakpoints in the source file buffers. The -value indicates the preferred method. Valid values are @code{nil}, -@code{t}, @code{face}, and @code{glyph}. -@end defopt - -@defopt idlwave-shell-breakpoint-face -The face for breakpoint lines in the source code if -@code{idlwave-shell-mark-breakpoints} has the value @code{face}. -@end defopt - -@defopt idlwave-shell-breakpoint-popup-menu (@code{t}) -Whether to pop-up a menu and present a tooltip description on -breakpoint lines. -@end defopt - -@defopt idlwave-shell-mark-stop-line (@code{t}) -Non-@code{nil} means mark the source code line where IDL is currently -stopped. The value specifies the preferred method. Valid values are -@code{nil}, @code{t}, @code{arrow}, and @code{face}. -@end defopt - -@defopt idlwave-shell-overlay-arrow (@code{">"}) -The overlay arrow to display at source lines where execution halts, if -configured in @code{idlwave-shell-mark-stop-line}. -@end defopt - -@defopt idlwave-shell-stop-line-face -The face which highlights the source line where IDL is stopped, if -configured in @code{idlwave-shell-mark-stop-line}. -@end defopt - - -@node Compiling Programs -@subsection Compiling Programs -@cindex Compiling programs -@cindex Programs, compiling -@cindex Default command line, executing -@cindex Executing a default command line - -@kindex C-c C-d C-c -In order to compile the current buffer under the IDLWAVE shell, press -@kbd{C-c C-d C-c} (@code{idlwave-save-and-run}). This first saves the -current buffer and then sends the command @samp{.run path/to/file} to the -shell. You can also execute @kbd{C-c C-d C-c} from the shell buffer, in -which case the most recently compiled buffer will be saved and -re-compiled. - -When developing or debugging a program, it is often necessary to execute -the same command line many times. A convenient way to do this is -@kbd{C-c C-d C-y} (@code{idlwave-shell-execute-default-command-line}). -This command first resets IDL from a state of interrupted execution by -closing all files and returning to the main interpreter level. Then a -default command line is send to the shell. To edit the default command -line, call @code{idlwave-shell-execute-default-command-line} with a -prefix argument: @kbd{C-u C-c C-d C-y}. If no default command line has -been set (or you give two prefix arguments), the last command on the -@code{comint} input history is sent. - -@kindex C-c C-d C-e -@cindex Compiling regions -For quickly compiling and running the currently marked region as a main -level program @kbd{C-c C-d C-e} (@code{idlwave-shell-run-region}) is -very useful. A temporary file is created holding the contents of the -current region (with @code{END} appended), and run from the shell. - -@node Walking the Calling Stack -@subsection Walking the Calling Stack -@cindex Calling stack, walking - -While debugging a program, it can be very useful to check the context in -which the current routine was called, for instance to help understand -the value of the arguments passed. To do so conveniently you need to -examine the calling stack. If execution is stopped somewhere deep in a -program, you can use the commands @kbd{C-c C-d C-@key{UP}} -(@code{idlwave-shell-stack-up}) and @kbd{C-c C-d C-@key{DOWN}} -(@code{idlwave-shell-stack-down}), or the corresponding toolbar buttons, -to move up or down through the calling stack. The mode line of the -shell window will indicate the position within the stack with a label -like @samp{[-3:MYPRO]}. The line of IDL code at that stack position -will be highlighted. If you continue execution, IDLWAVE will -automatically return to the current level. @xref{Examining Variables}, -for information how to examine the value of variables and expressions on -higher calling stack levels. - -@html - -@end html -@node Electric Debug Mode -@subsection Electric Debug Mode -@cindex Electric Debug Mode -@cindex @samp{*Debugging*} - -Even with a convenient debug key prefix enabled, repetitive stepping, -variable examination (@pxref{Examining Variables}), and other debugging -activities can be awkward and slow using commands which require multiple -keystrokes. Luckily, there's a better way, inspired by the lisp e-debug -mode, and available through the @emph{Electric Debug Mode}. By default, -as soon as a breakpoint is hit, this minor mode is enabled. The buffer -showing the line where execution has halted is switched to Electric -Debug Mode. This mode is visible as @samp{*Debugging*} in the mode -line, and a different face (violet by default, if color is available) -for the line stopped at point. The buffer is made read-only and -single-character bindings for the most commonly used debugging commands -are enabled. These character commands (a list of which is available -with @kbd{C-?}) are: - -@multitable @columnfractions .2 .8 -@item @kbd{a} -@tab Clear all breakpoints (@code{idlwave-shell-clear-all-bp}) -@item @kbd{b} -@tab Set breakpoint, @kbd{C-u b} for a conditional break, @kbd{C-n b} for nth hit (@code{idlwave-shell-break-here}) -@item @kbd{d} -@tab Clear current breakpoint (@code{idlwave-shell-clear-current-bp}) -@item @kbd{e} -@tab Prompt for expression to print (@code{idlwave-shell-clear-current-bp}). -@item @kbd{h} -@tab Continue to the line at cursor position (@code{idlwave-shell-to-here}) -@item @kbd{i} -@tab Set breakpoint in module named here (@code{idlwave-shell-break-in}) -@item @kbd{[} -@tab Go to the previous breakpoint in the file (@code{idlwave-shell-goto-previous-bp}) -@item @kbd{]} -@tab Go to the next breakpoint in the file -(@code{idlwave-shell-goto-next-bp}) -@item @kbd{\} -@tab Disable/Enable current breakpoint (@code{idlwave-shell-toggle-enable-current-bp}) -@item @kbd{j} -@tab Set breakpoint at beginning of enclosing routine (@code{idlwave-shell-break-this-module}) -@item @kbd{k} -@tab Skip one statement (@code{idlwave-shell-skip}) -@item @kbd{m} -@tab Continue to end of function (@code{idlwave-shell-return}) -@item @kbd{n} -@tab Step, over function calls (@code{idlwave-shell-stepover}) -@item @kbd{o} -@tab Continue past end of function (@code{idlwave-shell-out}) -@item @kbd{p} -@tab Print expression near point or in region with @kbd{C-u p} (@code{idlwave-shell-print}) -@item @kbd{q} -@tab End the debugging session and return to the Shell's main level -(@code{idlwave-shell-retall}) -@item @kbd{r} -@tab Continue execution to next breakpoint, if any (@code{idlwave-shell-cont}) -@item @kbd{s} or @kbd{@key{SPACE}} -@tab Step, into function calls (@code{idlwave-shell-step}) -@item @kbd{t} -@tab Print a calling-level traceback in the shell -@item @kbd{u} -@tab Continue to end of block (@code{idlwave-shell-up}) -@item @kbd{v} -@tab Turn Electric Debug Mode off -(@code{idlwave-shell-electric-debug-mode}) -@item @kbd{x} -@tab Examine expression near point (or in region with @kbd{C-u x}) -with shortcut of examine type. -@item @kbd{z} -@tab Reset IDL (@code{idlwave-shell-reset}) -@item @kbd{+} or @kbd{=} -@tab Show higher level in calling stack (@code{idlwave-shell-stack-up}) -@item @kbd{-} or @kbd{_} -@tab Show lower level in calling stack (@code{idlwave-shell-stack-down}) -@item @kbd{?} -@tab Help on expression near point or in region with @kbd{C-u ?} -(@code{idlwave-shell-help-expression}) -@item @kbd{C-?} -@tab Show help on the commands available. -@end multitable - -Most single-character electric debug bindings use the final keystroke -of the equivalent multiple key commands (which are of course also -still available), but some differ (e.g., @kbd{e},@kbd{t},@kbd{q},@kbd{x}). -Some have additional convenience bindings (like @kbd{@key{SPACE}} for -stepping). All prefix and other argument options described in this -section for the commands invoked by electric debug bindings are still -valid. For example, @kbd{C-u b} sets a conditional breakpoint, just -as it did with @kbd{C-u C-c C-d C-b}. - -You can toggle the electric debug mode at any time in a buffer using -@kbd{C-c C-d C-v} (@kbd{v} to turn it off while in the mode), or from -the Debug menu. Normally the mode will be enabled and disabled at the -appropriate times, but occasionally you might want to edit a file -while still debugging it, or switch to the mode for conveniently -setting lots of breakpoints. - -To quickly abandon a debugging session and return to normal editing at -the Shell's main level, use @kbd{q} (@code{idlwave-shell-retall}). -This disables electric debug mode in all IDLWAVE buffers@footnote{Note -that this binding is not symmetric: @kbd{C-c C-d C-q} is bound to -@code{idlwave-shell-quit}, which quits your IDL session.}. Help is -available for the command shortcuts with @kbd{C-?}. If you find this -mode gets in your way, you can keep it from automatically activating -by setting the variable @code{idlwave-shell-automatic-electric-debug} -to @code{nil}, or @code{'breakpoint}. If you'd like the convenient -electric debug shortcuts available also when run-time errors are -encountered, set to @code{t}. - -@defopt idlwave-shell-automatic-electric-debug (@code{'breakpoint}) -Whether to enter electric debug mode automatically when a breakpoint -or run-time error is encountered, and then disable it in all buffers -when the $MAIN$ level is reached (either through normal program -execution, or retall). In addition to @code{nil} for never, and -@code{t} for both breakpoints and errors, this can be -@code{'breakpoint} (the default) to enable it only at breakpoint -halts. -@end defopt - -@defopt idlwave-shell-electric-stop-color (Violet) -Default color of the stopped line overlay when in electric debug mode. -@end defopt - -@defopt idlwave-shell-electric-stop-line-face -The face to use for the stopped line. Defaults to a face similar to the -modeline, with color @code{idlwave-shell-electric-stop-color}. -@end defopt - -@defopt idlwave-shell-electric-zap-to-file (@code{t}) -If set, when entering electric debug mode, select the window displaying -the file where point is stopped. This takes point away from the shell -window, but is useful for immediate stepping, etc. -@end defopt - -@html - -@end html -@node Examining Variables -@section Examining Variables -@cindex @code{PRINT} expressions -@cindex @code{HELP}, on expressions -@cindex Expressions, printing & help -@cindex Examining expressions -@cindex Printing expressions -@cindex Mouse binding to print expressions - -@kindex C-c C-d C-p -Do you find yourself repeatedly typing, e.g., @code{print,n_elements(x)}, -and similar statements to remind yourself of the -type/size/structure/value/etc.@: of variables and expressions in your code -or at the command line? IDLWAVE has a suite of special commands to -automate these types of variable or expression examinations. They work -by sending statements to the shell formatted to include the indicated -expression, and can be accessed in several ways. - -These @emph{examine} commands can be used in the shell or buffer at any -time (as long as the shell is running), and are very useful when -execution is stopped in a buffer due to a triggered breakpoint or error, -or while composing a long command in the IDLWAVE shell. In the latter -case, the command is sent to the shell and its output is visible, but -point remains unmoved in the command being composed: you can inspect -the constituents of a command you're building without interrupting the -process of building it! You can even print arbitrary expressions from -older input or output further up in the shell window; any expression, -variable, number, or function you see can be examined. - -If the variable @code{idlwave-shell-separate-examine-output} is -non-@code{nil} (the default), all examine output will be sent to a -special @file{*Examine*} buffer, rather than the shell. The output of -prior examine commands is saved in this buffer. In this buffer @kbd{c} -clears the contents, and @kbd{q} hides the buffer. - -The two most basic examine commands are bound to @kbd{C-c C-d C-p}, to -print the expression at point, and @kbd{C-c C-d ?}, to invoke help on -this expression@footnote{Available as @kbd{p} and @kbd{?} in Electric -Debug Mode (@pxref{Electric Debug Mode})}. The expression at point is -either an array expression or a function call, or the contents of a pair -of parentheses. The chosen expression is highlighted, and -simultaneously the resulting output is highlighted in the shell or -separate output buffer. Calling the above commands with a prefix -argument will use the current region as expression instead of using the -one at point. which can be useful for examining complicated, multi-line -expressions. Two prefix arguments (@kbd{C-u C-u C-c C-d C-p}) will -prompt for an expression to print directly. By default, when invoking -print, only an initial portion of long arrays will be printed, up to -@code{idlwave-shell-max-print-length}. - -For added speed and convenience, there are mouse bindings which allow -you to click on expressions and examine their values. Use -@kbd{S-mouse-2} to print an expression and @kbd{C-M-mouse-2} to invoke -help (i.e., you need to hold down @key{META} and @key{CONTROL} while -clicking with the middle mouse button). If you simply click, the -nearest expression will be selected in the same manner as described -above. You can also @emph{drag} the mouse in order to highlight -exactly the specific expression or sub-expression you want to examine. -For custom expression examination, and the powerful customizable -pop-up examine selection, @xref{Custom Expression Examination}. - -@cindex Printing expressions, on calling stack -@cindex Restrictions for expression printing -The same variable inspection commands work both in the IDL Shell and -IDLWAVE buffers, and even for variables at higher levels of the calling -stack. For instance, if you're stopped at a breakpoint in a routine, -you can examine the values of variables and expressions inside its -calling routine, and so on, all the way up through the calling stack. -Simply step up the stack, and print variables as you see them -(@pxref{Walking the Calling Stack}, for information on stepping back -through the calling stack). The following restrictions apply for all -levels except the current: - -@itemize @bullet -@item -Array expressions must use the @samp{[ ]} index delimiters. Identifiers -with a @samp{( )} will be interpreted as function calls. -@item -@cindex ROUTINE_NAMES, IDL procedure -N.B.: printing values of expressions on higher levels of the calling -stack uses the @emph{unsupported} IDL routine @code{ROUTINE_NAMES}, -which may or may not be available in future versions of IDL@. Caveat -Examinor. -@end itemize - -@defopt idlwave-shell-expression-face -The face for @code{idlwave-shell-expression-overlay}. -Allows you to choose the font, color and other properties for -the expression printed by IDL. -@end defopt - -@defopt idlwave-shell-output-face -The face for @code{idlwave-shell-output-overlay}. -Allows you to choose the font, color and other properties for the most -recent output of IDL when examining an expression." -@end defopt - -@defopt idlwave-shell-separate-examine-output (@code{t}) -If non-@code{nil}, re-direct the output of examine commands to a special -@file{*Examine*} buffer, instead of in the shell itself. -@end defopt - -@defopt idlwave-shell-max-print-length (200) -The maximum number of leading array entries to print, when examining -array expressions. -@end defopt - -@node Custom Expression Examination -@section Custom Expression Examination -@cindex Expressions, custom examination -@cindex Custom expression examination - -The variety of possible variable and expression examination commands is -endless (just look, for instance, at the keyword list to -@code{widget_info()}). Rather than attempt to include them all, IDLWAVE -provides two easy methods to customize your own commands, with a special -mouse examine command, and two macros for generating your own examine -key and mouse bindings. - -The most powerful and flexible mouse examine command of all is -available on @kbd{C-S-mouse-2}. Just as for all the other mouse -examine commands, it permits click or drag expression selection, but -instead of sending hard-coded commands to the shell, it pops-up a -customizable selection list of examine functions to choose among, -configured with the @code{idlwave-shell-examine-alist} -variable@footnote{In Electric Debug Mode (@pxref{Electric Debug -Mode}), the key @kbd{x} provides a single-character shortcut interface -to the same examine functions for the expression at point or marked by -the region.}. This variable is a list of key-value pairs (an -@emph{alist} in Emacs parlance), where the key gives a name to be -shown for the examine command, and the value is the command strings -itself, in which the text @code{___} (three underscores) will be -replaced by the selected expression before being sent to the shell. -An example might be key @code{Structure Help} with value -@code{help,___,/STRUCTURE}. In that case, you'd be prompted with -@emph{Structure Help}, which might send something like -@code{help,var,/STRUCTURE} to the shell for output. -@code{idlwave-shell-examine-alist} comes configured by default with a -large list of examine commands, but you can easily customize it to add -your own. - -In addition to configuring the functions available to the pop-up mouse -command, you can easily create your own customized bindings to inspect -expressions using the two convenience macros -@code{idlwave-shell-examine} and @code{idlwave-shell-mouse-examine}. -These create keyboard or mouse-based custom inspections of variables, -sharing all the same properties of the built-in examine commands. -Both functions take a single string argument sharing the syntax of the -@code{idlwave-shell-examine-alist} values, e.g.: - -@lisp -(add-hook 'idlwave-shell-mode-hook - (lambda () - (idlwave-shell-define-key-both [s-down-mouse-2] - (idlwave-shell-mouse-examine - "print, size(___,/DIMENSIONS)")) - (idlwave-shell-define-key-both [f9] (idlwave-shell-examine - "print, size(___,/DIMENSIONS)")) - (idlwave-shell-define-key-both [f10] (idlwave-shell-examine - "print,size(___,/TNAME)")) - (idlwave-shell-define-key-both [f11] (idlwave-shell-examine - "help,___,/STRUCTURE")))) -@end lisp - -@noindent Now pressing @key{f9}, or middle-mouse dragging with the -@key{SUPER} key depressed, will print the dimensions of the nearby or -highlighted expression. Pressing @key{f10} will give the type string, -and @key{f11} will show the contents of a nearby structure. As you can -see, the possibilities are only marginally finite. - -@defopt idlwave-shell-examine-alist -An alist of examine commands in which the keys name the command and -are displayed in the selection pop-up, and the values are custom IDL -examine command strings to send, after all instances of @code{___} -(three underscores) are replaced by the indicated expression. -@end defopt - -@node Acknowledgments -@chapter Acknowledgments -@cindex Acknowledgments -@cindex Maintainer, of IDLWAVE -@cindex Authors, of IDLWAVE -@cindex Contributors, to IDLWAVE -@cindex Email address, of Maintainer -@cindex Thanks - -@noindent -The main contributors to the IDLWAVE package have been: - -@itemize @minus -@item -@uref{mailto:chase@@att.com, @b{Chris Chase}}, the original author. -Chris wrote @file{idl.el} and @file{idl-shell.el} and maintained them -for several years. - -@item -@uref{mailto:dominik@@astro.uva.nl, @b{Carsten Dominik}} was in charge -of the package from version 3.0, during which time he overhauled almost -everything, modernized IDLWAVE with many new features, and developed the -manual. - -@item -@uref{mailto:jdsmith@@as.arizona.edu, @b{J.D. Smith}}, the current -maintainer, as of version 4.10, helped shape object method completion -and most new features introduced in versions 4.x, and introduced many -new features for IDLWAVE versions 5.x and 6.x. -@end itemize - -@noindent -The following people have also contributed to the development of IDLWAVE -with patches, ideas, bug reports and suggestions. - -@itemize @minus -@item -Ulrik Dickow -@item -Eric E. Dors -@item -Stein Vidar H. Haugan -@item -David Huenemoerder -@item -Kevin Ivory -@item -Dick Jackson -@item -Xuyong Liu -@item -Simon Marshall -@item -Craig Markwardt -@item -Laurent Mugnier -@item -Lubos Pochman -@item -Bob Portmann -@item -Patrick M. Ryan -@item -Marty Ryba -@item -Phil Williams -@item -Phil Sterne -@item -Paul Sorenson -@end itemize - -Doug Dirks was instrumental in providing the crucial IDL XML catalog to -support HTML help with IDL v6.2 and later, and Ali Bahrami provided -scripts and documentation to interface with the IDL Assistant. - -@noindent -Thanks to everyone! - -@node Sources of Routine Info -@appendix Sources of Routine Info - -@cindex Sources of routine information -In @ref{Routine Info} and @ref{Completion} we showed how IDLWAVE -displays the calling sequence and keywords of routines, and completes -routine names and keywords. For these features to work, IDLWAVE must -know about the accessible routines. - -@menu -* Routine Definitions:: Where IDL Routines are defined. -* Routine Information Sources:: So how does IDLWAVE know about... -* Catalogs:: -* Load-Path Shadows:: Routines defined in several places -* Documentation Scan:: Scanning the IDL Manuals -@end menu - -@node Routine Definitions -@appendixsec Routine Definitions -@cindex Routine definitions -@cindex IDL variable @code{!PATH} -@cindex @code{!PATH}, IDL variable -@cindex @code{CALL_EXTERNAL}, IDL routine -@cindex @code{LINKIMAGE}, IDL routine -@cindex External routines - -@noindent Routines which can be used in an IDL program can be defined in -several places: - -@enumerate -@item -@emph{Builtin routines} are defined inside IDL itself. The source code -of such routines is not available, but instead are learned about through -the IDL documentation. -@item -Routines which are @emph{part of the current program}, are defined in a -file explicitly compiled by the user. This file may or may not be -located on the IDL search path. -@item -@emph{Library routines} are defined in files located on IDL's search -path. When a library routine is called for the first time, IDL will -find the source file and compile it dynamically. A special sub-category -of library routines are the @emph{system routines} distributed with IDL, -and usually available in the @file{lib} subdirectory of the IDL -distribution. -@item -External routines written in other languages (like Fortran or C) can be -called with @code{CALL_EXTERNAL}, linked into IDL via @code{LINKIMAGE}, -or included as dynamically loaded modules (DLMs). Currently IDLWAVE -cannot provide routine info and completion for such external routines, -except by querying the Shell for calling information (DLMs only). -@end enumerate - -@node Routine Information Sources -@appendixsec Routine Information Sources -@cindex Routine info sources -@cindex Builtin list of routines -@cindex Updating routine info -@cindex Scanning buffers for routine info -@cindex Buffers, scanning for routine info -@cindex Shell, querying for routine info - -@noindent To maintain the most comprehensive information about all IDL -routines on a system, IDLWAVE collects data from many sources: - -@enumerate - -@item -It has a @emph{builtin list} with information about the routines IDL -ships with. IDLWAVE @value{VERSION} is distributed with a list of -@value{NSYSROUTINES} routines and object methods, reflecting IDL version -@value{IDLVERSION}. As of IDL v6.2, the routine info is distributed -directly with IDL in the form of an XML catalog which IDLWAVE scans. -Formerly, this list was created by scanning the IDL manuals to produce -the file @file{idlw-rinfo.el}. - -@item -IDLWAVE @emph{scans} all its @emph{buffers} in the current Emacs session -for routine definitions. This is done automatically when routine -information or completion is first requested by the user. Each new -buffer and each buffer saved after making changes is also scanned. The -command @kbd{C-c C-i} (@code{idlwave-update-routine-info}) can be used -at any time to rescan all buffers. - -@item -If you have an IDLWAVE-Shell running in the Emacs session, IDLWAVE will -@emph{query the shell} for compiled routines and their arguments. This -happens automatically when routine information or completion is first -requested by the user. Each time an Emacs buffer is compiled with -@kbd{C-c C-d C-c}, the routine info for that file is queried. Though -rarely necessary, the command @kbd{C-c C-i} -(@code{idlwave-update-routine-info}) can be used to explicitly update -the shell routine data. - -@item -Many popular libraries are distributed with routine information already -scanned into @emph{library catalogs} (@pxref{Library Catalogs}). These -per-directory catalog files can also be built by the user with the -supplied @file{idlwave_catalog} tool. They are automatically discovered -by IDLWAVE. - -@item -IDLWAVE can scan selected directories of source files and store the -result in a single @emph{user catalog} file which will be -automatically loaded just like @file{idlw-rinfo.el}. @xref{User -Catalog}, for information on how to scan files in this way. -@end enumerate - -Loading all the routine and catalog information can be a time consuming -process, especially over slow networks. Depending on the system and -network configuration it could take up to 30 seconds (though locally on -fast systems is usually only a few seconds). In order to minimize the -wait time upon your first completion or routine info command in a -session, IDLWAVE uses Emacs idle time to do the initialization in six -steps, yielding to user input in between. If this gets into your way, -set the variable @code{idlwave-init-rinfo-when-idle-after} to 0 (zero). -The more routines documented in library and user catalogs, the slower -the loading will be, so reducing this number can help alleviate any long -load times. - -@defopt idlwave-init-rinfo-when-idle-after (@code{10}) -Seconds of idle time before routine info is automatically initialized. -@end defopt - -@defopt idlwave-scan-all-buffers-for-routine-info (@code{t}) -Non-@code{nil} means scan all buffers for IDL programs when updating -info. -@end defopt - -@defopt idlwave-query-shell-for-routine-info (@code{t}) -Non-@code{nil} means query the shell for info about compiled routines. -@end defopt - -@defopt idlwave-auto-routine-info-updates -Controls under what circumstances routine info is updated automatically. -@end defopt - -@html - -@end html -@node Catalogs -@appendixsec Catalogs -@cindex Catalogs - -@emph{Catalogs} are files containing scanned information on individual -routines, including arguments and keywords, calling sequence, file path, -class and procedure vs. function type, etc. They represent a way of -extending the internal built-in information available for IDL system -routines (@pxref{Routine Info}) to other source collections. - -Starting with version 5.0, there are two types of catalogs available -with IDLWAVE@. The traditional @emph{user catalog} and the newer -@emph{library catalogs}. Although they can be used interchangeably, the -library catalogs are more flexible, and preferred. There are few -occasions when a user catalog might be preferred---read below. Both -types of catalogs can coexist without causing problems. - -To facilitate the catalog systems, IDLWAVE stores information it gathers -from the shell about the IDL search paths, and can write this -information out automatically, or on-demand (menu @code{Debug->Save Path -Info}). On systems with no shell from which to discover the path -information (e.g., Windows), a library path must be specified in -@code{idlwave-library-path} to allow library catalogs to be located, and -to setup directories for user catalog scan (@pxref{User Catalog} for -more on this variable). Note that, before the shell is running, IDLWAVE -can only know about the IDL search path by consulting the file pointed -to by @code{idlwave-path-file} (@file{~/.emacs.d/idlwave/idlpath.el}, by -default). If @code{idlwave-auto-write-path} is enabled (which is the -default), the paths are written out whenever the IDLWAVE shell is -started. - -@defopt idlwave-auto-write-path (@code{t}) -Write out information on the !PATH and !DIR paths from IDL automatically -when they change and when the Shell is closed. These paths are needed -to locate library catalogs. -@end defopt - -@defopt idlwave-library-path -IDL library path for Windows and macOS@. Under Unix/macOS, will be -obtained from the Shell when run. -@end defopt - -@defopt idlwave-system-directory -The IDL system directory for Windows and macOS@. Also needed for -locating HTML help and the IDL Assistant for IDL v6.2 and later. Under -Unix/macOS, will be obtained from the Shell and recorded, if run. -@end defopt - -@defopt idlwave-config-directory (@file{~/.emacs.d/idlwave}) -Default path where IDLWAVE saves configuration information, a user -catalog (if any), and a cached scan of the XML catalog (IDL v6.2 and -later). -@end defopt - -@menu -* Library Catalogs:: -* User Catalog:: -@end menu - -@html - -@end html -@node Library Catalogs -@appendixsubsec Library Catalogs -@cindex @file{.idlwave_catalog} -@cindex Library catalogs -@cindex @code{idlwave_catalog} - -Library catalogs consist of files named @file{.idlwave_catalog} stored -in directories containing @code{.pro} routine files. They are -discovered on the IDL search path and loaded automatically when routine -information is read. Each catalog file documents the routines found in -that directory---one catalog per directory. Every catalog has a -library name associated with it (e.g., @emph{AstroLib}). This name will -be shown briefly when the catalog is found, and in the routine info of -routines it documents. - -Many popular libraries of routines are shipped with IDLWAVE catalog -files by default, and so will be automatically discovered. Library -catalogs are scanned externally to Emacs using a tool provided with -IDLWAVE@. Each catalog can be re-scanned independently of any other. -Catalogs can easily be made available system-wide with a common source -repository, providing uniform routine information, and lifting the -burden of scanning from the user (who may not even know they're using a -scanned catalog). Since all catalogs are independent, they can be -re-scanned automatically to gather updates, e.g., in a @file{cron} job. -Scanning is much faster than with the built-in user catalog method. One -minor disadvantage: the entire IDL search path is scanned for catalog -files every time IDLWAVE starts up, which might be slow if accessing IDL -routines over a slow network. - -A Perl tool to create library catalogs is distributed with IDLWAVE: -@code{idlwave_catalog}. It can be called quite simply: -@example -idlwave_catalog MyLib -@end example - -@noindent This will scan all directories recursively beneath the current and -populate them with @file{.idlwave_catalog} files, tagging the routines -found there with the name library ``MyLib''. The full usage -information: - -@example -Usage: idlwave_catalog [-l] [-v] [-d] [-s] [-f] [-h] libname - libname - Unique name of the catalog (4 or more alphanumeric - characters). - -l - Scan local directory only, otherwise recursively - catalog all directories at or beneath this one. - -v - Print verbose information. - -d - Instead of scanning, delete all .idlwave_catalog files - here or below. - -s - Be silent. - -f - Force overwriting any catalogs found with a different - library name. - -h - Print this usage. -@end example - -To re-load the library catalogs on the IDL path, force a system routine -info update using a single prefix to @code{idlwave-update-routine-info}: -@kbd{C-u C-c C-i}. - -@defopt idlwave-use-library-catalogs (@code{t}) -Whether to search for and load library catalogs. Disable if load -performance is a problem and/or the catalogs are not needed. -@end defopt - -@node User Catalog -@appendixsubsec User Catalog -@cindex User catalog -@cindex IDL library routine info -@cindex Windows -@cindex macOS -@cindex IDL variable @code{!DIR} -@cindex @code{!DIR}, IDL variable - -The user catalog is the old routine catalog system. It is produced -within Emacs, and stored in a single file in the user's home directory -(@file{.emacs.d/idlwave/idlusercat.el} by default). Although library catalogs -are more flexible, there may be reasons to prefer a user catalog -instead, including: - -@itemize @bullet -@item The scan is internal to Emacs, so you don't need a working Perl -installation, as you do for library catalogs. -@item Can be used to scan directories for which the user has no write -privileges. -@item Easy widget-based path selection. -@end itemize - -However, no routine info is available in the user catalog by default; -the user must actively complete a scan. In addition, this type of -catalog is all or nothing: if a single routine changes, the entire -catalog must be rescanned to update it. Creating the user catalog is -also much slower than scanning library catalogs. - -You can scan any of the directories on the currently known path. Under -Windows, you need to specify the IDL search path in -the variable @code{idlwave-library-path}, and the location of the IDL -directory (the value of the @code{!DIR} system variable) in the variable -@code{idlwave-system-directory}, like this@footnote{The initial @samp{+} -leads to recursive expansion of the path, just like in IDL}: - -@lisp -(setq idlwave-library-path - '("+c:/RSI/IDL56/lib/" "+c:/user/me/idllibs")) -(setq idlwave-system-directory "c:/RSI/IDL56/") -@end lisp - -@noindent Under GNU/Linux and UNIX, these values will be automatically -gathered from the IDLWAVE shell, if run. - -The command @kbd{M-x idlwave-create-user-catalog-file} (or the menu item -@samp{IDLWAVE->Routine Info->Select Catalog Directories}) can then be -used to create a user catalog. It brings up a widget in which you can -select some or all directories on the search path. Directories which -already contain a library catalog are marked with @samp{[LIB]}, and need -not be scanned (although there is no harm if you do so, other than the -additional memory used for the duplication). - -After selecting directories, click on the @w{@samp{[Scan & Save]}} -button in the widget to scan all files in the selected directories and -write out the resulting routine information. In order to update the -library information using the directory selection, call the command -@code{idlwave-update-routine-info} with a double prefix argument: -@w{@kbd{C-u C-u C-c C-i}}. This will rescan files in the previously -selected directories, write an updated version of the user catalog file -and rebuild IDLWAVE's internal lists. If you give three prefix -arguments @w{@kbd{C-u C-u C-u C-c C-i}}, updating will be done with a -background job@footnote{Unix systems only, I think.}. You can continue -to work, and the library catalog will be re-read when it is ready. If -you find you need to update the user catalog often, you should consider -building a library catalog for your routines instead (@pxref{Library -Catalogs}). - -@defopt idlwave-special-lib-alist -Alist of regular expressions matching special library directories for -labeling in routine-info display. -@end defopt - -@node Load-Path Shadows -@appendixsec Load-Path Shadows -@cindex Load-path shadows -@cindex Shadows, load-path -@cindex Duplicate routines -@cindex Multiply defined routines -@cindex Routine definitions, multiple -@cindex Application, testing for shadowing -@cindex Buffer, testing for shadowing - -IDLWAVE can compile a list of routines which are (re-)defined in more -than one file. Since one definition will hide (shadow) the others -depending on which file is compiled first, such multiple definitions are -called "load-path shadows". IDLWAVE has several routines to scan for -load path shadows. The output is placed into the special buffer -@file{*Shadows*}. The format of the output is identical to the source -section of the routine info buffer (@pxref{Routine Info}). The -different definitions of a routine are ordered by @emph{likelihood of -use}. So the first entry will be most likely the one you'll get if an -unsuspecting command uses that routine. Before listing shadows, you -should make sure that routine info is up-to-date by pressing @kbd{C-c -C-i}. Here are the different routines (also available in the Menu -@samp{IDLWAVE->Routine Info}): - -@table @asis -@item @kbd{M-x idlwave-list-buffer-load-path-shadows} -This command checks the names of all routines defined in the current -buffer for shadowing conflicts with other routines accessible to -IDLWAVE@. The command also has a key binding: @kbd{C-c C-b} -@item @kbd{M-x idlwave-list-shell-load-path-shadows}. -Checks all routines compiled under the shell for shadowing. This is -very useful when you have written a complete application. Just compile -the application, use @code{RESOLVE_ALL} to compile any routines used by -your code, update the routine info inside IDLWAVE with @kbd{C-c C-i} and -then check for shadowing. -@item @kbd{M-x idlwave-list-all-load-path-shadows} -This command checks all routines accessible to IDLWAVE for conflicts. -@end table - -For these commands to work fully you need to scan the entire load path -in either a user or library catalog. Also, IDLWAVE should be able to -distinguish between the system library files (normally installed in -@file{/usr/local/rsi/idl/lib}) and any site specific or user specific -files. Therefore, such local files should not be installed inside the -@file{lib} directory of the IDL directory. This is also advisable for -many other reasons. - -@cindex Windows -@cindex IDL variable @code{!DIR} -@cindex @code{!DIR}, IDL variable -Users of Windows also must set the variable -@code{idlwave-system-directory} to the value of the @code{!DIR} system -variable in IDL@. IDLWAVE appends @file{lib} to the value of this -variable and assumes that all files found on that path are system -routines. - -Another way to find out if a specific routine has multiple definitions -on the load path is routine info display (@pxref{Routine Info}). - -@node Documentation Scan -@appendixsec Documentation Scan -@cindex @file{get_html_rinfo} -@cindex @file{idlw-rinfo.el} -@cindex Scanning the documentation -@cindex Perl program, to create @file{idlw-rinfo.el} - -@strong{Starting with version 6.2, IDL is distributed directly with HTML -online help, and an XML-based catalog of routine information}. This -makes scanning the manuals with the tool @file{get_html_rinfo}, and the -@file{idlw-rinfo.el} file it produced, as described here, entirely -unnecessary. The information is left here for users wishing to produce -a catalog of older IDL versions' help. - - -IDLWAVE derives its knowledge about system routines from the IDL -manuals. The file @file{idlw-rinfo.el} contains the routine information -for the IDL system routines, and links to relevant sections of the HTML -documentation. The Online Help feature of IDLWAVE requires HTML -versions of the IDL manuals to be available; the HTML documentation is -not distributed with IDLWAVE by default, but must be downloaded -separately. - -The HTML files and related images can be produced from the -@file{idl.chm} HTMLHelp file distributed with IDL using the free -Microsoft HTML Help Workshop. If you are lucky, the maintainer of -IDLWAVE will always have access to the newest version of IDL and provide -updates. The IDLWAVE distribution also contains the Perl program -@file{get_html_rinfo} which constructs the @file{idlw-rinfo.el} file by -scanning the HTML documents produced from the IDL documentation. -Instructions on how to use @file{get_html_rinfo} are in the program -itself. - -@node HTML Help Browser Tips -@appendix HTML Help Browser Tips -@cindex Browser Tips - -There are a wide variety of possible browsers to use for displaying -the online HTML help available with IDLWAVE (starting with version -5.0). Since IDL v6.2, a single cross-platform HTML help browser, the -@emph{IDL Assistant} is distributed with IDL@. If this help browser is -available, it is the preferred choice, and the default. The variable -@code{idlwave-help-use-assistant}, enabled by default, controls -whether this help browser is used. If you use the IDL Assistant, the -tips here are not relevant. - -Since IDLWAVE runs on many different system types, a single browser -configuration is not possible, but choices abound. The default -@code{idlwave-help-browser-function} inherits the browser configured -in @code{browse-url-browser-function}. - -Note that the HTML files recompiled from the help sources contain -specific references to the @samp{Symbol} font, which by default is not -permitted in normal encodings (it's invalid, technically). Though it -only impacts a few symbols, you can trick Mozilla-based browsers into -recognizing @samp{Symbol} by following the directions -@c This page is 11 years old. Is it still relevant? -@uref{http://hutchinson.belmont.ma.us/tth/Xfonts.html, here}. With -this fix in place, HTML help pages look almost identical to their PDF -equivalents (yet can be bookmarked, browsed as history, searched, -etc.). - -@c Not updated in over a decade. -@c Maybe you want to recommend eww these days. -@ignore -@noindent Individual platform recommendations: - -@itemize @bullet -@item Unix/macOS: The @uref{http://www.w3m.org,@code{w3m}} browser -and its associated -@uref{http://emacs-w3m.namazu.org/,@code{emacs-w3m}} emacs mode -provide in-buffer browsing with image display, and excellent speed and -formatting. Both the Emacs mode and the browser itself must be -downloaded separately. To use this browser, include - -@lisp -(setq idlwave-help-browser-function 'w3m-browse-url) -@end lisp - -in your @file{.emacs}. Setting a few other nice @code{w3m} options -cuts down on screen clutter: - -@lisp -(setq w3m-use-tab nil - w3m-use-header-line nil - w3m-use-toolbar nil) -@end lisp - -If you use a dedicated frame for help, you might want to add the -following, to get consistent behavior with the @kbd{q} key: - -@lisp -;; Close my help window when w3m closes. -(defadvice w3m-close-window (after idlwave-close activate) - (if (boundp 'idlwave-help-frame) - (idlwave-help-quit))) -@end lisp - -Note that you can open the file in an external browser from within -@code{w3m} using @kbd{M}. -@end itemize -@end ignore - -@node Configuration Examples -@appendix Configuration Examples -@cindex Configuration examples -@cindex Example configuration -@cindex @file{.emacs} -@cindex Default settings, of options -@cindex Interview, with the maintainer - -@noindent -@b{Question:} You have all these complicated configuration options in -your package, but which ones do @emph{you} as the maintainer actually -set in your own configuration? - -@noindent -@b{Answer:} Not many, beyond custom key bindings. I set most defaults -the way that seems best. However, the default settings do not turn on -features which: - -@itemize @minus -@item -are not self-evident (i.e., too magic) when used by an unsuspecting user. -@item -are too intrusive. -@item -will not work properly on all Emacs installations. -@item -break with widely used standards. -@item -use function or other non-standard keys. -@item -are purely personal customizations, like additional key bindings, and -library names. -@end itemize - -@noindent To see what I mean, here is the @emph{entire} configuration -the old maintainer had in his @file{.emacs}: - -@lisp -(setq idlwave-shell-debug-modifiers '(control shift) - idlwave-store-inquired-class t - idlwave-shell-automatic-start t - idlwave-main-block-indent 2 - idlwave-init-rinfo-when-idle-after 2 - idlwave-help-dir "~/lib/emacs/idlwave" - idlwave-special-lib-alist '(("/idl-astro/" . "AstroLib") - ("/jhuapl/" . "JHUAPL-Lib") - ("/dominik/lib/idl/" . "MyLib"))) -@end lisp - -However, if you are an Emacs power-user and want IDLWAVE to work -completely differently, you can change almost every aspect of it. Here -is an example of a much more extensive configuration of IDLWAVE@. The -user is King! - -@example -;;; Settings for IDLWAVE mode - -(setq idlwave-block-indent 3) ; Indentation settings -(setq idlwave-main-block-indent 3) -(setq idlwave-end-offset -3) -(setq idlwave-continuation-indent 1) -(setq idlwave-begin-line-comment "^;[^;]") ; Leave ";" but not ";;" - ; anchored at start of line. -(setq idlwave-surround-by-blank t) ; Turn on padding ops =,<,> -(setq idlwave-pad-keyword nil) ; Remove spaces for keyword '=' -(setq idlwave-expand-generic-end t) ; convert END to ENDIF etc... -(setq idlwave-reserved-word-upcase t) ; Make reserved words upper case - ; (with abbrevs only) -(setq idlwave-abbrev-change-case nil) ; Don't force case of expansions -(setq idlwave-hang-indent-regexp ": ") ; Change from "- " for auto-fill -(setq idlwave-show-block nil) ; Turn off blinking to begin -(setq idlwave-abbrev-move t) ; Allow abbrevs to move point -(setq idlwave-query-class '((method-default . nil) ; No query for method - (keyword-default . nil); or keyword completion - ("INIT" . t) ; except for these - ("CLEANUP" . t) - ("SETPROPERTY" .t) - ("GETPROPERTY" .t))) - -;; Using w3m for help (must install w3m and emacs-w3m) -(autoload 'w3m-browse-url "w3m" "Interface for w3m on Emacs." t) -(setq idlwave-help-browser-function 'w3m-browse-url - w3m-use-tab nil ; no tabs, location line, or toolbar - w3m-use-header-line nil - w3m-use-toolbar nil) - -;; Close my help window or frame when w3m closes with 'q'. -(defadvice w3m-close-window (after idlwave-close activate) - (if (boundp 'idlwave-help-frame) - (idlwave-help-quit))) - -;; Some setting can only be done from a mode hook. Here is an example: -(add-hook 'idlwave-mode-hook - (lambda () - (setq case-fold-search nil) ; Make searches case sensitive - ;; Run other functions here - (font-lock-mode 1) ; Turn on font-lock mode - (idlwave-auto-fill-mode 0) ; Turn off auto filling - (setq idlwave-help-browser-function 'browse-url-w3) - - ;; Pad with 1 space (if -n is used then make the - ;; padding a minimum of n spaces.) The defaults use -1 - ;; instead of 1. - (idlwave-action-and-binding "=" '(idlwave-expand-equal 1 1)) - (idlwave-action-and-binding "<" '(idlwave-surround 1 1)) - (idlwave-action-and-binding ">" '(idlwave-surround 1 1 '(?-))) - (idlwave-action-and-binding "&" '(idlwave-surround 1 1)) - - ;; Only pad after comma and with exactly 1 space - (idlwave-action-and-binding "," '(idlwave-surround nil 1)) - (idlwave-action-and-binding "&" '(idlwave-surround 1 1)) - - ;; Pad only after '->', remove any space before the arrow - (idlwave-action-and-binding "->" '(idlwave-surround 0 -1 nil 2)) - - ;; Set some personal bindings - ;; (In this case, makes ',' have the normal self-insert behavior.) - (local-set-key "," 'self-insert-command) - (local-set-key [f5] 'idlwave-shell-break-here) - (local-set-key [f6] 'idlwave-shell-clear-current-bp) - - ;; Create a newline, indenting the original and new line. - ;; A similar function that does _not_ reindent the original - ;; line is on "\C-j" (The default for emacs programming modes). - (local-set-key "\n" 'idlwave-newline) - ;; (local-set-key "\C-j" 'idlwave-newline) ; My preference. - - ;; Some personal abbreviations - (define-abbrev idlwave-mode-abbrev-table - (concat idlwave-abbrev-start-char "wb") "widget_base()" - (idlwave-keyword-abbrev 1)) - (define-abbrev idlwave-mode-abbrev-table - (concat idlwave-abbrev-start-char "on") "obj_new()" - (idlwave-keyword-abbrev 1)) - )) - -;;; Settings for IDLWAVE SHELL mode - -(setq idlwave-shell-overlay-arrow "=>") ; default is ">" -(setq idlwave-shell-use-dedicated-frame t) ; Make a dedicated frame -(setq idlwave-shell-prompt-pattern "^WAVE> ") ; default is "^IDL> " -(setq idlwave-shell-explicit-file-name "wave") -(setq idlwave-shell-process-name "wave") -(setq idlwave-shell-use-toolbar nil) ; No toolbar - -;; Most shell interaction settings can be done from the shell-mode-hook. -(add-hook 'idlwave-shell-mode-hook - (lambda () - ;; Set up some custom key and mouse examine commands - (idlwave-shell-define-key-both [s-down-mouse-2] - (idlwave-shell-mouse-examine - "print, size(___,/DIMENSIONS)")) - (idlwave-shell-define-key-both [f9] (idlwave-shell-examine - "print, size(___,/DIMENSIONS)")) - (idlwave-shell-define-key-both [f10] (idlwave-shell-examine - "print,size(___,/TNAME)")) - (idlwave-shell-define-key-both [f11] (idlwave-shell-examine - "help,___,/STRUCTURE")))) -@end example - -@html - -@end html -@node Windows and macOS -@appendix Windows and macOS -@cindex Windows -@cindex macOS - -IDLWAVE was developed on a UNIX system. However, thanks to the -portability of Emacs, much of IDLWAVE does also work under different -operating systems like Windows (with NTEmacs). - -The only real problem is that there is no command-line version of IDL -for Windows with which IDLWAVE can interact. As a -result, the IDLWAVE Shell does not work and you have to rely on IDLDE -to run and debug your programs. However, editing IDL source files -with Emacs/IDLWAVE works with all bells and whistles, including -routine info, completion and fast online help. Only a small amount of -additional information must be specified in your @file{.emacs} file: -the path names which, on a UNIX system, are automatically gathered by -talking to the IDL program. - -Here is an example of the additional configuration needed for a Windows -system. I am assuming that IDLWAVE has been installed in -@w{@samp{C:\Program Files\IDLWAVE}} and that IDL is installed in -@w{@samp{C:\RSI\IDL63}}. - -@lisp -;; location of the lisp files (only needed if IDLWAVE is not part of -;; your default X/Emacs installation) -(setq load-path (cons "c:/program files/IDLWAVE" load-path)) - -;; The location of the IDL library directories, both standard, and your own. -;; note that the initial "+" expands the path recursively -(setq idlwave-library-path - '("+c:/RSI/IDL63/lib/" "+c:/path/to/my/idllibs" )) - -;; location of the IDL system directory (try "print,!DIR") -(setq idlwave-system-directory "c:/RSI/IDL63/") - -@end lisp - -@noindent Furthermore, Windows sometimes tries to outsmart you; make -sure you check the following things: - -@itemize @bullet -@item When you download the IDLWAVE distribution, make sure you save the -file under the names @file{idlwave.tar.gz}. -@item M-@key{TAB} switches among running programs---use @key{ESC}-@key{TAB} -instead. -@item Other issues as yet unnamed... -@end itemize - -Windows users who'd like to make use of IDLWAVE's context-aware HTML -help can skip the browser and use the HTMLHelp functionality directly. -@xref{Help with HTML Documentation}. - -@html - -@end html -@node Troubleshooting -@appendix Troubleshooting -@cindex Troubleshooting - -Although IDLWAVE usually installs and works without difficulty, a few -common problems and their solutions are documented below. - -@enumerate - -@item @strong{Whenever an IDL error occurs or a breakpoint is hit, I get -errors or strange behavior when I try to type anything into some of my -IDLWAVE buffers.} - -This is a @emph{feature}, not an error. You're in @emph{Electric -Debug Mode} (@pxref{Electric Debug Mode}). You should see -@code{*Debugging*} in the mode-line. The buffer is read-only and all -debugging and examination commands are available as single keystrokes; -@kbd{C-?} lists these shortcuts. Use @kbd{q} to quit the mode, and -customize the variable @code{idlwave-shell-automatic-electric-debug} -if you prefer not to enter electric debug on breakpoints@dots{} but -you really should try it before you disable it! You can also -customize this variable to enter debug mode when errors are -encountered. - -@item @strong{I get errors like @samp{Searching for program: no such -file or directory, idl} when attempting to start the IDL shell.} - -IDLWAVE needs to know where IDL is in order to run it as a process. -By default, it attempts to invoke it simply as @samp{idl}, which -presumes such an executable is on your search path. You need to -ensure @samp{idl} is on your @samp{$PATH}, or specify the full -pathname to the idl program with the variable -@code{idlwave-shell-explicit-file-name}. Note that you may need to -set your shell search path in two places when running Emacs as an Aqua -application with macOS; see the next topic. - -@item @strong{IDLWAVE is disregarding my @samp{IDL_PATH} which I set -under macOS} - -If you run Emacs directly as an Aqua application, rather than from the -console shell, the environment is set not from your usual shell -configuration files (e.g., @file{.cshrc}), but from the file -@file{~/.MacOSX/environment.plist}. Either include your path settings -there, or start Emacs and IDLWAVE from the shell. - -@item @strong{@kbd{M-@key{TAB}} doesn't complete words, it switches -windows on my desktop.} - -Your system is trapping @kbd{M-@key{TAB}} and using it for its own -nefarious purposes: Emacs never sees the keystrokes. On many Unix -systems, you can reconfigure your window manager to use another key -sequence for switching among windows. Another option is to use the -equivalent sequence @kbd{@key{ESC}-@key{TAB}}. - -@item @strong{When stopping at breakpoints or errors, IDLWAVE does not -seem to highlight the relevant line in the source.} - -IDLWAVE scans for error and halt messages and highlights the stop -location in the correct file. However, if you've changed the system -variable @samp{!ERROR_STATE.MSG_PREFIX}, it is unable to parse these -message correctly. Don't do that. - -@item @strong{IDLWAVE doesn't work correctly when using ENVI.} - -Though IDLWAVE was not written with ENVI in mind, it works just fine -with it, as long as you update the prompt it's looking for (@samp{IDL> -} by default). You can do this with the variable -@code{idlwave-shell-prompt-pattern} (@pxref{Starting the Shell}), e.g., -in your @file{.emacs}: - -@lisp -(setq idlwave-shell-prompt-pattern "^\r? ?\\(ENVI\\|IDL\\)> ") -@end lisp - -@item @strong{Attempts to set breakpoints fail: no breakpoint is -indicated in the IDLWAVE buffer.} - -IDL changed its breakpoint reporting format starting with IDLv5.5. The -first version of IDLWAVE to support the new format is IDLWAVE v4.10. If -you have an older version and are using IDL >v5.5, you need to upgrade, -and/or make sure your recent version of IDLWAVE is being found on the -Emacs load-path (see the next entry). You can list the version being -used with @kbd{C-h v idlwave-mode-version @key{RET}}. - -@item @strong{I installed a new version of IDLWAVE, but the old -version is still being used} or @strong{IDLWAVE works, but when I -tried to install the optional modules @file{idlw-roprompt.el} or -@file{idlw-complete-structtag}, I get errors like @samp{Cannot open -load file}}. - -The problem is that your Emacs is not finding the version of IDLWAVE you -installed. Emacs might come with an older bundled copy of IDLWAVE -which is likely what's being used instead. -You need to make sure your Emacs @emph{load-path} contains the directory -where IDLWAVE is installed (@file{/usr/local/share/emacs/site-lisp}, by -default), @emph{before} Emacs's default search directories. You can -accomplish this by putting the following in your @file{.emacs}: - -@lisp -(setq load-path (cons "/usr/local/share/emacs/site-lisp" load-path)) -@end lisp - -@noindent You can check on your load-path value using @kbd{C-h v -load-path @key{RET}}, and @kbd{C-h m} in an IDLWAVE buffer should show -you the version Emacs is using. - -@item @strong{IDLWAVE is screwing up the formatting of my @file{.idl} files.} - -Actually, this isn't IDLWAVE at all, but @samp{idl-mode}, an unrelated -programming mode for CORBA's Interface Definition Language (you should -see @samp{(IDL)}, not @samp{(IDLWAVE)} in the mode-line). One -solution: don't name your file @file{.idl}, but rather @file{.pro}. -Another solution: make sure @file{.idl} files load IDLWAVE instead of -@samp{idl-mode} by adding the following to your @file{.emacs}: - -@lisp -(setcdr (rassoc 'idl-mode auto-mode-alist) 'idlwave-mode) -@end lisp - -@item @strong{The routine info for my local routines is out of date!} - -IDLWAVE collects routine info from various locations (@pxref{Routine -Information Sources}). Routines in files visited in a buffer or -compiled in the shell should be up to date. For other routines, the -information is only as current as the most recent scan. If you have a -rapidly changing set of routines, and you'd like the latest routine -information to be available for it, one powerful technique is to make -use of the library catalog tool, @samp{idlwave_catalog}. Simply add a -line to your @samp{cron} file (@samp{crontab -e} will let you edit this -on some systems), like this - -@example -45 3 * * 1-5 (cd /path/to/myidllib; /path/to/idlwave_catalog MyLib) -@end example - -@noindent where @samp{MyLib} is the name of your library. This will -rescan all @file{.pro} files at or below @file{/path/to/myidllib} every -week night at 3:45am. You can even scan site-wide libraries with this -method, and the most recent information will be available to all users. -Since the scanning is very fast, there is very little impact. - -@item @strong{All the Greek-font characters in the HTML help are -displayed as Latin characters!} - -Unfortunately, the HTMLHelp files RSI provides attempt to switch to -@samp{Symbol} font to display Greek characters, which is not really an -permitted method for doing this in HTML@. There is a "workaround" for -some browsers: @xref{HTML Help Browser Tips}. - -@item @strong{In the shell, my long commands are truncated at 256 characters!} - -This actually happens when running IDL in an XTerm as well. There are -a couple of workarounds: @code{define_key,/control,'^d'} (e.g., in -your @file{$IDL_STARTUP} file) will disable the @samp{EOF} character -and give you a 512 character limit. You won't be able to use -@kbd{C-d} to quit the shell, however. Another possibility is -@code{!EDIT_INPUT=0}, which gives you an @emph{infinite} limit (OK, a -memory-bounded limit), but disables the processing of background -widget events (those with @code{/NO_BLOCK} passed to @code{XManager}). - -@item @strong{When I invoke IDL HTML help on a routine, the page which -is loaded is one page off, e.g., for @code{CONVERT_COORD}, I get -@code{CONTOUR}.} - -You have a mismatch between your help index and the HTML help package -you downloaded. You need to ensure you download a ``downgrade kit'' if -you are using anything older than the latest HTML help package. A new -help package appears with each IDL release (assuming the documentation -is updated). -Starting with IDL 6.2, the HTML help and its catalog are -distributed with IDL, and so should never be inconsistent. - -@end enumerate - -@node GNU Free Documentation License -@appendix GNU Free Documentation License -@include doclicense.texi - -@node Index -@unnumbered Index -@printindex cp - -@bye diff --git a/etc/TODO b/etc/TODO index f9918fede38..88287931cf7 100644 --- a/etc/TODO +++ b/etc/TODO @@ -39,11 +39,6 @@ is not always true. We need to figure out how to best include GNU ELPA packages in the Emacs tarball before doing any of the items below. -*** Move idlwave to elpa.gnu.org -Need to sync up the Emacs and external versions. -See - - *** Move Org mode to elpa.gnu.org See diff --git a/lisp/files.el b/lisp/files.el index 730026e925f..10c8999b3ef 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3088,8 +3088,6 @@ since only a single case-insensitive search through the alist is made." ;; Anyway, the following extensions are supported by gfortran. ("\\.f9[05]\\'" . f90-mode) ("\\.f0[38]\\'" . f90-mode) - ("\\.indent\\.pro\\'" . fundamental-mode) ; to avoid idlwave-mode - ("\\.\\(pro\\|PRO\\)\\'" . idlwave-mode) ("\\.prolog\\'" . prolog-mode) ("\\.tar\\'" . tar-mode) ;; The list of archive file extensions should be in sync with diff --git a/lisp/info-look.el b/lisp/info-look.el index 6926d524b82..392d9da71e6 100644 --- a/lisp/info-look.el +++ b/lisp/info-look.el @@ -1063,7 +1063,6 @@ Return nil if there is nothing appropriate in the buffer near point." ("forms" "Index") ("gnus" "Index") ("htmlfontify" "Functions" "Variables & Customization") - ("idlwave" "Index") ("ido" "Variable Index" "Function Index") ("info" "Index") ("mairix" "(mairix-el)Variable Index" "(mairix-el)Function Index") diff --git a/lisp/info.el b/lisp/info.el index 858a9cd1738..d199918bc17 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -218,7 +218,7 @@ These directories are searched after those in `Info-directory-list'." "ede" "ediff" "edt" "efaq" "efaq-w32" "eglot" "eieio" "eintr" "elisp" "emacs" "emacs-gnutls" "emacs-mime" "epa" "erc" "ert" "eshell" "eudc" "eww" "flymake" "forms" "gnus" - "htmlfontify" "idlwave" "ido" "info" "mairix-el" "message" + "htmlfontify" "ido" "info" "mairix-el" "message" "mh-e" "modus-themes" "newsticker" "nxml-mode" "octave-mode" "org" "pcl-cvs" "pgg" "rcirc" "reftex" "remember" "sasl" "sc" "semantic" "ses" "sieve" "smtpmail" "speedbar" "srecode" @@ -4728,7 +4728,7 @@ Advanced commands: (defvar Info-file-list-for-emacs '("ediff" "eudc" "forms" "gnus" "info" ("Info" . "info") - "sc" "message" ("dired" . "dired-x") "viper" "idlwave" + "sc" "message" ("dired" . "dired-x") "viper" ("c" . "ccmode") ("c++" . "ccmode") ("objc" . "ccmode") ("java" . "ccmode") ("idl" . "ccmode") ("pike" . "ccmode") ("skeleton" . "autotype") ("auto-insert" . "autotype") diff --git a/lisp/org/ol-info.el b/lisp/org/ol-info.el index ff9156c5296..282d528473d 100644 --- a/lisp/org/ol-info.el +++ b/lisp/org/ol-info.el @@ -131,7 +131,7 @@ If LINK is not an info link then DESC is returned." '("ada-mode" "auth" "autotype" "bovine" "calc" "ccmode" "cl" "dbus" "dired-x" "ede" "ediff" "efaq-w32" "efaq" "eglot" "eieio" "eintr" "elisp" "emacs-gnutls" "emacs-mime" "emacs" "epa" "erc" "ert" "eshell" - "eudc" "eww" "flymake" "forms" "gnus" "htmlfontify" "idlwave" "ido" "info" + "eudc" "eww" "flymake" "forms" "gnus" "htmlfontify" "ido" "info" "mairix-el" "message" "modus-themes" "newsticker" "nxml-mode" "octave-mode" "org" "pcl-cvs" "pgg" "rcirc" "reftex" "remember" "sasl" "sc" "semantic" "ses" "sieve" "smtpmail" "speedbar" "srecode" "todo-mode" "tramp" "transient" diff --git a/lisp/progmodes/idlw-complete-structtag.el b/lisp/progmodes/idlw-complete-structtag.el deleted file mode 100644 index bcc2ee2f005..00000000000 --- a/lisp/progmodes/idlw-complete-structtag.el +++ /dev/null @@ -1,243 +0,0 @@ -;;; idlw-complete-structtag.el --- Completion of structure tags. -*- lexical-binding: t; -*- - -;; Copyright (C) 2001-2024 Free Software Foundation, Inc. - -;; Author: Carsten Dominik -;; Maintainer: emacs-devel@gnu.org -;; Old-Version: 1.2 -;; Keywords: languages -;; Package: idlwave - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; Completion of structure tags can be done automatically in the -;; shell, since the list of tags can be determined dynamically through -;; interaction with IDL. - -;; Completion of structure tags in a source buffer is highly ambiguous -;; since you never know what kind of structure a variable will hold at -;; runtime. To make this feature useful in source buffers, we need a -;; special assumption/convention. We will assume that the structure is -;; defined in the same buffer and directly assigned to the correct -;; variable. This is mainly useful for applications in which there is one -;; main structure which contains a large amount of information (and many -;; tags). For example, many widget applications define a "state" structure -;; that contains all important data about the application. The different -;; routines called by the event handler then use this structure. If you -;; use the same variable name for this structure throughout your -;; application (a good idea for many reasons), IDLWAVE can support -;; completion for its tags. -;; -;; This file is a completion plugin which implements this kind of -;; completion. It is also an example which shows how completion plugins -;; should be programmed. -;; -;; New versions of IDLWAVE, documentation, and more information available -;; from: -;; https://github.com/jdtsmith/idlwave -;; -;; INSTALLATION -;; ============ -;; Load it with the following line in your init file: -;; -;; (with-eval-after-load 'idlwave -;; (require 'idlw-complete-structtag)) -;; -;; DESCRIPTION -;; =========== -;; Suppose your IDL program contains something like -;; -;; myvar = state.a* -;; -;; where the star marks the cursor position. If you now press the -;; completion key M-TAB, IDLWAVE searches the current file for a -;; structure definition -;; -;; state = {tag1:val1, tag2:val2, ...} -;; -;; and offers the tags for completion. -;; -;; In the idlwave shell, idlwave sends a "print,tag_names()" for the -;; variable to idl and determines the current tag list dynamically. -;; -;; Notes -;; ----- -;; - The structure definition assignment "state = {...}" must use the -;; same variable name as the completion location "state.*". -;; - The structure definition must be in the same file. -;; - The structure definition is searched backwards and then forward -;; from the current position, until a definition with tags is found. -;; - The file is parsed again for each new completion variable and location. -;; - You can force an update of the tag list with the usual command -;; to update routine info in IDLWAVE: C-c C-i - -;;; Code: - -(require 'idlwave) - -(declare-function idlwave-shell-buffer "idlw-shell") - -;; Some variables to identify the previously used structure -(defvar idlwave-current-tags-var nil) -(defvar idlwave-current-tags-buffer nil) -(defvar idlwave-current-tags-completion-pos nil) - -;; The tag list used for completion will be stored in the following vars -(defvar idlwave-current-struct-tags nil) -(defvar idlwave-sint-structtags nil) - -;; Create the sintern type for structure talks -(idlwave-new-sintern-type structtag) - -;; Hook the plugin into idlwave -(add-hook 'idlwave-complete-functions #'idlwave-complete-structure-tag) -(add-hook 'idlwave-update-rinfo-hook #'idlwave-structtag-reset) - -;;; The main code follows below -(defvar idlwave-completion-help-info) -(defun idlwave-complete-structure-tag () - "Complete a structure tag. -This works by looking in the current file for a structure assignment to a -variable with the same name and takes the tags from there. Quite useful -for big structures like the state variables of a widget application. - -In the idlwave shell, the current content of the variable is used to get -an up-to-date completion list." - (interactive) - (let ((pos (point)) - start - (case-fold-search t)) - (if (save-excursion - ;; Check if the context is right. - ;; In the shell, this could be extended to expressions like - ;; x[i+4].name.g*. But it is complicated because we would have - ;; to really parse this expression. For now, we allow only - ;; substructures, like "aaa.bbb.ccc.ddd" - (skip-chars-backward "a-zA-Z0-9._$") - (setq start (point)) ;; remember the start of the completion pos. - (and (< (point) pos) - (not (equal (char-before) ?!)) ; no sysvars - (looking-at "\\([a-zA-Z][.a-zA-Z0-9_]*\\)\\.") - (>= pos (match-end 0)) - (not (string= (downcase (match-string 1)) "self")))) - (let* ((var (downcase (match-string 1)))) - ;; Check if we need to update the "current" structure. Basically we - ;; do it always, except for subsequent completions at the same - ;; spot, to save a bit of time. Implementation: We require - ;; an update if - ;; - the variable is different or - ;; - the buffer is different or - ;; - we are completing at a different position - (if (or (not (string= var (or idlwave-current-tags-var "@"))) - (not (eq (current-buffer) idlwave-current-tags-buffer)) - (not (equal start idlwave-current-tags-completion-pos))) - (idlwave-prepare-structure-tag-completion var)) - (setq idlwave-current-tags-completion-pos start) - (setq idlwave-completion-help-info - (list 'idlwave-complete-structure-tag-help)) - (idlwave-complete-in-buffer 'structtag 'structtag - idlwave-current-struct-tags nil - "Select a structure tag" "structure tag") - t) ; we did the completion: return t to skip other completions - nil))) ; return nil to allow looking for other ways to complete - -(defun idlwave-structtag-reset () - "Force an update of the current structure tag list upon next use." - (setq idlwave-current-tags-buffer nil)) - -(defvar idlwave-structtag-struct-location nil - "The location of the structure definition, for help display.") - -(defun idlwave-prepare-structure-tag-completion (var) - "Find and parse the tag list for structure tag completion." - ;; This works differently in source buffers and in the shell - (if (derived-mode-p 'idlwave-shell-mode) - ;; OK, we are in the shell, do it dynamically - (progn - (message "preparing shell tags") - ;; The following call puts the tags into `idlwave-current-struct-tags' - (idlwave-complete-structure-tag-query-shell var) - ;; initialize - (setq idlwave-sint-structtags nil - idlwave-current-tags-buffer (current-buffer) - idlwave-current-tags-var var - idlwave-structtag-struct-location (point) - idlwave-current-struct-tags - (mapcar (lambda (x) - (list (idlwave-sintern-structtag x 'set))) - idlwave-current-struct-tags)) - (if (not idlwave-current-struct-tags) - (error "Cannot complete structure tags of variable %s" var))) - ;; Not the shell, so probably a source buffer. - (unless - (catch 'exit - (save-excursion - (goto-char (point-max)) - ;; Find possible definitions of the structure. - (while (idlwave-find-structure-definition var nil 'all) - (let ((tags (idlwave-struct-tags))) - (when tags - ;; initialize - (setq idlwave-sint-structtags nil - idlwave-current-tags-buffer (current-buffer) - idlwave-current-tags-var var - idlwave-structtag-struct-location (point) - idlwave-current-struct-tags - (mapcar (lambda (x) - (list (idlwave-sintern-structtag x 'set))) - tags)) - (throw 'exit t)))))) - (error "Cannot complete structure tags of variable %s" var)))) - -(defun idlwave-complete-structure-tag-query-shell (var) - "Ask the shell for the tags of the structure in variable or expression VAR." - (idlwave-shell-send-command - (format "if size(%s,/TYPE) eq 8 then print,tag_names(%s)" var var) - 'idlwave-complete-structure-tag-get-tags-from-help - 'hide 'wait)) - -(defvar idlwave-shell-prompt-pattern) -(defvar idlwave-shell-command-output) -(defun idlwave-complete-structure-tag-get-tags-from-help () - "Filter structure tag name output, result to `idlwave-current-struct-tags'." - (setq idlwave-current-struct-tags - (if (string-match (concat "tag_names(.*) *\n" - "\\(\\(.*[\r\n]?\\)*\\)" - "\\(" idlwave-shell-prompt-pattern "\\)") - idlwave-shell-command-output) - (split-string (match-string 1 idlwave-shell-command-output))))) - - -;; Fake help in the source buffer for structure tags. -;; idlw-help-kwd is a global-variable (from idlwave-do-mouse-completion-help). -(defvar idlw-help-kwd) -(defvar idlwave-help-do-struct-tag) -(defun idlwave-complete-structure-tag-help (mode word) - (cond - ((eq mode 'test) - ;; fontify only in source buffers, not in the shell. - (not (equal idlwave-current-tags-buffer - (get-buffer (idlwave-shell-buffer))))) - ((eq mode 'set) - (setq idlw-help-kwd word - idlwave-help-do-struct-tag idlwave-structtag-struct-location)) - (t (error "This should not happen")))) - -(provide 'idlw-complete-structtag) - -;;; idlw-complete-structtag.el ends here diff --git a/lisp/progmodes/idlw-help.el b/lisp/progmodes/idlw-help.el deleted file mode 100644 index c311e1c5377..00000000000 --- a/lisp/progmodes/idlw-help.el +++ /dev/null @@ -1,1357 +0,0 @@ -;;; idlw-help.el --- HTML Help code for IDLWAVE -*- lexical-binding: t; -*- - -;; Copyright (C) 2000-2024 Free Software Foundation, Inc. -;; -;; Authors: JD Smith -;; Carsten Dominik -;; Maintainer: emacs-devel@gnu.org -;; Package: idlwave - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; The help link information for IDLWAVE's online help feature for -;; system routines is extracted automatically from the IDL -;; documentation, and is available, along with general routine -;; information, in the file idlw-rinfo.el. The HTML help file -;; themselves are not distributable with Emacs, but are available, -;; along with new versions of IDLWAVE, documentation, and more -;; information, at: -;; -;; https://github.com/jdtsmith/idlwave -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;;; Code: - -(require 'browse-url) - -(defgroup idlwave-online-help nil - "Online Help options for IDLWAVE mode." - :group 'idlwave) - -(defcustom idlwave-html-help-pre-v6 nil - "Whether pre or post-v6.0 IDL help documents are being used." - :type 'boolean) - -(defvar idlwave-html-link-sep - (if idlwave-html-help-pre-v6 "#" "#wp")) - -(defcustom idlwave-html-system-help-location "help/online_help/" - "The directory, relative to `idlwave-system-directory', where the IDL -HTML help files live, for IDL 6.2 and later. This location, if found, -is used in preference to the old `idlwave-html-help-location'." - :type 'directory) - -(defcustom idlwave-html-help-location - (if (memq system-type '(ms-dos windows-nt)) - nil - "/usr/local/etc/") - "The directory where the idl_html_help/ dir lives. -Obsolete for IDL 6.2 or later (see `idlwave-html-system-help-location')." - :type 'directory) - -(defcustom idlwave-help-use-assistant t - "Whether to use the IDL Assistant as the help browser." - :type 'boolean) - -(defcustom idlwave-help-browser-function browse-url-browser-function - "Function to use to display HTML help. -Defaults to `browse-url-browser-function', which see." - :type 'function) - -(defcustom idlwave-help-browser-generic-program browse-url-generic-program - "Program to run if using `browse-url-generic-program'." - :type '(choice (const nil) string)) - -;; AFAICS, never used since it was introduced in 2004. -(defcustom idlwave-help-browser-generic-args - (if (boundp 'browse-url-generic-args) - browse-url-generic-args "") - "Program args to use if using `browse-url-generic-program'." - :type '(repeat string)) - -(defcustom idlwave-help-browser-is-local nil - "Whether the browser will display locally in an Emacs window. -Several browsers run and/or display inside Emacs windows, but most are -external programs. If the browser name contains \"-w3\", it is -assumed to be local to Emacs. For other local browsers, this variable -must be explicitly set non-nil in order for the variable -`idlwave-help-use-dedicated-frame' to function." - :type 'boolean) - -(defcustom idlwave-help-use-dedicated-frame t - "Non-nil means, use a separate frame for Online Help if possible." - :type 'boolean) - -(defcustom idlwave-help-frame-parameters - '((height . 32) (unsplittable . t)) - "The frame parameters for the special Online Help frame. -See also `idlwave-help-use-dedicated-frame'. -If you do not set the frame width here, the value specified in -`idlw-help.el' will be used." - :type '(repeat - (cons symbol sexp))) - -(defcustom idlwave-max-popup-menu-items 20 - "Maximum number of items per pane in popup menus. -Currently only used for class selection during completion help." - :type 'integer) - -(defcustom idlwave-extra-help-function 'idlwave-help-with-source - "The function to call for online help if the normal help fails. -Online help works only for system routines which are described in the -IDL manuals. A function may be specified to access help from other sources. - -The function must accept four arguments: NAME, TYPE, CLASS, KEYWORD. -The Help buffer is current when this function is called, and the help -text should be loaded into this buffer. If help is found, the -function should return the buffer position which should be used as -`window-start' in the help window. Also, the variable -`idlwave-help-mode-line-indicator' should be set to a useful string, -which will be displayed in the mode line of the help window. If -should also set the variable `idlwave-help-min-frame-width' to a -positive integer. IDLWAVE will ensure that the help frame is at least -that many columns wide. Failure to find help should be indicated by -throwing an error. - -When this variable is non-nil, IDLWAVE will allow the mouse-3 help click -for every routine and keyword, even though the item may not be highlighted -in blue (indicating the availability of system documentation). - -The default value for this function is `idlwave-help-with-source' which -loads the routine source file into the help buffer. If you try to write -a different function which accesses a special help file or so, it is -probably a good idea to still call this function as a fallback." - :type 'symbol) - -(defcustom idlwave-help-fontify-source-code nil - "Non-nil means, fontify source code displayed as help like normal code." - :type 'boolean) - -(defcustom idlwave-help-source-try-header t - "Non-nil means, try to find help in routine header when displaying source. -Routines which are not documented in the system manual use their source as -help text. When this variable is non-nil, we try to find a description of -the help item in the first routine doclib header above the routine definition. -If the variable is nil, or if we cannot find/parse the header, the routine -definition is displayed instead." - :type 'boolean) - - -(defcustom idlwave-help-doclib-name "name" - "A regexp for the heading word to search for in doclib headers -which specifies the `name' section. Can be used for localization -support." - :type 'regexp) - -(defcustom idlwave-help-doclib-keyword "KEYWORD" - "A regexp for the heading word to search for in doclib headers -which specifies the `keywords' section. Can be used for localization -support." - :type 'regexp) - -(defface idlwave-help-link - '((t :inherit link)) - "Face for highlighting links into IDLWAVE online help.") - -(defvar idlwave-help-activate-links-aggressively nil - "Obsolete variable.") - -(defvar idlwave-completion-help-info) - -(defvar idlwave-help-frame nil - "The frame for display of IDL online help.") -(defvar idlwave-help-frame-width 102 - "The default width of the help frame.") - -(defvar idlwave-html-help-is-available nil - "Is the system online help text available?") - -(defvar idlwave-help-mode-line-indicator "" - "Used for the special mode line in the `idlwave-help-mode'.") - -(defvar idlwave-help-window-configuration nil) -(defvar idlwave-help-special-topic-words nil) ; defined by get_rinfo - -;; Define the key bindings for the Help application - -(defvar idlwave-help-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "q" #'idlwave-help-quit) - (define-key map "w" #'widen) - (define-key map "\C-m" (lambda (arg) - (interactive "p") - (scroll-up arg))) - (define-key map " " #'scroll-up-command) - (define-key map [?\S-\ ] #'scroll-down-command) - (define-key map [delete] #'scroll-down-command) - (define-key map "h" #'idlwave-help-find-header) - (define-key map "H" #'idlwave-help-find-first-header) - (define-key map "." #'idlwave-help-toggle-header-match-and-def) - (define-key map "F" #'idlwave-help-fontify) - (define-key map "\M-?" #'idlwave-help-return-to-calling-frame) - (define-key map "x" #'idlwave-help-return-to-calling-frame) - map) - "The keymap used in `idlwave-help-mode'.") - -;; Define the menu for the Help application - -(easy-menu-define idlwave-help-menu idlwave-help-mode-map - "Menu for Help IDLWAVE system." - '("IDLHelp" - ["Definition <-> Help Text" idlwave-help-toggle-header-match-and-def t] - ["Find DocLib Header" idlwave-help-find-header t] - ["Find First DocLib Header" idlwave-help-find-first-header t] - ["Fontify help buffer" idlwave-help-fontify t] - "--" - ["Quit" idlwave-help-quit t])) - -(defvar idlwave-help-def-pos) -(defvar idlwave-help-args) -(defvar idlwave-help-in-header) -(declare-function idlwave-prepare-structure-tag-completion "idlw-complete-structtag") -(declare-function idlwave-all-method-classes "idlwave") -(declare-function idlwave-all-method-keyword-classes "idlwave") -(declare-function idlwave-beginning-of-statement "idlwave") -(declare-function idlwave-best-rinfo-assoc "idlwave") -(declare-function idlwave-class-found-in "idlwave") -(declare-function idlwave-class-or-superclass-with-tag "idlwave") -(declare-function idlwave-completing-read "idlwave") -(declare-function idlwave-current-routine "idlwave") -(declare-function idlwave-downcase-safe "idlwave") -(declare-function idlwave-entry-find-keyword "idlwave") -(declare-function idlwave-expand-keyword "idlwave") -(declare-function idlwave-find-class-definition "idlwave") -(declare-function idlwave-find-inherited-class "idlwave") -(declare-function idlwave-find-struct-tag "idlwave") -(declare-function idlwave-in-quote "idlwave") -(declare-function idlwave-make-full-name "idlwave") -(declare-function idlwave-members-only "idlwave") -(declare-function idlwave-popup-select "idlwave") -(declare-function idlwave-routine-source-file "idlwave") -(declare-function idlwave-routines "idlwave") -(declare-function idlwave-sintern-class "idlwave") -(declare-function idlwave-sintern-keyword "idlwave") -(declare-function idlwave-sintern-method "idlwave") -(declare-function idlwave-sintern-routine-or-method "idlwave") -(declare-function idlwave-sintern-sysvar "idlwave" t t);idlwave-new-sintern-type -(declare-function idlwave-sintern-sysvartag "idlwave" t t) -(declare-function idlwave-substitute-link-target "idlwave") -(declare-function idlwave-sys-dir "idlwave") -(declare-function idlwave-this-word "idlwave") -(declare-function idlwave-what-module-find-class "idlwave") -(declare-function idlwave-where "idlwave") - -(define-derived-mode idlwave-help-mode special-mode "IDLWAVE Help" - "Major mode for displaying IDL Help. - -This is a VIEW mode for the ASCII version of IDL Help files, -with some extras. Its main purpose is speed - so don't -expect a fully hyper-linked help. - -Scrolling: SPC DEL RET -Text Searches: Inside Topic: Use Emacs search functions -Exit: [q]uit or mouse button 3 will kill the frame - -When the help text is a source file, the following commands are available - -Fontification: [F]ontify the buffer like source code -Jump: [h] to function doclib header - [H] to file doclib header - [.] back and forth between header and definition - -Here are all keybindings. -\\{idlwave-help-mode-map}" - (buffer-disable-undo) - (setq truncate-lines t) - (setq case-fold-search t) - (setq mode-line-format - (list "" - 'mode-line-modified - 'mode-line-buffer-identification - ": " 'idlwave-help-mode-line-indicator - " -%-")) - (setq buffer-read-only t) - (set (make-local-variable 'idlwave-help-def-pos) nil) - (set (make-local-variable 'idlwave-help-args) nil) - (set (make-local-variable 'idlwave-help-in-header) nil)) - -(defun idlwave-html-help-location () - "Return the help directory where HTML files are, or nil if that is unknown." - (let ((syshelp-dir (expand-file-name - idlwave-html-system-help-location (idlwave-sys-dir))) - (help-dir (or (and (stringp idlwave-html-help-location) - (> (length idlwave-html-help-location) 0) - idlwave-html-help-location) - (getenv "IDLWAVE_HELP_LOCATION")))) - (if (and syshelp-dir (file-directory-p syshelp-dir)) - syshelp-dir - (if help-dir - (progn - (setq help-dir (expand-file-name "idl_html_help" help-dir)) - (if (file-directory-p help-dir) help-dir)))))) - -(defvar idlwave-help-assistant-available nil) - -(defun idlwave-help-check-locations () - ;; Check help locations and assistant. - (let ((sys-dir (idlwave-sys-dir)) - (help-loc (idlwave-html-help-location))) - (if (or (not (file-directory-p sys-dir)) - (not help-loc) - (not (file-directory-p help-loc))) - (message - "HTML help location not found: try setting `idlwave-system-directory' and/or `idlwave-html-help-location'.")) - ;; see if we have the assistant - (when (and idlwave-help-use-assistant - (not (eq (idlwave-help-assistant-available) t))) - (message "Cannot locate IDL Assistant, enabling default browser.") - (setq idlwave-help-use-assistant nil)))) - - -(defvar idlwave-current-obj_new-class) -(defvar idlwave-help-diagnostics) -(defvar idlwave-experimental) -(defvar idlwave-last-context-help-pos) -(defun idlwave-do-context-help (&optional arg) - "Wrapper around the call to `idlwave-do-context-help1'. -It collects and prints the diagnostics messages." - (let ((marker (list (current-buffer) (point))) - (idlwave-help-diagnostics nil)) - ;; Check for frame switching. When the command is invoked twice - ;; at the same position, we try to switch to the help frame - ;; FIXME: Frame switching works only on XEmacs - (if (and idlwave-experimental - (equal last-command this-command) - (equal idlwave-last-context-help-pos marker)) - (idlwave-help-select-help-frame) - ;; Do the real thing. - (setq idlwave-last-context-help-pos marker) - (idlwave-do-context-help1 arg) - (if idlwave-help-diagnostics - (message "%s" (mapconcat #'identity - (nreverse idlwave-help-diagnostics) - "; ")))))) - -(defvar idlwave-help-do-class-struct-tag nil) -(defvar idlwave-structtag-struct-location) -(defvar idlwave-help-do-struct-tag nil) -(defvar idlwave-system-variables-alist) -(defvar idlwave-executive-commands-alist) -(defvar idlwave-system-class-info) -(defvar idlwave-query-class) -(defvar idlwave-force-class-query) -(defvar idlw-help-name) -(defvar idlw-help-kwd) -(defvar idlw-help-link) - -(defun idlwave-do-context-help1 (&optional arg) - "The work-horse version of `idlwave-context-help', which see." - (save-excursion - (if (equal (char-after) ?/) - (forward-char 1) - (if (equal (char-before) ?=) - (backward-char 1))) - (let* ((idlwave-query-class nil) - (idlwave-force-class-query (equal arg '(4))) - (chars "a-zA-Z0-9_$.!") - (beg (save-excursion (skip-chars-backward chars) (point))) - (end (save-excursion (skip-chars-forward chars) (point))) - (this-word (buffer-substring-no-properties beg end)) - (st-ass (assoc-string this-word - idlwave-help-special-topic-words t)) - (classtag (and (string-match "self\\." this-word) - (< beg (- end 4)))) - (structtag (and (fboundp 'idlwave-complete-structure-tag) - (string-match "\\`\\([^.]+\\)\\." this-word) - (< beg (- end 4)))) - module keyword cw mod1 mod2 mod3) - (if (or arg - (and (not classtag) - (not structtag) - (not (member (string-to-char this-word) '(?! ?.))))) - ;; Need the module information - (progn - ;; MODULE is (name type class), for this or any inheriting class - (setq module (idlwave-what-module-find-class) - cw (nth 2 (idlwave-where))) ;what would we complete here? - ;; Correct for OBJ_NEW, we may need an INIT method instead. - (if (equal (idlwave-downcase-safe (car module)) "obj_new") - (let* ((bos (save-excursion (idlwave-beginning-of-statement) - (point))) - (str (buffer-substring bos (point)))) - (if (string-match "OBJ_NEW([ \t]*['\"]\\([a-zA-Z][a-zA-Z0-9$_]+\\)['\"]" str) - (setq module (list "init" 'fun (match-string 1 str)) - idlwave-current-obj_new-class (match-string 1 str)) - ))))) - (cond - (arg (setq mod1 module)) - - ;; A special topic -- only system help - ((and st-ass (not (memq cw '(function-keyword procedure-keyword)))) - (setq mod1 (list (cdr st-ass)))) - - ;; A system variable -- only system help - ((string-match - "\\`!\\([a-zA-Z0-9_]+\\)\\(\\.\\([A-Za-z0-9_]+\\)\\)?" - this-word) - (let* ((word (match-string-no-properties 1 this-word)) - (entry (assq (idlwave-sintern-sysvar word) - idlwave-system-variables-alist)) - (tag (match-string-no-properties 3 this-word)) - (tag-target (if tag - (cdr - (assq (idlwave-sintern-sysvartag tag) - (cdr (assq 'tags entry)))))) - (link (nth 1 (assq 'link entry)))) - (if tag-target - (setq link (idlwave-substitute-link-target link - tag-target))) - (setq mod1 (list link)))) - - ;; An executive command -- only system help - ((string-match "^\\.\\([A-Z_]+\\)" this-word) - (let* ((word (match-string 1 this-word)) - (link (cdr (assoc-string - word - idlwave-executive-commands-alist t)))) - (setq mod1 (list link)))) - - ;; A class -- system OR in-text help (via class__define). - ((and (eq cw 'class) - (or (idlwave-in-quote) ; e.g. obj_new - (re-search-backward "\\\\)" - (concat - "\\|" - ;; class__define or just class - (regexp-quote (downcase class)) "\\(__define\\)?") - "\\)") - (regexp-quote (downcase name)))) - - ;; NAME tag plus the routine name. The new version is from JD. - (name-re (concat - "\\(^;+\\*?[ \t]*" - idlwave-help-doclib-name - "\\([ \t]*:\\|[ \t]*$\\)[ \t]*\\(\n;+[ \t]*\\)*" - rname - "\\|" - "^;+[ \t]*" - rname - ":[ \t]*$\\)")) - - ;; Header start plus name - ;; (header-re (concat "\\(" idlwave-doclib-start "\\).*\n" - ;; "\\(^;+.*\n\\)*" - ;; "\\(" name-re "\\)")) - ;; A keywords section - (kwds-re (concat ; forgiving - "^;+\\*?[ \t]*" - "\\([-A-Z_ ]*" - idlwave-help-doclib-keyword - "[-A-Z_ ]*\\)" - "\\(:\\|[ \t]*\n\\)")) - - ;; The individual keyword description line. - (kwd-re (if keyword ; hard (well...) - (concat - "^;+[ \t]+" - "\\(/" (regexp-quote (upcase keyword)) - "\\|" (regexp-quote (upcase keyword)) "[ \t]*[-=:\n]" - "\\)"))) - (kwd-re2 (if keyword ; forgiving - (concat - "^;+[ \t]+" - (regexp-quote (upcase keyword)) - "\\>"))) - dstart dend name-pos kwds-pos kwd-pos) - (catch 'exit - (save-excursion - (goto-char (point-min)) - (while (and (setq dstart (re-search-forward idlwave-doclib-start nil t)) - (setq dend (re-search-forward idlwave-doclib-end nil t))) - ;; found a routine header - (goto-char dstart) - (if (setq name-pos (re-search-forward name-re dend t)) - (progn - (if keyword - ;; We do need a keyword - (progn - ;; Try to find a keyword section, but don't force it. - (goto-char name-pos) - (if (let ((case-fold-search nil)) - (re-search-forward kwds-re dend t)) - (setq kwds-pos (match-beginning 0))) - ;; Find the keyword description - (if (or (let ((case-fold-search nil)) - (re-search-forward kwd-re dend t)) - (re-search-forward kwd-re dend t) - (let ((case-fold-search nil)) - (re-search-forward kwd-re2 dend t)) - (re-search-forward kwd-re2 dend t)) - (setq kwd-pos (match-beginning 0)) - (if exact - (progn - (idlwave-help-diagnostics - (format "Could not find description of kwd %s" - (upcase keyword))) - (throw 'exit nil)))))) - ;; Return the best position we got - (throw 'exit (or kwd-pos kwds-pos name-pos dstart))) - (goto-char dend)))) - (idlwave-help-diagnostics "Could not find doclib header") - (throw 'exit nil)))) - -(defun idlwave-help-diagnostics (string &optional ding) - "Add a diagnostics string to the list. -When DING is non-nil, ring the bell as well." - (if (boundp 'idlwave-help-diagnostics) - (progn - (setq idlwave-help-diagnostics - (cons string idlwave-help-diagnostics)) - (if ding (ding))))) - -(defun idlwave-help-toggle-header-top-and-def (&optional _arg) - (interactive) - (let (pos) - (if idlwave-help-in-header - ;; Header was the last thing displayed - (progn - (setq idlwave-help-in-header nil) - (setq pos idlwave-help-def-pos)) - ;; Try to display header - (setq pos (idlwave-help-find-in-doc-header - (nth 0 idlwave-help-args) - (nth 1 idlwave-help-args) - (nth 2 idlwave-help-args) - nil)) - (if pos - (setq idlwave-help-in-header t) - (error "Cannot find doclib header for routine %s" - (idlwave-make-full-name (nth 2 idlwave-help-args) - (nth 0 idlwave-help-args))))) - (if pos - (progn - (goto-char pos) - (recenter 0))))) - -(defun idlwave-help-find-first-header (&optional _arg) - (interactive) - (let (pos) - (save-excursion - (goto-char (point-min)) - (if (re-search-forward idlwave-doclib-start nil t) - (setq pos (match-beginning 0)))) - (if pos - (progn - (goto-char pos) - (recenter 0)) - (error "No DocLib Header in current file")))) - -(defun idlwave-help-find-header (arg) - "Jump to the DocLib Header." - (interactive "P") - (if arg - (idlwave-help-find-first-header nil) - (setq idlwave-help-in-header nil) - (idlwave-help-toggle-header-match-and-def arg 'top))) - -(defun idlwave-help-toggle-header-match-and-def (&optional _arg top) - (interactive) - (let ((args idlwave-help-args) - pos) - (if idlwave-help-in-header - ;; Header was the last thing displayed - (progn - (setq idlwave-help-in-header nil) - (setq pos idlwave-help-def-pos)) - ;; Try to display header - (setq pos (apply #'idlwave-help-find-in-doc-header - (if top - (list (car args) (nth 1 args) (nth 2 args) nil) - args))) - (if pos - (setq idlwave-help-in-header t) - (error "Cannot find doclib header for routine %s" - (idlwave-make-full-name (nth 2 idlwave-help-args) - (nth 0 idlwave-help-args))))) - (if pos - (progn - (goto-char pos) - (recenter 0))))) - -(defvar idlwave-mode-syntax-table) -(defvar idlwave-font-lock-defaults) -(defun idlwave-help-fontify () - "Fontify the Help buffer as source code. -Useful when source code is displayed as help. See the option -`idlwave-help-fontify-source-code'." - (interactive) - (let ((major-mode 'idlwave-mode) - (font-lock-verbose - (if (called-interactively-p 'interactive) font-lock-verbose nil))) - (with-syntax-table idlwave-mode-syntax-table - (set (make-local-variable 'font-lock-defaults) - idlwave-font-lock-defaults) - (if (fboundp 'font-lock-ensure) ; Emacs >= 25.1 - (font-lock-ensure) - ;; Silence "interactive use only" warning on Emacs >= 25.1. - (with-no-warnings (font-lock-fontify-buffer)))))) - - -(defun idlwave-help-error (name _type class keyword) - (error "Can't find help on %s%s %s" - (or (and (or class name) (idlwave-make-full-name class name)) - "") - (if keyword (format ", keyword %s" (upcase keyword)) "") - (if idlwave-html-help-location - "" - "(help location unknown)"))) - -(defun idlwave-help-show-help-frame () - "Show the help frame, creating it if necessary." - ;; Use a special frame for this - (unless (frame-live-p idlwave-help-frame) - (setq idlwave-help-frame - (make-frame idlwave-help-frame-parameters)) - ;; Strip menubar (?) and toolbar from the Help frame. - (modify-frame-parameters idlwave-help-frame - '(;;(menu-bar-lines . 0) - (tool-bar-lines . 0)))) - (select-frame idlwave-help-frame)) - -(defun idlwave-help-get-help-buffer () - "Return the IDLWAVE Help buffer. Make it first if necessary." - (let ((buf (get-buffer "*IDLWAVE Help*"))) - (if buf - nil - (setq buf (get-buffer-create "*IDLWAVE Help*")) - (with-current-buffer buf - (idlwave-help-mode))) - buf)) - -(defun idlwave-grep (regexp list) - (let (rtn) - (while list - (if (string-match regexp (car list)) - (setq rtn (cons (car list) rtn))) - (setq list (cdr list))) - (nreverse rtn))) - -(defun idlwave-entry-has-help (entry) - (and entry (car (nth 5 entry)))) - -(defun idlwave-has-help (name type class) - "Does this have help associated with it?" - (let ((entry (idlwave-best-rinfo-assoc name type class (idlwave-routines)))) - (idlwave-entry-has-help entry))) - -;;----- Control the IDL Assistant, which shipped with IDL v6.2 -(defvar idlwave-help-assistant-process nil) -(defvar idlwave-help-assistant-socket nil) - -;; The Windows version does not have a !DIR/bin/* set of front-end -;; scripts, but instead only links directly to bin.x86. As a result, -;; we must pass the -profile argument as well. -(defvar idlwave-help-assistant-command - (if (memq system-type '(ms-dos windows-nt)) - "bin/bin.x86/idl_assistant.exe" - "bin/idl_assistant") - "The command, rooted at `idlwave-system-directory', which invokes the -IDL assistant.") - -(defun idlwave-help-assistant-available () - (if idlwave-help-assistant-available - (eq idlwave-help-assistant-available t) - (setq idlwave-help-assistant-available - (if (file-executable-p (idlwave-help-assistant-command)) - t - 'not-available)))) - -(defun idlwave-help-assistant-command () - (expand-file-name idlwave-help-assistant-command (idlwave-sys-dir))) - -(defun idlwave-help-assistant-start (&optional full-link) - "Start the IDL Assistant, loading link FULL-LINK, if passed." - (when (or (not idlwave-help-assistant-socket) - (not (eq (process-status idlwave-help-assistant-socket) 'open))) - (let* ((help-loc (idlwave-html-help-location)) - (command (idlwave-help-assistant-command)) - (extra-args - (nconc - (if (memq system-type '(ms-dos windows-nt)) - `("-profile" ,(expand-file-name "idl.adp" help-loc))) - (if full-link `("-file" ,full-link)))) - port) - (if idlwave-help-assistant-socket - (delete-process idlwave-help-assistant-socket)) - - (setq idlwave-help-assistant-process - (apply #'start-process - "IDL_ASSISTANT_PROC" nil command "-server" extra-args)) - - (set-process-filter idlwave-help-assistant-process - (lambda (_proc string) - (setq port (string-to-number string)))) - (unless (accept-process-output idlwave-help-assistant-process 15) - (error "Failed binding IDL_ASSISTANT socket")) - (if (not port) - (error "Unable to open IDL_ASSISTANT") - (set-process-filter idlwave-help-assistant-process nil) - (setq idlwave-help-assistant-socket - (open-network-stream "IDL_ASSISTANT_SOCK" - nil "localhost" port)) - (if (eq (process-status idlwave-help-assistant-socket) 'open) - (progn - (process-send-string idlwave-help-assistant-socket - (concat "setHelpPath " help-loc "\n")) - t) - (idlwave-help-assistant-close) - (error "Cannot communicate with IDL_ASSISTANT")))))) - -(defun idlwave-help-assistant-raise () - (idlwave-help-assistant-start) - (process-send-string idlwave-help-assistant-socket "raise\n")) - -(defun idlwave-help-assistant-open-link (&optional link) - ;; Open a link (file name with anchor, no leading path) in the assistant. - (let ((help-loc (idlwave-html-help-location)) - topic anchor file just-started exists full-link) - - (if (string-match "\\.html" link) - (setq topic (substring link 0 (match-beginning 0)) - anchor (substring link (match-end 0))) - (error "Malformed help link")) - - (setq file (expand-file-name (concat topic ".html") help-loc)) - (if (file-exists-p file) - (setq exists t) - (setq file (expand-file-name - (concat (upcase topic) ".html") help-loc)) - (setq exists (file-exists-p file))) - - (setq full-link (concat file anchor) - just-started (idlwave-help-assistant-start (if exists full-link))) - (if exists - (progn - (if (not just-started) - (process-send-string idlwave-help-assistant-socket - (concat "openLink " full-link "\n"))) - (process-send-string idlwave-help-assistant-socket - (concat "searchIndexNoOpen " topic "\n"))) - (process-send-string idlwave-help-assistant-socket - (concat "searchIndexAndOpen " topic "\n")))) - (idlwave-help-assistant-raise)) - -(defvar idlwave-help-assistant-help-with-topic-history nil - "The history of help topics selected with the minibuffer.") - -(defvar idlwave-system-routines) - -(defun idlwave-help-assistant-help-with-topic (&optional topic) - "Prompt for and provide help with TOPIC." - (interactive) - (let (list) - (unless topic - (idlwave-routines) - (setq list (append (mapcar (lambda (x) - (concat (nth 2 x) (car x))) - idlwave-system-routines) - (mapcar (lambda (x) - (concat "." (car x))) - idlwave-executive-commands-alist) - idlwave-system-class-info)) - (setq topic - (idlwave-completing-read - "Help Topic: " list - nil nil nil - 'idlwave-help-assistant-help-with-topic-history))) - (if (and topic (not (string= topic ""))) - (idlwave-help-assistant-open-link (concat topic ".html"))))) - -(defun idlwave-help-assistant-close () - (when (and idlwave-help-assistant-process - (eq (process-status idlwave-help-assistant-process) 'run)) - (when idlwave-help-assistant-socket - (process-send-string idlwave-help-assistant-socket "quit\n") - (delete-process idlwave-help-assistant-socket)) - (stop-process idlwave-help-assistant-process) - (delete-process idlwave-help-assistant-process) - (setq idlwave-help-assistant-socket nil - idlwave-help-assistant-process nil))) - -;;; Obsolete - -(defvar idlwave-help-browse-url-available t) -(make-obsolete-variable 'idlwave-help-browse-url-available nil "28.1") -(defvar idlwave-help-use-hh nil "Obsolete variable.") -(make-obsolete-variable 'idlwave-help-use-hh nil "28.1") -(defvar idlwave-help-directory "" - "Obsolete variable. See `idlwave-html-help-location'.") -(make-obsolete-variable 'idlwave-help-directory nil "28.1") - -(provide 'idlw-help) -(provide 'idlwave-help) - -;;; idlw-help.el ends here diff --git a/lisp/progmodes/idlw-shell.el b/lisp/progmodes/idlw-shell.el deleted file mode 100644 index b5d91f46b17..00000000000 --- a/lisp/progmodes/idlw-shell.el +++ /dev/null @@ -1,4490 +0,0 @@ -;;; idlw-shell.el --- run IDL as an inferior process of Emacs. -*- lexical-binding:t -*- - -;; Copyright (C) 1999-2024 Free Software Foundation, Inc. - -;; Authors: JD Smith -;; Carsten Dominik -;; Chris Chase -;; Maintainer: emacs-devel@gnu.org -;; Keywords: processes -;; Package: idlwave - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: -;; -;; This mode is for IDL version 5 or later. -;; -;; Runs IDL as an inferior process of Emacs, much like the Emacs -;; `shell' or `telnet' commands. Provides command history and -;; searching. Provides debugging commands available in buffers -;; visiting IDL procedure files, e.g., breakpoint setting, stepping, -;; execution until a certain line, printing expressions under point, -;; visual line pointer for current execution line, etc. -;; -;; Documentation should be available online with `M-x idlwave-info'. -;; -;; New versions of IDLWAVE, documentation, and more information -;; available from: -;; https://github.com/jdtsmith/idlwave -;; -;; INSTALLATION: -;; ============= -;; -;; Follow the instructions in the INSTALL file of the distribution. -;; In short, put this file on your load path and add the following -;; lines to your init file: -;; -;; (autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t) -;; -;; -;; SOURCE -;; ====== -;; -;; The newest version of this file can be found on the maintainers -;; web site. -;; -;; https://github.com/jdtsmith/idlwave -;; -;; DOCUMENTATION -;; ============= -;; -;; IDLWAVE is documented online in info format. -;; A printable version of the documentation is available from the -;; maintainers webpage (see under SOURCE) -;; -;; -;; CUSTOMIZATION VARIABLES -;; ======================= -;; -;; IDLWAVE has customize support - so if you want to learn about -;; the variables which control the behavior of the mode, use -;; `M-x idlwave-customize'. -;; -;;-------------------------------------------------------------------------- -;; - -;;; Code: - -(require 'comint) -(require 'idlwave) - -(eval-when-compile (require 'cl-lib)) - -(defvar idlwave-shell-have-new-custom nil) - -;;; Customizations: idlwave-shell group - -;; General/Misc. customizations -(defgroup idlwave-shell-general-setup nil - "General setup of the Shell interaction for IDLWAVE/Shell." - :prefix "idlwave-shell" - :group 'idlwave) - -(defcustom idlwave-shell-prompt-pattern "^\r? ?IDL> " - "Regexp to match IDL prompt at beginning of a line. -For example, \"^\\r?IDL> \" or \"^\\r?WAVE> \". -The \"^\\r?\" is needed, to indicate the beginning of the line, with -optional return character (which IDL seems to output randomly). -This variable is used to initialize `comint-prompt-regexp' in the -process buffer." - :group 'idlwave-shell-general-setup - :type 'regexp) - -(defcustom idlwave-shell-process-name "idl" - "Name to be associated with the IDL process. -The buffer for the process output is made by surrounding this -name with `*'s." - :group 'idlwave-shell-general-setup - :type 'string) - -;; (defcustom idlwave-shell-automatic-start...) See idlwave.el - -(defcustom idlwave-shell-use-dedicated-window nil - "Non-nil means, never replace the shell frame with another buffer." - :group 'idlwave-shell-general-setup - :type 'boolean) - -(defcustom idlwave-shell-use-dedicated-frame nil - "Non-nil means, IDLWAVE should use a special frame to display shell buffer." - :group 'idlwave-shell-general-setup - :type 'boolean) - -(defcustom idlwave-shell-frame-parameters - '((height . 30) (unsplittable . nil)) - "The frame parameters for a dedicated `idlwave-shell' frame. -See also `idlwave-shell-use-dedicated-frame'. -The default makes the frame splittable, so that completion works correctly." - :group 'idlwave-shell-general-setup - :type '(repeat - (cons symbol sexp))) - -(defcustom idlwave-shell-raise-frame t - "Non-nil means, `idlwave-shell' raises the frame showing the shell window." - :group 'idlwave-shell-general-setup - :type 'boolean) - -(defcustom idlwave-shell-arrows-do-history t - "Non-nil means UP and DOWN arrows move through command history. -This variable can have 3 values: -nil Arrows just move the cursor -t Arrows force the cursor back to the current command line and - walk the history -`cmdline' When the cursor is in the current command line, arrows walk the - history. Everywhere else in the buffer, arrows move the cursor." - :group 'idlwave-shell-general-setup - :type '(choice - (const :tag "never" nil) - (const :tag "everywhere" t) - (const :tag "in command line only" cmdline))) - -;; FIXME: add comint-input-ring-size? - -(defcustom idlwave-shell-use-toolbar t - "Non-nil means, use the debugging toolbar in all IDL related buffers. -Starting the shell will then add the toolbar to all `idlwave-mode' buffers. -Exiting the shell will removed everywhere. -At any time you can toggle the display of the toolbar with -\\[idlwave-shell-toggle-toolbar]." - :group 'idlwave-shell-general-setup - :type 'boolean) - -(defcustom idlwave-shell-temp-pro-prefix "/tmp/idltemp" - "The prefix for temporary IDL files used when compiling regions. -It should be an absolute pathname. -The full temporary file name is obtained by using `make-temp-file' -so that the name will be unique among multiple Emacs processes." - :group 'idlwave-shell-general-setup - :type 'string) - -(defcustom idlwave-shell-prefix-key "\C-c\C-d" - "The prefix key for the debugging map `idlwave-shell-mode-prefix-map'. -This variable must already be set when idlwave-shell.el is loaded. -Setting it in the mode-hook is too late." - :group 'idlwave-shell-general-setup - :type 'string) - -(defcustom idlwave-shell-activate-prefix-keybindings t - "Non-nil means, the debug commands will be bound to the prefix key. -The prefix key itself is given in the option `idlwave-shell-prefix-key'. -So by default setting a breakpoint will be on C-c C-d C-b." - :group 'idlwave-shell-general-setup - :type 'boolean) - -(defcustom idlwave-shell-automatic-electric-debug 'breakpoint - "Enter the electric-debug minor mode automatically. -This occurs at a breakpoint or any other halt. The mode is exited -upon return to the main level. Can be set to `breakpoint' to enter -electric debug mode only when breakpoints are tripped." - :group 'idlwave-shell-general-setup - :type '(choice - (const :tag "never" nil) - (const :tag "always" t) - (const :tag "for breakpoints only" breakpoint))) - -(defcustom idlwave-shell-electric-zap-to-file t - "When entering electric debug mode, select the window displaying the -file at which point is stopped. This takes point away from the shell -window, but is useful for stepping, etc." - :group 'idlwave-shell-general-setup - :type 'boolean) - -;; (defcustom idlwave-shell-debug-modifiers... See idlwave.el - -(defcustom idlwave-shell-use-truename nil - "Non-nil means, use `file-truename' when looking for buffers. -If this variable is non-nil, Emacs will use the function `file-truename' to -resolve symbolic links in the file paths printed by e.g., STOP commands. -This means, unvisited files will be loaded under their truename. -However, when a file is already visited under a different name, IDLWAVE will -reuse that buffer. -This option was once introduced in order to avoid multiple buffers visiting -the same file. However, IDLWAVE no longer makes this mistake, so it is safe -to set this option to nil." - :group 'idlwave-shell-general-setup - :type 'boolean) - -(defcustom idlwave-shell-file-name-chars "~/A-Za-z0-9+:_.$#%={}\\- " - "The characters allowed in file names, as a string. -Used for file name completion. Must not contain `\\='', `,' and `\"' -because these are used as separators by IDL." - :group 'idlwave-shell-general-setup - :type 'string) - -(defcustom idlwave-shell-mode-hook '() - "Hook for customizing `idlwave-shell-mode'." - :group 'idlwave-shell-general-setup - :type 'hook) - -(defcustom idlwave-shell-graphics-window-size '(500 400) - "Size of IDL graphics windows popped up by special IDLWAVE command. -The command is \\`C-c C-d C-f' and accepts as a prefix the window nr. -A command like `WINDOW,N,xsize=XX,ysize=YY' is sent to IDL." - :group 'idlwave-shell-general-setup - :type '(list - (integer :tag "x size") - (integer :tag "y size"))) - - -;; Commands Sent to Shell... etc. -(defgroup idlwave-shell-command-setup nil - "Setup for command parameters of the Shell interaction for IDLWAVE." - :prefix "idlwave-shell" - :group 'idlwave) - -(defcustom idlwave-shell-initial-commands "!more=0 & defsysv,'!ERROR_STATE',EXISTS=__e & if __e then begin & !ERROR_STATE.MSG_PREFIX=\"% \" & delvar,__e & endif" - "Initial commands, separated by newlines, to send to IDL. -This string is sent to the IDL process by `idlwave-shell-mode' which is -invoked by `idlwave-shell'." - :group 'idlwave-shell-command-setup - :type 'string) - -(defcustom idlwave-shell-save-command-history t - "Non-nil means preserve command history between sessions. -The file `idlwave-shell-command-history-file' is used to save and restore -the history." - :group 'idlwave-shell-command-setup - :type 'boolean) - -(defcustom idlwave-shell-command-history-file "idlwhist" - "The file in which the command history of the idlwave shell is saved. -In order to change the size of the history, see the variable -`comint-input-ring-size'. -The history is only saved if the variable `idlwave-shell-save-command-history' -is non-nil." - :group 'idlwave-shell-command-setup - :type 'file) - -(defcustom idlwave-shell-show-commands - '(run misc breakpoint) - "A list of command types to show output from in the shell. -Possibilities are `run', `debug', `breakpoint', and `misc'. Unselected -types are not displayed in the shell. The type `everything' causes all -the copious shell traffic to be displayed." - :group 'idlwave-shell-command-setup - :type '(choice - (const everything) - (set :tag "Checklist" :greedy t - (const :tag "All .run and .compile commands" run) - (const :tag "All breakpoint commands" breakpoint) - (const :tag "All debug and stepping commands" debug) - (const :tag "Close, window, retall, etc. commands" misc)))) - -(defcustom idlwave-shell-max-print-length 200 - "Maximum number of array elements to print when examining." - :group 'idlwave-shell-command-setup - :type 'integer) - -(defcustom idlwave-shell-examine-alist - `(("Print" . ,(concat "idlwave_print_safe,___," - (number-to-string - idlwave-shell-max-print-length))) - ("Help" . "help,___") - ("Structure Help" . "help,___,/STRUCTURE") - ("Dimensions" . "print,size(___,/DIMENSIONS)") - ("Type" . "print,size(___,/TNAME)") - ("N_Elements" . "print,n_elements(___)") - ("All Size Info" . "help,(__IWsz__=size(___,/STRUCTURE)),/STRUCTURE & print,__IWsz__.DIMENSIONS") - ("Ptr Valid" . "print,ptr_valid(___)") - ("Arg Present" . "print,arg_present(___)") - ("Widget Valid" . "print,widget_info(___,/VALID)") - ("Widget Geometry" . "help,widget_info(___,/GEOMETRY)")) - "Alist of special examine commands for popup selection. -The keys are used in the selection popup created by -`idlwave-shell-examine-select', and the corresponding value is sent as -a command to the shell, with special sequence `___' replaced by the -expression being examined." - :group 'idlwave-shell-command-setup - :type '(repeat - (cons - (string :tag "Label ") - (string :tag "Command")))) - -(defcustom idlwave-shell-separate-examine-output t - "Non-nil means, put output of examine commands in their own buffer." - :group 'idlwave-shell-command-setup - :type 'boolean) - -(defcustom idlwave-shell-comint-settings - '((comint-scroll-to-bottom-on-input . t) - (comint-scroll-to-bottom-on-output . t) - (comint-scroll-show-maximum-output . nil) - (comint-prompt-read-only . t)) - - "Alist of special settings for the comint variables in the IDLWAVE Shell. -Each entry is a cons cell with the name of a variable and a value. -The function `idlwave-shell-mode' will make local variables out of each entry. -Changes to this variable will only be active when the shell buffer is -newly created." - :group 'idlwave-shell-command-setup - :type '(repeat - (cons variable sexp))) - -(defcustom idlwave-shell-query-for-class t - "Non-nil means query the shell for object class on object completions." - :group 'idlwave-shell-command-setup - :type 'boolean) - -(defcustom idlwave-shell-use-input-mode-magic nil - "Non-nil means, IDLWAVE should check for input mode spells in output. -The spells are strings printed by your IDL program and matched -by the regular expressions in `idlwave-shell-input-mode-spells'. -When these expressions match, IDLWAVE switches to character input mode and -back, respectively. See `idlwave-shell-input-mode-spells' for details." - :group 'idlwave-shell-command-setup - :type 'boolean) - -(defcustom idlwave-shell-input-mode-spells - '("^$" "^$" "^$") - "The three regular expressions which match the magic spells for input modes. - -When the first regexp matches in the output stream of IDL, IDLWAVE -prompts for a single character and sends it immediately to IDL, similar -to the command \\[idlwave-shell-send-char]. - -When the second regexp matches, IDLWAVE switches to a blocking -single-character input mode. This is the same mode which can be entered -manually with \\[idlwave-shell-char-mode-loop]. -This input mode exits when the third regexp matches in the output, -or when the IDL prompt is encountered. - -The variable `idlwave-shell-use-input-mode-magic' must be non-nil to enable -scanning for these expressions. If the IDL program produces lots of -output, shell operation may be slowed down. - -This mechanism is useful for correct interaction with the IDL function -GET_KBRD, because in normal operation IDLWAVE only sends \\n terminated -strings. Here is some example code which makes use of the default spells. - - print,\\='\\=' ; Make IDLWAVE switch to character mode - REPEAT BEGIN - A = GET_KBRD(1) - PRINT, BYTE(A) - ENDREP UNTIL A EQ \\='q\\=' - print,\\='\\=' ; Make IDLWAVE switch back to line mode - - print,\\='Quit the program, y or n?\\=' - print,\\='\\=' ; Ask IDLWAVE to send one character - answer = GET_KBRD(1) - -Since the IDLWAVE shell defines the system variable `!IDLWAVE_VERSION', -you could actually check if you are running under Emacs before printing -the magic strings. Here is a procedure which uses this. - -Usage: -====== -idlwave_char_input ; Make IDLWAVE send one character -idlwave_char_input,/on ; Start the loop to send characters -idlwave_char_input,/off ; End the loop to send characters - - -pro idlwave_char_input,on=on,off=off - ;; Test if we are running under Emacs - defsysv,\\='!idlwave_version\\=',exists=running_emacs - if running_emacs then begin - if keyword_set(on) then print,\\='\\=' $ - else if keyword_set(off) then print,\\='\\=' $ - else print,\\='\\=' - endif -end" - :group 'idlwave-shell-command-setup - :type '(list - (regexp :tag "One-char regexp") - (regexp :tag "Char-mode regexp") - (regexp :tag "Line-mode regexp"))) - -(defcustom idlwave-shell-breakpoint-popup-menu t - "If non-nil, provide a menu on mouse-3 on breakpoint lines, and -popup help text on the line." - :group 'idlwave-shell-command-setup - :type 'boolean) - -(defcustom idlwave-shell-reset-no-prompt nil - "If non-nil, skip the yes/no prompt when resetting the IDL session." - :group 'idlwave-shell-command-setup - :type 'boolean) - -;; Breakpoint Overlays etc -(defgroup idlwave-shell-highlighting-and-faces nil - "Highlighting and faces used by the IDLWAVE Shell mode." - :prefix "idlwave-shell" - :group 'idlwave) - -(defcustom idlwave-shell-mark-stop-line t - "Non-nil means, mark the source code line where IDL is currently stopped. -Value decides about the method which is used to mark the line. Valid values -are: - -nil Do not mark the line -`arrow' Use the overlay arrow -`face' Use `idlwave-shell-stop-line-face' to highlight the line. -t Use what IDLWAVE thinks is best. Will be a face where possible, - otherwise the overlay arrow. -The overlay-arrow has the disadvantage to hide the first chars of a line. -Since many people do not have the main block of IDL programs indented, -a face highlighting may be better." - :group 'idlwave-shell-highlighting-and-faces - :type '(choice - (const :tag "No marking" nil) - (const :tag "Use overlay arrow" arrow) - (const :tag "Highlight with face" face) - (const :tag "Face or arrow." t))) - -(defcustom idlwave-shell-overlay-arrow ">" - "The overlay arrow to display at source lines where execution halts. -We use a single character by default, since the main block of IDL procedures -often has no indentation. Where possible, IDLWAVE will use overlays to -display the stop-lines. The arrow is only used on character-based terminals. -See also `idlwave-shell-mark-stop-line'." - :group 'idlwave-shell-highlighting-and-faces - :type 'string) - -(defcustom idlwave-shell-stop-line-face 'highlight - "The face for `idlwave-shell-stop-line-overlay'. -Allows you to choose the font, color and other properties for -line where IDL is stopped. See also `idlwave-shell-mark-stop-line'." - :group 'idlwave-shell-highlighting-and-faces - :type 'symbol) - -(defcustom idlwave-shell-electric-stop-color "Violet" - "The color for the default face or overlay arrow when stopped." - :group 'idlwave-shell-highlighting-and-faces - :type 'string) - -(defcustom idlwave-shell-electric-stop-line-face - (prog1 - (copy-face 'mode-line 'idlwave-shell-electric-stop-line) - (set-face-background 'idlwave-shell-electric-stop-line - idlwave-shell-electric-stop-color) - (condition-case nil - (set-face-foreground 'idlwave-shell-electric-stop-line nil) - (error nil))) - "The face for `idlwave-shell-stop-line-overlay' when in electric debug mode. -Allows you to choose the font, color and other properties for the line -where IDL is stopped, when in Electric Debug Mode." - :group 'idlwave-shell-highlighting-and-faces - :type 'symbol) - -(defcustom idlwave-shell-mark-breakpoints t - "Non-nil means, mark breakpoints in the source files. -Valid values are: -nil Do not mark breakpoints. -`face' Highlight line with `idlwave-shell-breakpoint-face'. -`glyph' Red dot at the beginning of line. If the display does not - support glyphs, will use `face' instead. -t Glyph when possible, otherwise face (same effect as `glyph')." - :group 'idlwave-shell-highlighting-and-faces - :type '(choice - (const :tag "No marking" nil) - (const :tag "Highlight with face" face) - (const :tag "Display glyph (red dot)" glyph) - (const :tag "Glyph or face." t))) - -(defcustom idlwave-shell-breakpoint-face 'idlwave-shell-bp - "The face for breakpoint lines in the source code. -Allows you to choose the font, color and other properties for -lines which have a breakpoint. See also `idlwave-shell-mark-breakpoints'." - :group 'idlwave-shell-highlighting-and-faces - :type 'symbol) - -(if (not idlwave-shell-have-new-custom) - ;; Just copy the underline face to be on the safe side. - (copy-face 'underline 'idlwave-shell-bp) - ;; We have the new customize - use it to define a customizable face - (defface idlwave-shell-bp - '((((class color)) (:foreground "Black" :background "Pink")) - (t (:underline t))) - "Face for highlighting lines with breakpoints." - :group 'idlwave-shell-highlighting-and-faces)) - -(defcustom idlwave-shell-disabled-breakpoint-face - 'idlwave-shell-disabled-bp - "The face for disabled breakpoint lines in the source code. -Allows you to choose the font, color and other properties for -lines which have a breakpoint. See also `idlwave-shell-mark-breakpoints'." - :group 'idlwave-shell-highlighting-and-faces - :type 'symbol) - -(if (not idlwave-shell-have-new-custom) - ;; Just copy the underline face to be on the safe side. - (copy-face 'underline 'idlwave-shell-disabled-bp) - ;; We have the new customize - use it to define a customizable face - (defface idlwave-shell-disabled-bp - '((((class color)) (:foreground "Black" :background "gray")) - (t (:underline t))) - "Face for highlighting lines with breakpoints." - :group 'idlwave-shell-highlighting-and-faces)) - - -(defcustom idlwave-shell-expression-face 'secondary-selection - "The face for `idlwave-shell-expression-overlay'. -Allows you to choose the font, color and other properties for -the expression printed by IDL." - :group 'idlwave-shell-highlighting-and-faces - :type 'symbol) - -(defcustom idlwave-shell-output-face 'secondary-selection - "The face for `idlwave-shell-output-overlay'. -Allows you to choose the font, color and other properties for -the expression output by IDL." - :group 'idlwave-shell-highlighting-and-faces - :type 'symbol) - -;;; End user customization variables - -;;; External variables -(defvar comint-last-input-start) -(defvar comint-last-input-end) - -;; Other variables -(defvar idlwave-shell-temp-pro-file nil - "Absolute pathname for temporary IDL file for compiling regions.") - -(defvar idlwave-shell-temp-rinfo-save-file nil - "Absolute pathname for temporary IDL file save file for routine_info. -This is used to speed up the reloading of the routine info procedure -before use by the shell.") - -(defun idlwave-shell-temp-file (type) - "Return a temp file, creating it if necessary. - -TYPE is either `pro' or `rinfo', and `idlwave-shell-temp-pro-file' or -`idlwave-shell-temp-rinfo-save-file' is set (respectively)." - (cond - ((eq type 'rinfo) - (or idlwave-shell-temp-rinfo-save-file - (setq idlwave-shell-temp-rinfo-save-file - (make-temp-file idlwave-shell-temp-pro-prefix)))) - ((eq type 'pro) - (or idlwave-shell-temp-pro-file - (setq idlwave-shell-temp-pro-file - (make-temp-file idlwave-shell-temp-pro-prefix)))) - (t (error "Wrong argument (idlwave-shell-temp-file): %s" - (symbol-name type))))) - - -(define-obsolete-function-alias 'idlwave-shell-make-temp-file - #'make-temp-file "27.1") - -(defvar idlwave-shell-dirstack-query "cd,current=___cur & print,___cur" - "Command used by `idlwave-shell-resync-dirs' to query IDL for -the directory stack.") - -(defvar idlwave-shell-path-query "print,'PATH:<'+transpose(expand_path(!PATH,/ARRAY))+'>' & print,'SYSDIR:<'+!dir+'>'" - - "The command which gets !PATH and !DIR info from the shell.") - -(defvar idlwave-shell-mode-line-info nil - "Additional info displayed in the mode line.") - -(defvar idlwave-shell-default-directory nil - "The default directory in the `idlwave-shell' buffer, of outside use.") - -(defvar idlwave-shell-last-save-and-action-file nil - "The last file which was compiled with `idlwave-shell-save-and-...'.") - -(defvar idlwave-shell-stop-line-overlay nil - "The overlay for where IDL is currently stopped.") -(defvar idlwave-shell-is-stopped nil) -(defvar idlwave-shell-expression-overlay nil - "The overlay for the examined expression.") -(defvar idlwave-shell-output-overlay nil - "The overlay for the last IDL output.") - -;; If these were already overlays, delete them. This probably means that we -;; are reloading this file. -(if (overlayp idlwave-shell-stop-line-overlay) - (delete-overlay idlwave-shell-stop-line-overlay)) -(if (overlayp idlwave-shell-expression-overlay) - (delete-overlay idlwave-shell-expression-overlay)) -(if (overlayp idlwave-shell-output-overlay) - (delete-overlay idlwave-shell-output-overlay)) - -;; Set to nil initially -(setq idlwave-shell-stop-line-overlay nil - idlwave-shell-expression-overlay nil - idlwave-shell-output-overlay nil) - -;; Define the shell stop overlay. When left nil, the arrow will be used. -(cond - ((or (null idlwave-shell-mark-stop-line) - (eq idlwave-shell-mark-stop-line 'arrow)) - ;; Leave the overlay nil - nil) - - ((eq idlwave-shell-mark-stop-line 'face) - ;; Try to use a face. If not possible, arrow will be used anyway - ;; So who can display faces? - (when window-system - (progn - (setq idlwave-shell-stop-line-overlay (make-overlay 1 1)) - (overlay-put idlwave-shell-stop-line-overlay - 'face idlwave-shell-stop-line-face)))) - - (t - ;; IDLWAVE may decide. Will use a face on window systems, arrow elsewhere - (if window-system - (progn - (setq idlwave-shell-stop-line-overlay (make-overlay 1 1)) - (overlay-put idlwave-shell-stop-line-overlay - 'face idlwave-shell-stop-line-face))))) - -;; Now the expression and output overlays -(setq idlwave-shell-expression-overlay (make-overlay 1 1)) -(overlay-put idlwave-shell-expression-overlay - 'face idlwave-shell-expression-face) -(overlay-put idlwave-shell-expression-overlay - 'priority 1) -(setq idlwave-shell-output-overlay (make-overlay 1 1)) -(overlay-put idlwave-shell-output-overlay - 'face idlwave-shell-output-face) - -(copy-face idlwave-shell-stop-line-face - 'idlwave-shell-pending-stop) -(copy-face idlwave-shell-electric-stop-line-face - 'idlwave-shell-pending-electric-stop) -(set-face-background 'idlwave-shell-pending-stop "gray70") -(set-face-background 'idlwave-shell-pending-electric-stop "gray70") - - - -(defvar idlwave-shell-bp-query "help,/breakpoints" - "Command to obtain list of breakpoints.") - -(defvar idlwave-shell-command-output nil - "String for accumulating current command output.") - -(defvar idlwave-shell-post-command-hook nil - "Lisp list expression or function to run when an IDL command is finished. -The current command is finished when the IDL prompt is displayed. -This is evaluated if it is a list or called with funcall.") - -(defvar idlwave-shell-sentinel-hook nil - "Hook run when the IDL process exits.") - -(defvar idlwave-shell-hide-output nil - "If non-nil the process output is not inserted into the output buffer.") - -(defvar idlwave-shell-show-if-error nil - "If non-nil the process output is inserted into the output buffer if -it contains an error message, even if hide-output is non-nil.") - -(defvar idlwave-shell-accumulation nil - "Accumulate last line of output.") - -(defvar idlwave-shell-command-line-to-execute nil) -(defvar idlwave-shell-cleanup-hook nil - "List of functions to do cleanup when the shell exits.") - -(defvar idlwave-shell-pending-commands nil - "List of commands to be sent to IDL. -Each element of the list is list of \(CMD PCMD HIDE), where CMD is a -string to be sent to IDL and PCMD is a post-command to be placed on -`idlwave-shell-post-command-hook'. If HIDE is non-nil, hide the output -from command CMD. PCMD and HIDE are optional.") - -(defun idlwave-shell-buffer () - "Name of buffer associated with IDL process. -The name of the buffer is made by surrounding `idlwave-shell-process-name' -with `*'s." - (concat "*" idlwave-shell-process-name "*")) - -(defvar idlwave-shell-ready nil - "If non-nil can send next command to IDL process.") - -;;; The following are the types of messages we attempt to catch to -;;; resync our idea of where IDL execution currently is. -;;; - -(defvar idlwave-shell-halt-frame nil - "The frame associated with halt/breakpoint messages.") - -(defvar idlwave-shell-step-frame nil - "The frame associated with step messages.") - -(defvar idlwave-shell-trace-frame nil - "The frame associated with trace messages.") - -(defconst idlwave-shell-halt-messages - '("^% Interrupted at:" - "^% Stepped to:" - "^% Skipped to:" - "^% Stop encountered:" - ) - "A list of regular expressions matching IDL messages. -These are the messages containing file and line information where -IDL is currently stopped.") - - -(defconst idlwave-shell-halt-messages-re - (mapconcat #'identity idlwave-shell-halt-messages "\\|") - "The regular expression computed from `idlwave-shell-halt-messages'.") - -(defconst idlwave-shell-trace-message-re - "^% At " ;; First line of a trace message - "A regular expression matching IDL trace messages. -These are the messages containing file and line information of a -current traceback.") - -(defconst idlwave-shell-step-messages - '("^% Stepped to:" - ) - "A list of regular expressions matching stepped execution messages. -These are IDL messages containing file and line information where -IDL has currently stepped.") - -(defvar idlwave-shell-break-message "^% Breakpoint at:" - "Regular expression matching an IDL breakpoint message line.") - -(defconst idlwave-shell-electric-debug-help - " ==> IDLWAVE Electric Debug Mode Help <== - - Break Point Setting and Clearing: - b Set breakpoint ([C-u b] for conditional, [C-n b] nth hit, etc.). - d Clear nearby breakpoint. - a Clear all breakpoints. - i Set breakpoint in routine named here. - j Set breakpoint at beginning of containing routine. - \\ Toggle breakpoint disable - ] Go to next breakpoint in file. - [ Go to previous breakpoint in file. - - Stepping, Continuing, and the Stack: - s or SPACE Step, into function calls. - n Step, over function calls. - k Skip one statement. - m Continue to end of function. - o Continue past end of function. - u Continue to end of block. - h Continue to line at cursor position. - r Continue execution to next breakpoint, if any. - + or = Show higher level in calling stack. - - or _ Show lower level in calling stack. - - Examining Expressions (with prefix for examining the region): - p Print expression near point or in region ([C-u p]). - ? Help on expression near point or in region ([C-u ?]). - x Examine expression near point or in region ([C-u x]) with - letter completion of the examine type. - e Prompt for an expression to print. - - Miscellaneous: - q Quit - end debugging session and return to the Shell's main level. - v Turn Electric Debugging Mode off (C-c C-d C-v to return). - t Print a calling-level traceback in the shell. - z Reset IDL. - C-? Show this help menu.") - -(defvar idlwave-shell-bp-alist) -;(defvar idlwave-shell-post-command-output) -(defvar idlwave-shell-sources-alist) -(defvar idlwave-shell-menu-def) -(defvar idlwave-shell-mode-menu) -(defvar idlwave-shell-initial-commands) -(defvar idlwave-shell-syntax-error) -(defvar idlwave-shell-other-error) -(defvar idlwave-shell-error-buffer) -(defvar idlwave-shell-error-last) -(defvar idlwave-shell-bp-buffer) -(defvar idlwave-shell-sources-query) -(defvar idlwave-shell-mode-map) -(defvar idlwave-shell-calling-stack-index) -(defvar idlwave-shell-only-prompt-pattern nil) -(defvar tool-bar-map) - -(define-derived-mode idlwave-shell-mode comint-mode "IDL-Shell" - "Major mode for interacting with an inferior IDL process. - -1. Shell Interaction - ----------------- - RET after the end of the process' output sends the text from the - end of process to the end of the current line. RET before end of - process output copies the current line (except for the prompt) to - the end of the buffer. - - Command history, searching of previous commands, command line - editing are available via the comint-mode key bindings, by default - mostly on the key \\`C-c'. Command history is also available with - the arrow keys UP and DOWN. - -2. Completion - ---------- - TAB and M-TAB do completion of IDL routines, classes and keywords - - similar to M-TAB in `idlwave-mode'. In executive commands and - strings, it completes file names. Abbreviations are also expanded - like in `idlwave-mode'. - -3. Routine Info - ------------ - \\[idlwave-routine-info] displays information about an IDL routine near point, - just like in `idlwave-mode'. The module used is the one at point or - the one whose argument list is being edited. - To update IDLWAVE's knowledge about compiled or edited modules, use - \\[idlwave-update-routine-info]. - \\[idlwave-find-module] find the source of a module. - \\[idlwave-resolve] tells IDL to compile an unresolved module. - \\[idlwave-context-help] shows the online help on the item at - point, if online help has been installed. - - -4. Debugging - --------- - A complete set of commands for compiling and debugging IDL programs - is available from the menu. Also keybindings starting with a - \\`C-c C-d' prefix are available for most commands in the *idl* buffer - and also in source buffers. The best place to learn about the - keybindings is again the menu. - - On Emacs versions where this is possible, a debugging toolbar is - installed. - - When IDL is halted in the middle of a procedure, the corresponding - line of that procedure file is displayed with an overlay in another - window. Breakpoints are also highlighted in the source. - - \\[idlwave-shell-resync-dirs] queries IDL in order to change Emacs current directory - to correspond to the IDL process current directory. - -5. Expression Examination - ---------------------- - - Expressions near point can be examined with print, - \\[idlwave-shell-print] or \\[idlwave-shell-mouse-print] with the - mouse, help, \\[idlwave-shell-help-expression] or - \\[idlwave-shell-mouse-help] with the mouse, or with a - configurable set of custom examine commands using - \\[idlwave-shell-examine-select]. The mouse examine commands can - also work by click and drag, to select an expression for - examination. - -6. Hooks - ----- - Turning on `idlwave-shell-mode' runs `comint-mode-hook' and - `idlwave-shell-mode-hook' (in that order). - -7. Documentation and Customization - ------------------------------- - Info documentation for this package is available. Use \\[idlwave-info] - to display (complain to your sysadmin if that does not work). - For PostScript and HTML versions of the documentation, see IDLWAVE's - website at URL `https://github.com/jdtsmith/idlwave'. - IDLWAVE has customize support - see the group `idlwave'. - -8. Keybindings - ----------- -\\{idlwave-shell-mode-map}" - :abbrev-table idlwave-mode-abbrev-table - (idlwave-setup) ; Make sure config files and paths, etc. are available. - (unless (file-name-absolute-p idlwave-shell-command-history-file) - (setq idlwave-shell-command-history-file - (expand-file-name idlwave-shell-command-history-file - idlwave-config-directory))) - - (setq comint-prompt-regexp idlwave-shell-prompt-pattern) - (setq comint-process-echoes t) - - ;; Can not use history expansion because "!" is used for system variables. - (setq comint-input-autoexpand nil) - ;; (setq comint-input-ring-size 64) - - (set (make-local-variable 'completion-ignore-case) t) - (set (make-local-variable 'comint-completion-addsuffix) '("/" . "")) - (setq comint-input-ignoredups t) - (setq idlwave-shell-mode-line-info nil) - (setq mode-line-format - '("" - mode-line-modified - mode-line-buffer-identification - " " - global-mode-string - " %[(" - mode-name - mode-line-process - minor-mode-alist - "%n" - ")%]-" - idlwave-shell-mode-line-info - "---" - (line-number-mode "L%l--") - (column-number-mode "C%c--") - (-3 . "%p") - "-%-")) - ;; (make-local-variable 'idlwave-shell-bp-alist) - (setq idlwave-shell-halt-frame nil - idlwave-shell-trace-frame nil - idlwave-shell-command-output nil - idlwave-shell-step-frame nil) - (idlwave-shell-display-line nil) - (setq idlwave-shell-calling-stack-index 0) - (setq idlwave-shell-only-prompt-pattern - (concat "\\`[ \t\n]*" - (substring idlwave-shell-prompt-pattern 1) - "[ \t\n]*\\'")) - - (when idlwave-shell-query-for-class - (add-hook 'idlwave-determine-class-functions - #'idlwave-shell-get-object-class nil t) - (setq idlwave-store-inquired-class t)) - - ;; Make sure comint-last-input-end does not go to beginning of - ;; buffer (in case there were other processes already in this buffer). - (set-marker comint-last-input-end (point)) - (setq idlwave-idlwave_routine_info-compiled nil) - (setq idlwave-shell-ready nil) - (setq idlwave-shell-bp-alist nil) - (idlwave-shell-update-bp-overlays) ; Throw away old overlays - (setq idlwave-shell-post-command-hook nil ;clean up any old stuff - idlwave-shell-sources-alist nil) - (setq idlwave-shell-default-directory default-directory) - (setq idlwave-shell-hide-output nil) - - (add-hook 'kill-buffer-hook #'idlwave-shell-kill-shell-buffer-confirm - nil 'local) - (add-hook 'kill-buffer-hook #'idlwave-shell-delete-temp-files nil 'local) - (add-hook 'kill-emacs-hook #'idlwave-shell-delete-temp-files) - - ;; Set the optional comint variables - (when idlwave-shell-comint-settings - (let ((list idlwave-shell-comint-settings) entry) - (while (setq entry (pop list)) - (set (make-local-variable (car entry)) (cdr entry))))) - - - (unless (memq #'comint-carriage-motion - (default-value 'comint-output-filter-functions)) - ;; Strip those pesky ctrl-m's. - (add-hook 'comint-output-filter-functions - (lambda (string) - (when (string-search "\r" string) - (let ((pmark (process-mark (get-buffer-process - (current-buffer))))) - (save-excursion - ;; bare CR -> delete preceding line - (goto-char comint-last-output-start) - (while (search-forward "\r" pmark t) - (delete-region (point) (line-beginning-position))))))) - 'append 'local) - (add-hook 'comint-output-filter-functions #'comint-strip-ctrl-m nil 'local)) - - ;; Python-mode, bundled with many Emacs installs, quite cavalierly - ;; adds this function to the global default hook. It interferes - ;; with overlay-arrows. - ;; FIXME: We should fix this interference rather than globally turn it off. - (when (fboundp 'py-pdbtrack-track-stack-file) - (remove-hook 'comint-output-filter-functions - #'py-pdbtrack-track-stack-file)) - - ;; IDLWAVE syntax, and turn on abbreviations - (set (make-local-variable 'comment-start) ";") - (setq abbrev-mode t) - - (add-hook 'post-command-hook #'idlwave-command-hook nil t) - - ;; Read the command history? - (when (and idlwave-shell-save-command-history - (stringp idlwave-shell-command-history-file)) - (set (make-local-variable 'comint-input-ring-file-name) - idlwave-shell-command-history-file) - (if (file-regular-p idlwave-shell-command-history-file) - (comint-read-input-ring))) - - ;; Turn off the non-debug toolbar buttons (open,save,etc.) - (set (make-local-variable 'tool-bar-map) nil) - - (idlwave-shell-send-command idlwave-shell-initial-commands nil 'hide) - ;; Turn off IDL's ^d interpreting, and define a system - ;; variable which knows the version of IDLWAVE - (idlwave-shell-send-command - (format "defsysv,'!idlwave_version','%s',1" idlwave-mode-version) - nil 'hide) - ;; Read the paths, and save if they changed - (idlwave-shell-send-command idlwave-shell-path-query - 'idlwave-shell-get-path-info - 'hide)) - -(defvar idlwave-system-directory) -(defun idlwave-shell-get-path-info (&optional no-write) - "Get the path lists, writing to file unless NO-WRITE is set." - (let* ((rpl (idlwave-shell-path-filter)) - (sysdir (car rpl)) - (dirs (cdr rpl)) - (old-path-alist idlwave-path-alist) - (old-sys-dir idlwave-system-directory) - path-changed sysdir-changed) - (when sysdir - (setq idlwave-system-directory sysdir) - (if (setq sysdir-changed - (not (string= idlwave-system-directory old-sys-dir))) - (put 'idlwave-system-directory 'from-shell t))) - ;; Preserve any existing flags - (setq idlwave-path-alist - (mapcar (lambda (x) - (let ((old-entry (assoc x old-path-alist))) - (if old-entry - (cons x (cdr old-entry)) - (list x)))) - dirs)) - (if (setq path-changed (not (equal idlwave-path-alist old-path-alist))) - (put 'idlwave-path-alist 'from-shell t)) - (if idlwave-path-alist - (if (and (not no-write) - idlwave-auto-write-paths - (or sysdir-changed path-changed) - (not idlwave-library-path)) - (idlwave-write-paths)) - ;; Fall back - (setq idlwave-path-alist old-path-alist)))) - -(if (not (fboundp 'idl-shell)) - (defalias 'idl-shell #'idlwave-shell)) - -(defvar idlwave-shell-idl-wframe nil - "Frame for displaying the IDL shell window.") -(defvar idlwave-shell-display-wframe nil - "Frame for displaying the IDL source files.") - -(defvar idlwave-shell-calling-stack-index 0) -(defvar idlwave-shell-calling-stack-routine nil) - -(defun idlwave-shell-source-frame () - "Return the frame to be used for source display." - (if idlwave-shell-use-dedicated-frame - ;; We want separate frames for source and shell - (if (frame-live-p idlwave-shell-display-wframe) - ;; The frame exists, so we use it. - idlwave-shell-display-wframe - ;; The frame does not exist. We use the current frame. - ;; However, if the current is the shell frame, we make a new frame, - ;; or recycle the first existing visible frame - (setq idlwave-shell-display-wframe - (if (eq (selected-frame) idlwave-shell-idl-wframe) - (or - (let ((flist (visible-frame-list))) - (catch 'exit - (while flist - (if (not (eq (car flist) - idlwave-shell-idl-wframe)) - (throw 'exit (car flist)) - (setq flist (cdr flist)))))) - (make-frame)) - (selected-frame)))))) - -(defun idlwave-shell-shell-frame () - "Return the frame to be used for the shell buffer." - (if idlwave-shell-use-dedicated-frame - ;; We want a dedicated frame - (if (frame-live-p idlwave-shell-idl-wframe) - ;; It does exist, so we use it. - idlwave-shell-idl-wframe - ;; It does not exist. Check if we have a source frame. - (if (not (frame-live-p idlwave-shell-display-wframe)) - ;; We do not have a source frame, so we use this one. - (setq idlwave-shell-display-wframe (selected-frame))) - ;; Return a new frame - (setq idlwave-shell-idl-wframe - (make-frame idlwave-shell-frame-parameters))))) - -;;;###autoload -(defun idlwave-shell (&optional arg) - "Run an inferior IDL, with I/O through buffer `(idlwave-shell-buffer)'. -If buffer exists but shell process is not running, start new IDL. -If buffer exists and shell process is running, just switch to the buffer. - -When called with a prefix ARG, or when `idlwave-shell-use-dedicated-frame' -is non-nil, the shell buffer and the source buffers will be in -separate frames. - -The command to run comes from variable `idlwave-shell-explicit-file-name', -with options taken from `idlwave-shell-command-line-options'. - -The buffer is put in `idlwave-shell-mode', providing commands for sending -input and controlling the IDL job. See help on `idlwave-shell-mode'. -See also the variable `idlwave-shell-prompt-pattern'. - -\(Type \\[describe-mode] in the shell buffer for a list of commands.)" - (interactive "P") - (if (eq arg 'quick) - (progn - (let ((idlwave-shell-use-dedicated-frame nil)) - (idlwave-shell nil) - (delete-other-windows)) - (and idlwave-shell-use-dedicated-frame - (setq idlwave-shell-idl-wframe (selected-frame))) - (add-hook 'idlwave-shell-sentinel-hook - #'save-buffers-kill-emacs t)) - - ;; A non-nil arg means, we want a dedicated frame. This will last - ;; for the current editing session. - (if arg (setq idlwave-shell-use-dedicated-frame t)) - (if (equal arg '(16)) (setq idlwave-shell-use-dedicated-frame nil)) - - ;; Check if the process still exists. If not, create it. - (unless (comint-check-proc (idlwave-shell-buffer)) - (let* ((prg (or idlwave-shell-explicit-file-name "idl")) - (buf (apply #'make-comint - idlwave-shell-process-name prg nil - (if (stringp idlwave-shell-command-line-options) - (idlwave-split-string - idlwave-shell-command-line-options) - idlwave-shell-command-line-options))) - (process (get-buffer-process buf))) - (setq idlwave-idlwave_routine_info-compiled nil) - (set-process-filter process #'idlwave-shell-filter) - (set-process-sentinel process #'idlwave-shell-sentinel) - (set-buffer buf) - (idlwave-shell-mode))) - (let ((window (idlwave-display-buffer (idlwave-shell-buffer) nil - (idlwave-shell-shell-frame))) - (current-window (selected-window))) - (select-window window) - (goto-char (point-max)) - (if idlwave-shell-use-dedicated-window - (set-window-dedicated-p window t)) - (select-window current-window) - (if idlwave-shell-ready - (raise-frame (window-frame window))) - (if (eq (selected-frame) (window-frame window)) - (select-window window)))) - ;; Save the paths at the end, if they are from the Shell and new. - (add-hook 'idlwave-shell-sentinel-hook - (lambda () - (if (and - idlwave-auto-write-paths - idlwave-path-alist - (not idlwave-library-path) - (get 'idlwave-path-alist 'from-shell)) - (idlwave-write-paths))))) - -(defun idlwave-shell-recenter-shell-window (&optional arg) - "Run `idlwave-shell', but make sure the current window stays selected." - (interactive "P") - (let ((window (selected-window))) - (idlwave-shell arg) - (select-window window))) - -(defun idlwave-shell-hide-p (type &optional list) - "Whether to hide this type of command. -Return either nil or `hide'." - (let ((list (or list idlwave-shell-show-commands))) - (if (listp list) - (if (not (memq type list)) 'hide)))) - -(defun idlwave-shell-add-or-remove-show (type) - "Add or remove a show command from the list." - (if (listp idlwave-shell-show-commands) - (setq idlwave-shell-show-commands - (if (memq type idlwave-shell-show-commands) - (delq type idlwave-shell-show-commands) - (add-to-list'idlwave-shell-show-commands type))) - (setq idlwave-shell-show-commands (list type)))) - - -(defun idlwave-shell-send-command (&optional cmd pcmd hide preempt - show-if-error) - "Send a command to IDL process. - -\(CMD PCMD HIDE) are placed at the end of `idlwave-shell-pending-commands'. -If IDL is ready the first command in `idlwave-shell-pending-commands', -CMD, is sent to the IDL process. - -If optional second argument PCMD is non-nil it will be placed on -`idlwave-shell-post-command-hook' when CMD is executed. - -If the optional third argument HIDE is non-nil, then hide output from -CMD, unless it is the symbol `mostly', in which case only output -beginning with \"%\" is hidden, and all other output (i.e., the -results of a PRINT command), is shown. This helps with, e.g., -stepping through code with output. - -If optional fourth argument PREEMPT is non-nil CMD is put at front of -`idlwave-shell-pending-commands'. If PREEMPT is `wait', wait for all -output to complete and the next prompt to arrive before returning -\(useful if you need an answer now). IDL is considered ready if the -prompt is present and if `idlwave-shell-ready' is non-nil. - -If SHOW-IF-ERROR is non-nil, show the output if it contains an error -message, independent of what HIDE is set to." - -; (setq hide nil) ; FIXME: turn this on for debugging only -; (if (null cmd) -; (progn -; (message "SENDING Pending commands: %s" -; (prin1-to-string idlwave-shell-pending-commands))) -; (message "SENDING %s|||%s" cmd pcmd)) - (if (and (symbolp idlwave-shell-show-commands) - (eq idlwave-shell-show-commands 'everything)) - (setq hide nil)) - (let ((save-buffer (current-buffer)) - buf proc) - ;; Get or make the buffer and its process - (if (or (not (setq buf (get-buffer (idlwave-shell-buffer)))) - (not (setq proc (get-buffer-process buf)))) - (if (not idlwave-shell-automatic-start) - (error "%s" - (substitute-command-keys - "You need to first start an IDL shell with \\[idlwave-shell]")) - (idlwave-shell-recenter-shell-window) - (setq buf (get-buffer (idlwave-shell-buffer))) - (if (or (not (setq buf (get-buffer (idlwave-shell-buffer)))) - (not (setq proc (get-buffer-process buf)))) - ;; Still nothing - (error "Problem with autostarting IDL shell")))) - (when (or cmd idlwave-shell-pending-commands) - (set-buffer buf) - ;; To make this easy, always push CMD onto pending commands - (if cmd - (setq idlwave-shell-pending-commands - (if preempt - ;; Put at front. - (append (list (list cmd pcmd hide show-if-error)) - idlwave-shell-pending-commands) - ;; Put at end. - (append idlwave-shell-pending-commands - (list (list cmd pcmd hide show-if-error)))))) - ;; Check if IDL ready - (let ((save-point (point-marker))) - (goto-char (process-mark proc)) - (if (and idlwave-shell-ready - ;; Check for IDL prompt - (prog2 - (forward-line 0) - ;; (beginning-of-line) ; Changed for Emacs 21 - (looking-at idlwave-shell-prompt-pattern) - (goto-char (process-mark proc)))) - ;; IDL ready for command, execute it - (let* ((lcmd (car idlwave-shell-pending-commands)) - (cmd (car lcmd)) - (pcmd (nth 1 lcmd)) - (hide (nth 2 lcmd)) - (show-if-error (nth 3 lcmd))) - ;; If this is an executive command, reset the stack pointer - (if (eq (string-to-char cmd) ?.) - (setq idlwave-shell-calling-stack-index 0)) - ;; Set post-command - (setq idlwave-shell-post-command-hook pcmd) - ;; Output hiding - (setq idlwave-shell-hide-output hide) - ;;Showing errors - (setq idlwave-shell-show-if-error show-if-error) - ;; Pop command - (setq idlwave-shell-pending-commands - (cdr idlwave-shell-pending-commands)) - ;; Send command for execution - (set-marker comint-last-input-start (point)) - (set-marker comint-last-input-end (point)) - (comint-simple-send proc cmd) - (setq idlwave-shell-ready nil) - (if (equal preempt 'wait) ; Get all the output at once - (while (not idlwave-shell-ready) - (when (not (accept-process-output proc 6)) ; long wait - (setq idlwave-shell-pending-commands nil) - (error "Process timed out")))))) - (goto-char save-point)) - (set-buffer save-buffer)))) - -(defun idlwave-shell-send-char (c &optional error) - "Send one character to the shell, without a newline." - (interactive "cChar to send to IDL: \np") - (let ((errf (if error 'error 'message)) - buf proc) - (if (or (not (setq buf (get-buffer (idlwave-shell-buffer)))) - (not (setq proc (get-buffer-process buf)))) - (funcall errf "Shell is not running")) - (if (equal c ?\C-g) - (funcall errf "Abort") - (comint-send-string proc (char-to-string c))))) - -(defvar idlwave-shell-char-mode-active) -(defun idlwave-shell-input-mode-magic (string) - "Check STRING for magic words and toggle character input mode. -See also the variable `idlwave-shell-input-mode-spells'." - (cond - ((string-match (car idlwave-shell-input-mode-spells) string) - (call-interactively 'idlwave-shell-send-char)) - ((and (boundp 'idlwave-shell-char-mode-active) - (string-match (nth 2 idlwave-shell-input-mode-spells) string)) - (setq idlwave-shell-char-mode-active 'exit)) - ((string-match (nth 1 idlwave-shell-input-mode-spells) string) - ;; Set a timer which will soon start the character loop - (run-at-time 0.5 nil #'idlwave-shell-char-mode-loop 'no-error)))) - -(defvar keyboard-quit) -(defun idlwave-shell-char-mode-loop (&optional no-error) - "Enter a loop which accepts single characters and sends them to IDL. -Characters are sent one by one, without newlines. The loop is blocking -and intercepts all input events to Emacs. You can use this command -to interact with the IDL command GET_KBRD. -The loop can be aborted by typing \\[keyboard-quit]. The loop also exits automatically -when the IDL prompt gets displayed again after the current IDL command." - (interactive) - - ;; First check if there is a shell waiting for input - (let ((idlwave-shell-char-mode-active t) - (errf (if no-error 'message 'error)) - buf proc c) - (if (or (not (setq buf (get-buffer (idlwave-shell-buffer)))) - (not (setq proc (get-buffer-process buf)))) - (funcall errf "Shell is not running")) - (if idlwave-shell-ready - (funcall errf "No IDL program seems to be waiting for input")) - - ;; OK, start the loop - (message (substitute-command-keys - "Character mode on: Sending single chars (\\[keyboard-quit] to exit)")) - (message - (catch 'exit - (while t - ;; Wait for input - ;; FIXME: Is it too dangerous to inhibit quit here? - (let ((inhibit-quit t)) - ;; We wait and check frequently if we should abort - (while (sit-for 0.3) - (and idlwave-shell-ready - (throw 'exit "Character mode off (prompt displayed)")) - (and (eq idlwave-shell-char-mode-active 'exit) - (throw 'exit "Character mode off (closing spell incantation)"))) - ;; Interpret input as a character - ignore non-char input - (condition-case nil - (setq c (read-char)) - (error (ding) (throw 'exit "Character mode off"))) - (cond - ((null c) ; Non-char event: ignore - (ding)) - ((equal c ?\C-g) ; Abort the loop - (setq keyboard-quit nil) - (ding) - (throw 'exit "Character mode off (keyboard quit)")) - (t ; Send the character and continue the loop - (comint-send-string proc (char-to-string c)))) - (and (eq idlwave-shell-char-mode-active 'exit) - (throw 'exit "Single char loop exited")))))))) - -(defun idlwave-shell-move-or-history (up &optional arg) - "When in last line of process buffer, do `comint-previous-input'. -Otherwise just move the line. Move down unless UP is non-nil." - (let* ((proc-pos (marker-position - (process-mark (get-buffer-process (current-buffer))))) - (arg (or arg 1)) - (arg (if up arg (- arg)))) - (if (eq t idlwave-shell-arrows-do-history) (goto-char proc-pos)) - (if (and idlwave-shell-arrows-do-history - (>= (1+ (line-end-position)) proc-pos)) - (comint-previous-input arg) - (forward-line (- arg))))) - -(defun idlwave-shell-up-or-history (&optional arg) - "When in last line of process buffer, move to previous input. -Otherwise just go up one line." - (interactive "p") - (idlwave-shell-move-or-history t arg)) - -(defun idlwave-shell-down-or-history (&optional arg) - "When in last line of process buffer, move to next input. -Otherwise just go down one line." - (interactive "p") - (idlwave-shell-move-or-history nil arg)) - -(define-obsolete-function-alias 'idlwave-shell-comint-filter - #'comint-output-filter "25.1") - -(defun idlwave-shell-is-running () - "Return t if the shell process is running." - (eq (process-status idlwave-shell-process-name) 'run)) - -(defun idlwave-shell-filter-hidden-output (output) - "Filter hidden output, leaving the good stuff. - -Remove everything to the first newline, and all lines with % in front -of them, with optional follow-on lines starting with two spaces. This -works well enough, since any print output typically arrives before -error messages, etc." - (setq output (substring output (string-search "\n" output))) - (while (string-match "\\(\n\\|\\`\\)%.*\\(\n .*\\)*" output) - (setq output (replace-match "" nil t output))) - (unless - (string-match idlwave-shell-only-prompt-pattern output) - output)) - -(defvar idlwave-shell-hidden-output-buffer " *idlwave-shell-hidden-output*" - "Buffer containing hidden output from IDL commands.") -(defvar idlwave-shell-current-state nil) - -(defun idlwave-shell-filter (proc string) - "Watch for IDL prompt and filter incoming text. -When the IDL prompt is received executes `idlwave-shell-post-command-hook' -and then calls `idlwave-shell-send-command' for any pending commands." - ;; We no longer do the cleanup here - this is done by the process sentinel - (if (eq (process-status idlwave-shell-process-name) 'run) - ;; OK, process is still running, so we can use it. - (let ((data (match-data)) p full-output) - (unwind-protect - (progn - ;; Ring the bell if necessary - (while (setq p (string-search "\C-G" string)) - (ding) - (aset string p ?\C-j )) - (if idlwave-shell-hide-output - (save-excursion - (while (setq p (string-search "\C-M" string)) - (aset string p ?\ )) - (set-buffer - (get-buffer-create idlwave-shell-hidden-output-buffer)) - (goto-char (point-max)) - (insert string)) - (comint-output-filter proc string)) - ;; Watch for magic - need to accumulate the current line - ;; since it may not be sent all at once. - (if (string-search "\n" string) - (progn - (if idlwave-shell-use-input-mode-magic - (idlwave-shell-input-mode-magic - (concat idlwave-shell-accumulation string))) - (setq idlwave-shell-accumulation - (substring string - (string-match "[^\n\r]*\\'" string)))) - (setq idlwave-shell-accumulation - (concat idlwave-shell-accumulation string))) - - - ;; ;; Test/Debug code - ;;(with-current-buffer - ;; (get-buffer-create "*idlwave-shell-output*") - ;; (goto-char (point-max)) - ;; (insert "\nReceived STRING\n===>\n" string "\n<====\n")) - - ;; Check for prompt in current accumulating output - (when (setq idlwave-shell-ready - (string-match idlwave-shell-prompt-pattern - idlwave-shell-accumulation)) - ;; Gather the command output - (if idlwave-shell-hide-output - (with-current-buffer idlwave-shell-hidden-output-buffer - (setq full-output (buffer-string)) - (goto-char (point-max)) - (re-search-backward idlwave-shell-prompt-pattern nil t) - (goto-char (match-end 0)) - (setq idlwave-shell-command-output - (buffer-substring-no-properties - (point-min) (point))) - (delete-region (point-min) (point))) - (setq idlwave-shell-command-output - (with-current-buffer (process-buffer proc) - (buffer-substring-no-properties - (save-excursion - (goto-char (process-mark proc)) - (forward-line 0) ; Emacs 21 (beginning-of-line nil) - (point)) - comint-last-input-end)))) - - ;; Scan for state and do post commands - bracket - ;; them with idlwave-shell-ready=nil since they may - ;; call idlwave-shell-send-command themselves. - (let ((idlwave-shell-ready nil)) - (idlwave-shell-scan-for-state) - ;; Show the output in the shell if it contains an error - (if idlwave-shell-hide-output - (if (and idlwave-shell-show-if-error - (eq idlwave-shell-current-state 'error)) - (comint-output-filter proc full-output) - ;; If it's only *mostly* hidden, filter % lines, - ;; and show anything that remains - (if (eq idlwave-shell-hide-output 'mostly) - (let ((filtered - (idlwave-shell-filter-hidden-output - full-output))) - (if filtered - (comint-output-filter - proc filtered)))))) - - ;; Call the post-command hook - (if (functionp idlwave-shell-post-command-hook) - ;;(message "Calling command function") - (funcall idlwave-shell-post-command-hook) - ;;(message "Calling list") - ;;(prin1 idlwave-shell-post-command-hook) - (eval idlwave-shell-post-command-hook t)) - - ;; Reset to default state for next command. - ;; Also we do not want to find this prompt again. - (setq idlwave-shell-accumulation nil - idlwave-shell-command-output nil - idlwave-shell-post-command-hook nil - idlwave-shell-hide-output nil - idlwave-shell-show-if-error nil)) - ;; Done with post command. Do pending command if - ;; any. - (idlwave-shell-send-command))) - (store-match-data data))))) - -(defun idlwave-shell-sentinel (process event) - "The sentinel function for the IDLWAVE shell process." - (let* ((buf (idlwave-shell-buffer)) - (win (get-buffer-window buf))) - (when (get-buffer buf) - (with-current-buffer (idlwave-shell-buffer) - (goto-char (point-max)) - (insert (format "\n\n Process %s %s" process event)) - (if (and idlwave-shell-save-command-history - (stringp idlwave-shell-command-history-file)) - (condition-case nil - (comint-write-input-ring) - (error nil))))) - - (when (and (> (length (frame-list)) 1) - (frame-live-p idlwave-shell-idl-wframe)) - (delete-frame idlwave-shell-idl-wframe) - (setq idlwave-shell-idl-wframe nil - idlwave-shell-display-wframe nil)) - (when (and (window-live-p win) - (not (one-window-p 'nomini))) - (delete-window win)) - (idlwave-shell-cleanup) - ;; Run the hook, if possible in the shell buffer. - (if (get-buffer buf) - (with-current-buffer buf - (run-hooks 'idlwave-shell-sentinel-hook)) - (run-hooks 'idlwave-shell-sentinel-hook)))) - -(defvar idlwave-shell-error-buffer " *idlwave-shell-errors*" - "Buffer containing syntax errors from IDL compilations.") - -;; FIXME: the following two variables do not currently allow line breaks -;; in module and file names. I am not sure if it will be necessary to -;; change this. Currently it seems to work the way it is. -(defvar idlwave-shell-syntax-error - "^% Syntax error.\\s-*\n\\s-*At:\\s-*\\(.*\\),\\s-*Line\\s-*\\(.*\\)" - "A regular expression to match an IDL syntax error. -The first pair matches the file name, the second pair matches the line -number.") - -(defvar idlwave-shell-other-error - "^% .*\n\\s-*At:\\s-*\\(.*\\),\\s-*Line\\s-*\\(.*\\)" - "A regular expression to match any IDL error.") - -(defvar idlwave-shell-halting-error - "^% .*\n\\([^%].*\n\\)*% Execution halted at:\\(\\s-*\\S-+\\s-*[0-9]+.*\\)\n" - "A regular expression to match errors which halt execution.") - -(defvar idlwave-shell-cant-continue-error - "^% Can't continue from this point.\n" - "A regular expression to match errors stepping errors.") - -(defvar idlwave-shell-file-line-message - (concat - "\\(" ; program name group (1) - "\\$MAIN\\$\\|" ; main level routine - "\\<[a-zA-Z][a-zA-Z0-9_$:]*" ; start with a letter followed by [..] - "\\([ \t]*\n[ \t]*[a-zA-Z0-9_$:]+\\)*"; continuation lines program name (2) - "\\)" ; end program name group (1) - "[ \t\n]+" ; white space - "\\(" ; line number group (3) - "[0-9]+" ; the line number (the fix point) - "\\([ \t]*\n[ \t]*[0-9]+\\)*" ; continuation lines number (4) - "\\)" ; end line number group (3) - "[ \t\n]+" ; white space - "\\(" ; file name group (5) - "[^ \t\n]+" ; file names can contain any non-white - "\\([ \t]*\n[ \t]*[^ \t\n]+\\)*" ; continuation lines file name (6) - "\\)" ; end line number group (5) - ) - "A regular expression to parse out the file name and line number. -The 1st group should match the subroutine name. -The 3rd group is the line number. -The 5th group is the file name. -All parts may contain linebreaks surrounded by spaces. This is important -in IDL5 which inserts random linebreaks in long module and file names.") - -(defvar idlwave-shell-electric-debug-mode) ; defined by easy-mmode - -(defun idlwave-shell-scan-for-state () - "Scan for state info. -Looks for messages in output from last IDL command indicating where -IDL has stopped. The types of messages we are interested in are -execution halted, stepped, breakpoint, interrupted at and trace -messages. For breakpoint messages process any attached count or -command parameters. Update the stop line if a message is found. -The variable `idlwave-shell-current-state' is set to `error', `halt', -or `breakpoint', which describes the status, or nil for none of -the above." - (let (trace) - (cond - ;; Make sure we have output - ((not idlwave-shell-command-output)) - - ;; First Priority: Syntax and other errors - ((or - (string-match idlwave-shell-syntax-error - idlwave-shell-command-output) - (string-match idlwave-shell-other-error - idlwave-shell-command-output)) - (with-current-buffer - (get-buffer-create idlwave-shell-error-buffer) - (erase-buffer) - (insert idlwave-shell-command-output) - (goto-char (point-min)) - (setq idlwave-shell-error-last (point))) - (setq idlwave-shell-current-state 'error) - (idlwave-shell-goto-next-error)) - - ;; Second Priority: Halting errors - ((string-match idlwave-shell-halting-error - idlwave-shell-command-output) - ;; Grab the file and line state info. - (setq idlwave-shell-calling-stack-index 0) - (setq idlwave-shell-halt-frame - (idlwave-shell-parse-line - (substring idlwave-shell-command-output - (match-beginning 2))) - idlwave-shell-current-state 'error) - (idlwave-shell-display-line (idlwave-shell-pc-frame))) - - ;; Third Priority: Various types of innocuous HALT and - ;; TRACEBACK messages. - ((or (setq trace (string-match idlwave-shell-trace-message-re - idlwave-shell-command-output)) - (string-match idlwave-shell-halt-messages-re - idlwave-shell-command-output)) - ;; Grab the file and line state info. - (setq idlwave-shell-calling-stack-index 0) - (setq idlwave-shell-halt-frame - (idlwave-shell-parse-line - (substring idlwave-shell-command-output (match-end 0)))) - (setq idlwave-shell-current-state 'halt) - ;; Don't debug trace messages - (idlwave-shell-display-line - (idlwave-shell-pc-frame) nil - (if trace 'disable - (if idlwave-shell-electric-debug-mode 'force)))) - - ;; Fourth Priority: Breakpoints - ((string-match idlwave-shell-break-message - idlwave-shell-command-output) - (setq idlwave-shell-calling-stack-index 0) - (setq idlwave-shell-halt-frame - (idlwave-shell-parse-line - (substring idlwave-shell-command-output (match-end 0)))) - ;; We used to count hits on breakpoints - ;; this is no longer supported since IDL breakpoints - ;; have learned counting. - ;; Do breakpoint command processing - (let ((bp (assoc - (list - (nth 0 idlwave-shell-halt-frame) - (nth 1 idlwave-shell-halt-frame)) - idlwave-shell-bp-alist))) - ;(message "Scanning with %s" bp) - (if bp - (let ((cmd (idlwave-shell-bp-get bp 'cmd))) - (if cmd ;; Execute any breakpoint command - (if (functionp cmd) (funcall cmd) (eval cmd t)))) - ;; A breakpoint that we did not know about - perhaps it was - ;; set by the user... Let's update our list. - (idlwave-shell-bp-query))) - (setq idlwave-shell-current-state 'breakpoint) - (idlwave-shell-display-line (idlwave-shell-pc-frame))) - - ;; Last Priority: Can't Step errors - ((string-match idlwave-shell-cant-continue-error - idlwave-shell-command-output) - (setq idlwave-shell-current-state 'breakpoint)) - - ;; Otherwise, no particular state - (t (setq idlwave-shell-current-state nil))))) - - -(defun idlwave-shell-parse-line (string &optional skip-main) - "Parse IDL message for the subroutine, file name and line number." -;We need to work hard here to remove the stupid line breaks inserted by -;IDL5. These line breaks can be right in the middle of procedure -;or file names. -;It is very difficult to come up with a robust solution. This one seems -;to be pretty good though. -; -;Here is in what ways it improves over the previous solution: -; -;1. The procedure name can be split and will be restored. -;2. The number can be split. I have never seen this, but who knows. -;3. We do not require the `.pro' extension for files. -; -;This function can still break when the file name ends on an end line -;and the message line contains an additional line with garbage. Then -;the first part of that garbage will be added to the file name. -;However, the function checks the existence of the files with and -;without this last part - thus the function only breaks if file name -;plus garbage match an existing regular file. This is hopefully very -;unlikely. -; -;If optional arg SKIP-MAIN is non-nil, don't parse $MAIN$ routine stop -;statements. - - (let (number procedure file) - (when (and (not (if skip-main (string-match ":\\s-*\\$MAIN" string))) - (string-match idlwave-shell-file-line-message string)) - (setq procedure (match-string 1 string) - number (match-string 3 string) - file (match-string 5 string)) - - ;; Repair the strings - (setq procedure (idlwave-shell-repair-string procedure)) - (setq number (idlwave-shell-repair-string number)) - (setq file (idlwave-shell-repair-file-name file)) - - ;; If we have a file, return the frame list - (if file - (list (idlwave-shell-file-name file) - (string-to-number number) - procedure) - ;; No success finding a file - nil)))) - -(defun idlwave-shell-repair-string (string) - "Repair a string by taking out all linebreaks. This is destructive!" - (while (string-match "[ \t]*\n[ \t]*" string) - (setq string (replace-match "" t t string))) - string) - -(defun idlwave-shell-repair-file-name (file) - "Repair a file name string by taking out all linebreaks. -The last line of STRING may be garbage - we check which one makes a valid -file name." - (let ((file1 "") (file2 "") (start 0)) - ;; We scan no further than to the next "^%" line - (if (string-match "^%" file) - (setq file (substring file 0 (match-beginning 0)))) - ;; Take out the line breaks - (while (string-match "[ \t]*\n[ \t]*" file start) - (setq file1 (concat file1 (substring file start (match-beginning 0))) - start (match-end 0))) - (setq file2 (concat file1 (substring file start))) - (cond - ((file-regular-p file2) file2) - ((file-regular-p file1) file1) - ;; If we cannot verify the existence of the file, we return the shorter - ;; name. The idea behind this is that this may be a relative file name - ;; and our idea about the current working directory may be wrong. - ;; If it is a relative file name, it hopefully is short. - ((not (string= "" file1)) file1) - ((not (string= "" file2)) file2) - (t nil)))) - -(defun idlwave-shell-cleanup () - "Do necessary cleanup for a terminated IDL process." - (setq idlwave-shell-step-frame nil - idlwave-shell-halt-frame nil - idlwave-shell-pending-commands nil - idlwave-shell-command-line-to-execute nil - idlwave-shell-bp-alist nil - idlwave-shell-calling-stack-index 0 - idlwave-idlwave_routine_info-compiled nil) - (idlwave-shell-delete-temp-files) - (idlwave-shell-display-line nil) - (idlwave-shell-update-bp-overlays) ; kill old overlays - (idlwave-shell-kill-buffer idlwave-shell-hidden-output-buffer) - (idlwave-shell-kill-buffer idlwave-shell-bp-buffer) - (idlwave-shell-kill-buffer idlwave-shell-error-buffer) - ;; (idlwave-shell-kill-buffer (idlwave-shell-buffer)) - (and (get-buffer (idlwave-shell-buffer)) - (bury-buffer (get-buffer (idlwave-shell-buffer)))) - (run-hooks 'idlwave-shell-cleanup-hook)) - -(defun idlwave-shell-kill-buffer (buf) - "Kill buffer BUF if it exists." - (if (setq buf (get-buffer buf)) - (kill-buffer buf))) - -(defun idlwave-shell-kill-shell-buffer-confirm () - (when (idlwave-shell-is-running) - (ding) - (unless (y-or-n-p "IDL shell is running. Are you sure you want to kill the buffer? ") - (error "Abort")) - (message "Killing buffer *idl* and the associated process"))) - -(defun idlwave-shell-window (n) - "Issue a `window,N' command to IDL, with special window size. -The size is given by `idlwave-shell-graphics-window-size'." - (interactive "P") - (let ((n (if n (prefix-numeric-value n) 0))) - (idlwave-shell-send-command - (apply #'format "window,%d,xs=%d,ys=%d" - n idlwave-shell-graphics-window-size) - nil (idlwave-shell-hide-p 'misc) nil t))) - -(defun idlwave-shell-resync-dirs () - "Resync the buffer's idea of the current directory. -This command queries IDL with the command bound to -`idlwave-shell-dirstack-query', reads the output for the new -directory." - (interactive) - (idlwave-shell-send-command idlwave-shell-dirstack-query - 'idlwave-shell-filter-directory - 'hide 'wait)) - -(defun idlwave-shell-retall () - "Return from the entire calling stack. -Also get rid of widget events in the queue." - (interactive) - (save-selected-window - ;;if (widget_info(/MANAGED))[0] gt 0 then for i=0,n_elements(widget_info(/MANAGED))-1 do widget_control,(widget_info(/MANAGED))[i],/clear_events & - (idlwave-shell-send-command "retall" nil - (if (idlwave-shell-hide-p 'misc) 'mostly) - nil t) - (idlwave-shell-display-line nil))) - -(defun idlwave-shell-closeall () - "Close all open files." - (interactive) - (idlwave-shell-send-command "close,/all" nil - (idlwave-shell-hide-p 'misc) nil t)) - -(defun idlwave-shell-quit (&optional arg) - "Exit the IDL process after confirmation. -With prefix ARG, exit without confirmation." - (interactive "P") - (if (not (idlwave-shell-is-running)) - (error "Shell is not running") - (if (or arg (y-or-n-p "Exit the IDLWAVE Shell? ")) - (condition-case nil - (idlwave-shell-send-command "exit") - (error nil))))) - -(defun idlwave-shell-reset (&optional hidden) - "Reset IDL. Return to main level and destroy the leftover variables. -This issues the following commands: -RETALL -WIDGET_CONTROL,/RESET -CLOSE, /ALL -HEAP_GC, /VERBOSE" - ;; OBJ_DESTROY, OBJ_VALID() FIXME: should this be added? - (interactive "P") - (when (or idlwave-shell-reset-no-prompt - (yes-or-no-p "Really Reset IDL and discard current session? ")) - (message "Resetting IDL") - (setq idlwave-shell-calling-stack-index 0) - ;; Give widget exit handlers a chance - (idlwave-shell-send-command "retall" nil hidden) - (idlwave-shell-send-command "widget_control,/reset" nil hidden) - (idlwave-shell-send-command "close,/all" nil hidden) - ;; (idlwave-shell-send-command "obj_destroy, obj_valid()" nil hidden) - (idlwave-shell-send-command "heap_gc,/verbose" nil hidden) - (idlwave-shell-display-line nil))) - -(defun idlwave-shell-path-filter () - ;; Convert the output of the path query into a list of directories - (let ((path-string idlwave-shell-command-output) - (case-fold-search t) - (start 0) - dirs sysdir) - (while (string-match "^PATH:[ \t]*<\\(.*\\)>[ \t]*\n" path-string start) - (push (match-string 1 path-string) dirs) - (setq start (match-end 0))) - (setq dirs (mapcar #'file-name-as-directory dirs)) - (if (string-match "^SYSDIR:[ \t]*<\\(.*\\)>[ \t]*\n" path-string) - (setq sysdir (file-name-as-directory - (match-string 1 path-string)))) - (cons sysdir (nreverse dirs)))) - -(defun idlwave-shell-routine-info-filter () - "Parse the special output from idlwave_routine_info.pro." - (let ((text idlwave-shell-command-output) - (start 0) - sep sep-re file type spec specs name cs key keys class entry) - ;; (message "GOT: %s" text) ;?????????????????????? - ;; Initialize variables - (setq idlwave-compiled-routines nil - idlwave-unresolved-routines nil) - ;; Cut out the correct part of the output. - (if (string-match - "^>>>BEGIN OF IDLWAVE ROUTINE INFO (\"\\(.+\\)\" IS THE SEPARATOR.*" - text) - (setq sep (match-string 1 text) - sep-re (concat (regexp-quote sep) " *") - text (substring text (match-end 0))) - ;; Set dummy values and kill the text - (setq sep "@" sep-re "@ *" text "") - (if idlwave-idlwave_routine_info-compiled - (message - "Routine Info warning: No match for BEGIN line in \n>>>\n%s\n<<<\n" - idlwave-shell-command-output))) - (if (string-match "^>>>END OF IDLWAVE ROUTINE INFO.*" text) - (setq text (substring text 0 (match-beginning 0))) - (if idlwave-idlwave_routine_info-compiled - (message - "Routine Info warning: No match for END line in \n>>>\n%s\n<<<\n" - idlwave-shell-command-output))) - ;; Match the output lines - (while (string-match "^IDLWAVE-\\(PRO\\|FUN\\): \\(.*\\)" text start) - (setq start (match-end 0)) - (setq type (match-string 1 text) - spec (match-string 2 text) - specs (idlwave-split-string spec sep-re) - name (nth 0 specs) - class (if (equal (nth 1 specs) "") nil (nth 1 specs)) - file (nth 2 specs) - cs (nth 3 specs) - key (nth 4 specs) - keys (if (and (stringp key) - (not (string-match "\\` *\\'" key))) - (mapcar #'list - (delete "" (idlwave-split-string key " +"))))) - (setq name (idlwave-sintern-routine-or-method name class t) - class (idlwave-sintern-class class t) - file (if (equal file "") nil file) - keys (mapcar (lambda (x) - (list (idlwave-sintern-keyword (car x) t))) - keys)) - - ;; In the following ignore routines already defined in buffers, - ;; assuming that if the buffer stuff differs, it is a "new" - ;; version, not yet compiled, and should take precedence. - ;; We could do the same for the library to avoid duplicates - - ;; but I think frequently a user might have several versions of - ;; the same function in different programs, and in this case the - ;; compiled one will be the best guess of all versions. - ;; Therefore, we leave duplicates of library routines in. - (cond ((string= name "$MAIN$")) ; ignore this one - ((and (string= type "PRO") - ;; FIXME: is it OK to make the buffer routines dominate? - (or t (null file) - (not (idlwave-rinfo-assq name 'pro class - idlwave-buffer-routines))) - ;; FIXME: is it OK to make the library routines dominate? - ;;(not (idlwave-rinfo-assq name 'pro class - ;; idlwave-library-routines)) - ) - (setq entry (list name 'pro class - (cons 'compiled - (if file - (list - (file-name-nondirectory file) - (idlwave-sintern-dir - (file-name-directory file))))) - cs (cons nil keys))) - (if file - (push entry idlwave-compiled-routines) - (push entry idlwave-unresolved-routines))) - - ((and (string= type "FUN") - ;; FIXME: is it OK to make the buffer routines dominate? - (or t (not file) - (not (idlwave-rinfo-assq name 'fun class - idlwave-buffer-routines))) - ;; FIXME: is it OK to make the library routines dominate? - ;; (not (idlwave-rinfo-assq name 'fun class - ;; idlwave-library-routines)) - ) - (setq entry (list name 'fun class - (cons 'compiled - (if file - (list - (file-name-nondirectory file) - (idlwave-sintern-dir - (file-name-directory file))))) - cs (cons nil keys))) - (if file - (push entry idlwave-compiled-routines) - (push entry idlwave-unresolved-routines)))))) - ;; Reverse the definitions so that they are alphabetically sorted. - (setq idlwave-compiled-routines (nreverse idlwave-compiled-routines) - idlwave-unresolved-routines (nreverse idlwave-unresolved-routines))) - -(defun idlwave-shell-filter-directory () - "Get the current directory from `idlwave-shell-command-output'. -Change the default directory for the process buffer to concur." - (with-current-buffer (idlwave-shell-buffer) - (if (string-match ",___cur[\n\r ]+\\([^\n\r]+\\)[\n\r]" - idlwave-shell-command-output) - (let ((dir (substring idlwave-shell-command-output - (match-beginning 1) (match-end 1)))) - ;; (message "Setting Emacs working dir to %s" dir) - (setq idlwave-shell-default-directory dir) - (setq default-directory (file-name-as-directory dir)))))) - -(defvar idlwave-shell-get-object-class nil) -(defun idlwave-shell-get-object-class (apos) - "Query the shell for the class of the object before point." - (let ((bos (save-excursion (idlwave-start-of-substatement 'pre) (point))) - (bol (save-excursion (forward-line 0) (point))) - expression) - (save-excursion - (goto-char apos) - (setq expression (buffer-substring - (catch 'exit - (while t - (if (not (re-search-backward - "[^][.A-Za-z0-9_() ]" bos t)) - (throw 'exit bos)) ;ran into bos - (if (not (idlwave-is-pointer-dereference bol)) - (throw 'exit (1+ (point)))))) - apos))) - (when (not (string= expression "")) - (setq idlwave-shell-get-object-class nil) - (idlwave-shell-send-command - (concat "if obj_valid(" expression ") then print,obj_class(" - expression ")") - 'idlwave-shell-parse-object-class - 'hide 'wait) - ;; If we don't know anything about the class, update shell routines - (if (and idlwave-shell-get-object-class - (not (assoc-string idlwave-shell-get-object-class - (idlwave-class-alist) t))) - (idlwave-shell-maybe-update-routine-info)) - idlwave-shell-get-object-class))) - -(defun idlwave-shell-parse-object-class () - "Parse the output of the obj_class command." - (let ((match "obj_class([^\n\r]+[\n\r ]")) - (if (string-match (concat match "\\([A-Za-z_0-9]+\\) *[\n\r]\\(" - idlwave-shell-prompt-pattern "\\)") - idlwave-shell-command-output) - (setq idlwave-shell-get-object-class - (match-string 1 idlwave-shell-command-output))))) - -(defvar idlwave-sint-sysvars nil) -(idlwave-new-sintern-type execcomm) - -(defun idlwave-shell-complete (&optional arg) - "Do completion in the `idlwave-shell' buffer. -Calls `idlwave-shell-complete-filename' after some executive commands or -in strings. Otherwise, calls `idlwave-complete' to complete modules and -keywords." - (interactive "P") - (let (exec-cmd) - (cond - ((and - (setq exec-cmd (idlwave-shell-executive-command)) - (cdr exec-cmd) - (member (upcase (cdr exec-cmd)) - '(".R" ".RU" ".RUN" ".RN" ".RNE" ".RNEW" - ".COM" ".COMP" ".COMPI" ".COMPIL" ".COMPILE"))) - ;; We are in a command line with an executive command - (idlwave-shell-complete-filename)) - - ((car-safe exec-cmd) - (setq idlwave-completion-help-info - '(idlwave-shell-complete-execcomm-help)) - (idlwave-complete-in-buffer 'execcomm 'execcomm - idlwave-executive-commands-alist nil - "Select an executive command" - "system variable")) - - ((idlwave-shell-batch-command) - (idlwave-shell-complete-filename)) - - ((idlwave-shell-shell-command) - (idlwave-shell-complete-filename)) - - ((and (idlwave-shell-filename-string) - (save-excursion - (beginning-of-line) - (let ((case-fold-search t)) - (not (looking-at ".*obj_new"))))) - (idlwave-shell-complete-filename)) - - (t - ;; Default completion of modules and keywords - (idlwave-complete arg))))) - -;; Get rid of opaque dynamic variable passing of idlw-help-link? -(defvar idlw-help-link) ; dynamic variable from idlwave-do-mouse-completion-help -(defun idlwave-shell-complete-execcomm-help (mode word) - (let ((word (or (nth 1 idlwave-completion-help-info) word)) - (entry (assoc-string word idlwave-executive-commands-alist t))) - (cond - ((eq mode 'test) - (and (stringp word) entry (cdr entry))) - ((eq mode 'set) - (if entry (setq idlw-help-link (cdr entry)))) ; setting dynamic variable! - (t (error "This should not happen"))))) - -(defun idlwave-shell-complete-filename () - "Complete a file name at point if after a file name. -We assume that we are after a file name when completing one of the -args of an executive .run, .rnew or .compile." - ;; CWD might have changed, resync, to set default directory - (idlwave-shell-resync-dirs) - (let ((comint-file-name-chars idlwave-shell-file-name-chars)) - (comint-dynamic-complete-filename))) - -(defun idlwave-shell-executive-command () - "Return the name of the current executive command, if any." - (save-excursion - (idlwave-beginning-of-statement) - (cons (looking-at "[ \t]*\\.") - (if (looking-at "[ \t]*[.]\\([^ \t\n\r]+\\)[ \t]") - (match-string 1))))) - -(defun idlwave-shell-filename-string () - "Return t if in a string and after what could be a file name." - (let ((limit (line-beginning-position))) - (save-excursion - ;; Skip backwards over file name chars - (skip-chars-backward idlwave-shell-file-name-chars limit) - ;; Check of the next char is a string delimiter - (and (memq (preceding-char) '(?\' ?\")) t)))) - -(defun idlwave-shell-batch-command () - "Return t if we're in a batch command statement like \"@foo\"." - (let ((limit (line-beginning-position))) - (save-excursion - ;; Skip backwards over filename - (skip-chars-backward idlwave-shell-file-name-chars limit) - (skip-chars-backward " \t" limit) - (and (eq (preceding-char) ?@) (not (idlwave-in-quote)))))) - -(defun idlwave-shell-shell-command () - "Return t if we're in a shell command statement like \"$ls\"." - (save-excursion - (idlwave-beginning-of-statement) - (looking-at "\\$"))) - -;; Debugging Commands ------------------------------------------------------ - -(defun idlwave-shell-redisplay (&optional hide) - "Try to resync the display with where execution has stopped. -Issues a \"help,/trace\" command followed by a call to -`idlwave-shell-display-line'. Also updates the breakpoint -overlays." - (interactive) - (setq idlwave-shell-calling-stack-index 0) - (idlwave-shell-send-command - "help,/trace" - '(idlwave-shell-display-line - (idlwave-shell-pc-frame)) - hide) - (idlwave-shell-bp-query)) - -(defun idlwave-shell-display-level-in-calling-stack (&optional hide) - (idlwave-shell-send-command - "help,/trace" - `(progn - ;; scanning for the state will reset the stack level - restore it - (setq idlwave-shell-calling-stack-index - ,idlwave-shell-calling-stack-index) - ;; parse the stack and visit the selected frame - (idlwave-shell-parse-stack-and-display)) - hide)) - -(defun idlwave-shell-parse-stack-and-display () - (let* ((lines (delete "" (idlwave-split-string - idlwave-shell-command-output "^%"))) - (stack (delq nil (mapcar #'idlwave-shell-parse-line lines))) - (nmax (1- (length stack))) - (nmin 0) message) - (cond - ((< nmax nmin) - (setq idlwave-shell-calling-stack-index 0) - (ding) - (message "Problem with calling stack")) - ((> idlwave-shell-calling-stack-index nmax) - (ding) - (setq idlwave-shell-calling-stack-index nmax - message (format "%d is the highest calling stack level - can't go further up" - (- nmax)))) - ((< idlwave-shell-calling-stack-index nmin) - (ding) - (setq idlwave-shell-calling-stack-index nmin - message (format "%d is the current calling stack level - can't go further down" - (- nmin))))) - (setq idlwave-shell-calling-stack-routine - (nth 2 (nth idlwave-shell-calling-stack-index stack))) - - ;; force edebug for this frame if we're in that mode already - (idlwave-shell-display-line - (nth idlwave-shell-calling-stack-index stack) nil - (if idlwave-shell-electric-debug-mode 'force)) - (message "%s" (or message - (format "In routine %s (stack level %d)" - idlwave-shell-calling-stack-routine - (- idlwave-shell-calling-stack-index)))))) - -(defun idlwave-shell-stack-up () - "Display the source code one step up the calling stack." - (interactive) - (cl-incf idlwave-shell-calling-stack-index) - (idlwave-shell-display-level-in-calling-stack 'hide)) -(defun idlwave-shell-stack-down () - "Display the source code one step down the calling stack." - (interactive) - (cl-decf idlwave-shell-calling-stack-index) - (idlwave-shell-display-level-in-calling-stack 'hide)) - -(defun idlwave-shell-goto-frame (&optional frame) - "Set buffer to FRAME with point at the frame line. -If the optional argument FRAME is nil then `idlwave-shell-pc-frame' -is used. Does nothing if the resulting frame is nil." - (if frame () - (setq frame (idlwave-shell-pc-frame))) - (cond - (frame - (set-buffer (idlwave-find-file-noselect (car frame) 'shell)) - (widen) - (goto-char (point-min)) - (forward-line (1- (nth 1 frame)))))) - -(defun idlwave-shell-pc-frame () - "Return the frame for IDL execution." - (and idlwave-shell-halt-frame - (list (nth 0 idlwave-shell-halt-frame) - (nth 1 idlwave-shell-halt-frame) - (nth 2 idlwave-shell-halt-frame)))) - -(defun idlwave-shell-valid-frame (frame) - "Check that frame is for an existing file." - (file-readable-p (car frame))) - -(defun idlwave-shell-stop-line-pending () - ;; Temporarily change the color of the stop line overlay - (if idlwave-shell-stop-line-overlay - (overlay-put idlwave-shell-stop-line-overlay 'face - (if idlwave-shell-electric-debug-mode - 'idlwave-shell-pending-electric-stop - 'idlwave-shell-pending-stop)))) - -(defvar idlwave-shell-suppress-electric-debug nil) -(defun idlwave-shell-display-line (frame &optional col debug) - "Display frame file in other window with overlay arrow. - -FRAME is a list of file name, line number, and subroutine name. If -FRAME is nil then remove overlay. If COL is set, move point to that -column in the line. If DEBUG is non-nil, enable the electric debug -mode. If it is `disable', do not enable no matter what the setting of -`idlwave-shell-automatic-electric-debug'. If it is `force', enable no -matter what the settings of that variable." - (if (not frame) - ;; remove stop-line overlay from old position - (progn - (setq overlay-arrow-string nil) - (setq idlwave-shell-mode-line-info nil) - (setq idlwave-shell-is-stopped nil) - (if idlwave-shell-stop-line-overlay - (delete-overlay idlwave-shell-stop-line-overlay)) - ;; turn off electric debug everywhere, if it's on - (idlwave-shell-electric-debug-all-off)) - (if (not (idlwave-shell-valid-frame frame)) - ;; fixme: errors are dangerous in shell filters. but i think i - ;; have never encountered this one. - (error "Invalid frame - unable to access file: %s" (car frame)) - ;; - ;; buffer : the buffer to display a line in. - ;; select-shell: current buffer is the shell. - ;; - (setq idlwave-shell-mode-line-info - (if (nth 2 frame) - (format "[%d:%s]" - (- idlwave-shell-calling-stack-index) - (nth 2 frame)))) - (let* ((buffer (idlwave-find-file-noselect (car frame) 'shell)) - (select-shell (equal (buffer-name) (idlwave-shell-buffer))) - window pos electric) - - ;; first make sure the shell window is visible - (idlwave-display-buffer (idlwave-shell-buffer) - nil (idlwave-shell-shell-frame)) - - ;; now display the buffer and remember which window it is. - (setq window (idlwave-display-buffer buffer - nil (idlwave-shell-source-frame))) - - ;; enter the buffer and mark the line - (with-current-buffer buffer - (save-restriction - (widen) - (goto-char (point-min)) - (forward-line (1- (nth 1 frame))) - (setq pos (point)) - (setq idlwave-shell-is-stopped t) - - (if idlwave-shell-stop-line-overlay - (progn - ;; restore face and move overlay - (overlay-put idlwave-shell-stop-line-overlay 'face - (if idlwave-shell-electric-debug-mode - idlwave-shell-electric-stop-line-face - idlwave-shell-stop-line-face)) - (move-overlay idlwave-shell-stop-line-overlay - (point) (line-end-position) - (current-buffer))) - ;; use the arrow instead, but only if marking is wanted. - (if idlwave-shell-mark-stop-line - (setq overlay-arrow-string idlwave-shell-overlay-arrow)) - (or overlay-arrow-position ; create the marker if necessary - (setq overlay-arrow-position (make-marker))) - (set-marker overlay-arrow-position (point) buffer))) - - ;; if the point is outside the restriction, widen the buffer. - (if (or (< pos (point-min)) (> pos (point-max))) - (progn - (widen) - (goto-char pos))) - - ;; if we have the column of the error, move the cursor there. - (if col (move-to-column col)) - (setq pos (point)) - - ;; enter electric debug mode, if not prohibited and not in - ;; it already - (when (and (not idlwave-shell-electric-debug-mode) - (or (eq debug 'force) - (and - (not (eq debug 'disable)) ;; explicitly disabled - (or - (eq idlwave-shell-automatic-electric-debug t) - (and - (eq idlwave-shell-automatic-electric-debug - 'breakpoint) - (not (eq idlwave-shell-current-state 'error)))) - (not idlwave-shell-suppress-electric-debug)))) - (idlwave-shell-electric-debug-mode t)) - (setq electric idlwave-shell-electric-debug-mode)) - - ;; Make sure pos is really displayed in the window. - (set-window-point window pos) - - ;; If we came from the shell, go back there. Otherwise select - ;; the window where the error/halt is displayed. - (if (or (and idlwave-shell-electric-zap-to-file electric) - (and (equal (buffer-name) (idlwave-shell-buffer)) - (not select-shell))) - (select-window window)))))) - - -(defun idlwave-shell-step (arg) - "Step one source line. -If given prefix argument ARG, step ARG source lines." - (interactive "p") - (or (not arg) (< arg 1) - (setq arg 1)) - (idlwave-shell-stop-line-pending) - (idlwave-shell-send-command - (concat ".s " (if (integerp arg) (int-to-string arg) arg)) - nil (if (idlwave-shell-hide-p 'debug) 'mostly) nil t)) - -(defun idlwave-shell-stepover (arg) - "Stepover one source line. -If given prefix argument ARG, step ARG source lines. -Uses IDL's stepover executive command which does not enter called functions." - (interactive "p") - (or (not arg) (< arg 1) - (setq arg 1)) - (idlwave-shell-stop-line-pending) - (idlwave-shell-send-command - (concat ".so " (if (integerp arg) (int-to-string arg) arg)) - nil (if (idlwave-shell-hide-p 'debug) 'mostly) nil t)) - -(defun idlwave-shell-break-here (&optional count cmd condition disabled - no-show) - "Set breakpoint at current line. - -If COUNT is nil then an ordinary breakpoint is set. We treat a COUNT -of 1 as a temporary breakpoint using the ONCE keyword. Counts greater -than 1 use the IDL AFTER=count keyword to break only after reaching -the statement COUNT times. - -Optional argument CMD is a list or function to evaluate upon reaching -the breakpoint. CONDITION is a break condition, and DISABLED, if -non-nil disables the breakpoint." - (interactive "P") - (when (listp count) - (if (equal (car count) 4) - (setq condition (read-string "Break Condition: "))) - (setq count nil)) - (idlwave-shell-set-bp - ;; Create breakpoint - (idlwave-shell-bp (idlwave-shell-current-frame) - (list count cmd condition disabled) - (idlwave-shell-current-module)) - no-show)) - -(defun idlwave-shell-set-bp-check (bp) - "Check for failure to set breakpoint. -This is run on `idlwave-shell-post-command-hook'. -Offers to recompile the procedure if we failed. This usually fixes -the problem with not being able to set the breakpoint." - ;; Scan for message - (if idlwave-shell-command-output - (cond - ((string-match "% BREAKPOINT: *Unable to find code" - idlwave-shell-command-output) - ;; Offer to recompile - (if (progn - (beep) - (y-or-n-p - (concat "Okay to recompile file " - (idlwave-shell-bp-get bp 'file) "?"))) - ;; Recompile - (progn - ;; Clean up before retrying - (idlwave-shell-command-failure) - (idlwave-shell-send-command - (concat ".run \"" (idlwave-shell-bp-get bp 'file) "\"") nil - (if (idlwave-shell-hide-p 'run) 'mostly) nil t) - ;; Try setting breakpoint again - (idlwave-shell-set-bp bp)) - (beep) - (message "Unable to set breakpoint.") - (idlwave-shell-command-failure)) - nil) - - ((string-match "% Syntax error" idlwave-shell-command-output) - (message "Syntax error in condition.") - (idlwave-shell-command-failure) - nil) - - (t 'okay)))) - -(defun idlwave-shell-command-failure () - "Do any necessary clean up when an IDL command fails. -Call this from a function attached to `idlwave-shell-post-command-hook' -that detects the failure of a command. -For example, this is called from `idlwave-shell-set-bp-check' when a -breakpoint can not be set." - ;; Clear pending commands - (setq idlwave-shell-pending-commands nil)) - -(defun idlwave-shell-cont (&optional no-show) - "Continue executing." - (interactive) - (idlwave-shell-stop-line-pending) - (idlwave-shell-send-command ".c" (unless no-show - '(idlwave-shell-redisplay 'hide)) - (if (idlwave-shell-hide-p 'debug) 'mostly) - nil t)) - -(defun idlwave-shell-go () - "Run .GO. This starts the main program of the last compiled file." - (interactive) - (idlwave-shell-stop-line-pending) - (idlwave-shell-send-command ".go" '(idlwave-shell-redisplay 'hide) - (if (idlwave-shell-hide-p 'debug) 'mostly) - nil t)) - -(defun idlwave-shell-return () - "Run .RETURN (continue to next return, but stay in subprogram)." - (interactive) - (idlwave-shell-stop-line-pending) - (idlwave-shell-send-command ".return" '(idlwave-shell-redisplay 'hide) - (if (idlwave-shell-hide-p 'debug) 'mostly) - nil t)) - -(defun idlwave-shell-skip () - "Run .SKIP (skip one line, then step)." - (interactive) - (idlwave-shell-stop-line-pending) - (idlwave-shell-send-command ".skip" '(idlwave-shell-redisplay 'hide) - (if (idlwave-shell-hide-p 'debug) 'mostly) - nil t)) - -(defun idlwave-shell-clear-bp (bp &optional no-query) - "Clear breakpoint BP. -Clears in IDL and in `idlwave-shell-bp-alist'." - (let ((index (idlwave-shell-bp-get bp))) - (if index - (progn - (idlwave-shell-send-command - (concat "breakpoint,/clear," (int-to-string index)) - nil (idlwave-shell-hide-p 'breakpoint) nil t) - (unless no-query (idlwave-shell-bp-query)))))) - -(defun idlwave-shell-current-frame () - "Return a list containing the current file name and line point is in. -If in the IDL shell buffer, returns `idlwave-shell-pc-frame'." - (if (eq (current-buffer) (get-buffer (idlwave-shell-buffer))) - ;; In IDL shell - (idlwave-shell-pc-frame) - ;; In source - (list (idlwave-shell-file-name (buffer-file-name)) - (save-restriction - (widen) - (1+ (count-lines 1 (line-beginning-position))))))) - -(defun idlwave-shell-current-module () - "Return the name of the module for the current file. -Returns nil if unable to obtain a module name." - (if (eq (current-buffer) (get-buffer (idlwave-shell-buffer))) - ;; In IDL shell - (nth 2 idlwave-shell-halt-frame) - ;; In pro file - (save-restriction - (widen) - (save-excursion - (if (idlwave-prev-index-position) - (let* ((module (idlwave-what-module)) - (name (idlwave-make-full-name (nth 2 module) (car module))) - (type (nth 1 module))) - (list (upcase name) type))))))) - -(defun idlwave-shell-clear-current-bp () - "Remove breakpoint at current line. -This command can be called from the shell buffer if IDL is currently -stopped at a breakpoint." - (interactive) - (let ((bp (idlwave-shell-find-current-bp))) - (if bp (idlwave-shell-clear-bp bp)))) - - -(defun idlwave-shell-toggle-enable-current-bp (&optional bp force - no-update) - "Disable or enable current breakpoint or a breakpoint passed in BP. -If FORCE is `disable' or `enable', for that condition instead of -toggling. If NO-UPDATE is non-nil, don't update the breakpoint -list after toggling." - (interactive) - (let* ((bp (or bp (idlwave-shell-find-current-bp))) - (disabled (idlwave-shell-bp-get bp 'disabled))) - (cond ((eq force 'disable) (setq disabled nil)) - ((eq force 'enable) (setq disabled t))) - (when bp - (setf (nth 3 (cdr (cdr bp))) (not disabled)) - (idlwave-shell-send-command - (concat "breakpoint," - (if disabled "/enable," "/disable,") - (int-to-string (idlwave-shell-bp-get bp))) - nil (idlwave-shell-hide-p 'breakpoint) nil t) - (unless no-update (idlwave-shell-bp-query))))) - -(defun idlwave-shell-enable-all-bp (&optional enable no-update bpl) - "Disable all breakpoints we know about which need disabling. -If ENABLE is non-nil, enable them instead." - (let ((bpl (or bpl idlwave-shell-bp-alist)) disabled modified) - (while bpl - (setq disabled (idlwave-shell-bp-get (car bpl) 'disabled)) - (when (xor (not disabled) (eq enable 'enable)) - (idlwave-shell-toggle-enable-current-bp - (car bpl) (if (eq enable 'enable) 'enable 'disable) no-update) - (push (car bpl) modified)) - (setq bpl (cdr bpl))) - (unless no-update (idlwave-shell-bp-query)) - modified)) - -(defun idlwave-shell-to-here () - "Set a breakpoint with count 1 then continue." - (interactive) - ;; temporarily disable all other breakpoints - (let ((disabled (idlwave-shell-enable-all-bp 'disable 'no-update))) - (idlwave-shell-break-here 1 nil nil nil 'no-show) - (idlwave-shell-cont 'no-show) - (idlwave-shell-enable-all-bp 'enable 'no-update disabled)) - (idlwave-shell-redisplay)) ; sync up everything at the end - -(defun idlwave-shell-break-this-module (&optional arg) - (interactive "P") - (save-excursion - (idlwave-beginning-of-subprogram) - (idlwave-shell-break-here arg))) - -(defun idlwave-shell-break-in () - "Look for a module name near point and set a break point for it. -The command looks for an identifier near point and sets a breakpoint -for the first line of the corresponding module. If MODULE is t, set -in the current routine." - (interactive) - (let* ((module (idlwave-fix-module-if-obj_new (idlwave-what-module))) - (type (nth 1 module)) - (name (car module)) - (class (nth 2 module))) - (if module - (progn - (setq module (idlwave-make-full-name class name)) - (idlwave-shell-module-source-query module type) - (idlwave-shell-set-bp-in-module name type class)) - (error "No identifier at point")))) - - -(defun idlwave-shell-set-bp-in-module (name type class) - "Set breakpoint in module. -Assumes that `idlwave-shell-sources-alist' contains an entry for that module." - (let* ((module (idlwave-make-full-name class name)) - (source-file - (car-safe (cdr-safe - (or - (assoc (upcase module) - idlwave-shell-sources-alist) - (nth 3 (idlwave-best-rinfo-assoc name type class - (idlwave-routines))))))) - buf) - (if (or (not source-file) - (not (file-regular-p source-file)) - (not (setq buf - (or (find-buffer-visiting source-file) - (find-file-noselect source-file))))) - (progn - (message "The source file for module %s is probably not compiled" - module) - (beep)) - (with-current-buffer buf - (save-excursion - (goto-char (point-min)) - (let ((case-fold-search t)) - (if (re-search-forward - (concat "^[ \t]*\\(pro\\|function\\)[ \t]+" - (downcase module) - "[ \t\n,]") nil t) - (progn - (goto-char (match-beginning 1)) - (message "Setting breakpoint for module %s" module) - (idlwave-shell-break-here)) - (message "Cannot find module %s in file %s" module source-file) - (beep)))))))) - -(defun idlwave-shell-up () - "Run to end of current block. -Sets a breakpoint with count 1 at end of block, then continues." - (interactive) - (if (idlwave-shell-pc-frame) - (save-excursion - (idlwave-shell-goto-frame) - ;; find end of subprogram - (let ((eos (save-excursion - (idlwave-beginning-of-subprogram) - (idlwave-forward-block) - (point)))) - (idlwave-backward-up-block -1) - ;; move beyond end block line - IDL will not break there. - ;; That is, you can put a breakpoint there but when IDL does - ;; break it will report that it is at the next line. - (idlwave-next-statement) - (idlwave-end-of-statement) - ;; Make sure we are not beyond subprogram - (if (< (point) eos) - ;; okay - () - ;; Move back inside subprogram - (goto-char eos) - (idlwave-previous-statement)) - (idlwave-shell-to-here))))) - -(defun idlwave-shell-out () - "Attempt to run until this procedure exits. -Runs to the last statement and then steps 1 statement. Use the .out command." - (interactive) - (idlwave-shell-send-command ".o" nil - (if (idlwave-shell-hide-p 'debug) 'mostly) - nil t)) - -(defun idlwave-shell-goto-previous-bp () - "Move to the previous breakpoint in the buffer." - (interactive) - (idlwave-shell-move-to-bp -1)) -(defun idlwave-shell-goto-next-bp () - "Move to the next breakpoint in the buffer." - (interactive) - (idlwave-shell-move-to-bp 1)) - -(defun idlwave-shell-move-to-bp (dir) - "Move to the next or previous breakpoint, depending on direction DIR." - (let* ((frame (idlwave-shell-current-frame)) - (file (car frame)) - (orig-bp-line (nth 1 frame)) - (bp-alist idlwave-shell-bp-alist) - (orig-func (if (> dir 0) '> '<)) - (closer-func (if (> dir 0) '< '>)) - bp bp-line cur-line) - (while (setq bp (pop bp-alist)) - (when (string= file (car (car bp))) - (setq cur-line (nth 1 (car bp))) - (if (and - (funcall orig-func cur-line orig-bp-line) - (or (not bp-line) (funcall closer-func cur-line bp-line))) - (setq bp-line cur-line)))) - (unless bp-line (error "No further breakpoints")) - (goto-char (point-min)) - (forward-line (1- bp-line)))) - -;; Examine Commands ------------------------------------------------------ - -(defun idlwave-shell-help-expression (arg) - "Print help on current expression. See `idlwave-shell-print'." - (interactive "P") - (idlwave-shell-print arg 'help)) - -(defun idlwave-shell--mouse-examine (event help &optional ev) - "Expansion function for expression examination." - (let* ((transient-mark-mode t)) - (mouse-drag-track event) - (idlwave-shell-print (if (region-active-p) '(4) nil) - help ev))) - -(define-obsolete-function-alias - 'idlwave-default-mouse-track-event-is-with-button #'always "28.1") - -(define-obsolete-function-alias 'idlwave-xemacs-hack-mouse-track - #'ignore "27.1") -;;; End terrible hack section - -(defun idlwave-shell-mouse-print (event) - "Print value of variable at the mouse position, with `print'." - (interactive "e") - (idlwave-shell--mouse-examine event nil)) - -(defun idlwave-shell-mouse-help (event) - "Print value of variable at the mouse position, with `help'." - (interactive "e") - (idlwave-shell--mouse-examine event 'help)) - -(defun idlwave-shell-examine-select (event) - "Pop-up a list to select from for examining the expression." - (interactive "e") - (idlwave-shell--mouse-examine event nil event)) - -(defmacro idlwave-shell-examine (help) - "Create a function for key-driven expression examination." - `(lambda () - (interactive) - (idlwave-shell-print nil ,help))) - -(defvar idlwave-shell-examine-label nil - "Label to include with examine text if in a separate buffer.") -(defvar idlwave-shell-examine-completion-list nil) - -(defun idlwave-shell-print (arg &optional help ev complete-help-type) - "Print current expression. - -With HELP non-nil, show help on expression. If HELP is a string, -the expression will be put in place of ___, e.g.: - - print,size(___,/DIMENSIONS) - -HELP can also be a cons cell ( NAME . STRING ) in which case NAME will -be used to label the help print-out. - -Otherwise, print is called on the expression. - -An expression is an identifier plus 1 pair of matched parentheses -directly following the identifier - an array or function call. -Alternatively, an expression is the contents of any matched -parentheses when the open parenthesis is not directly preceded by an -identifier. If point is at the beginning or within an expression -return the inner-most containing expression, otherwise, return the -preceding expression. - -With prefix arg, or if transient mode set and the region is defined, -use the current region as the expression. - -With double prefix arg ARG prompt for an expression. - -If EV is a valid event passed, pop-up a list from -`idlwave-shell-examine-alist' from which to select the help -command text. If instead COMPLETE-HELP-TYPE is non-nil, choose -from `idlwave-shell-examine-alist' via mini-buffer shortcut key." - (interactive "P") - - ;; For speed: assume the helper routine hasn't been lost, e.g. with - ;; .FULL_RESET_SESSION. We'll recover if necessary - (unless idlwave-idlwave_routine_info-compiled - (idlwave-shell-compile-helper-routines)) - (save-excursion - (let* ((process (get-buffer-process (current-buffer))) - (process-mark (if process (process-mark process))) - (stack-label - (if (and (integerp idlwave-shell-calling-stack-index) - (> idlwave-shell-calling-stack-index 0)) - (format " [-%d:%s]" - idlwave-shell-calling-stack-index - idlwave-shell-calling-stack-routine))) - expr beg end cmd) - (cond - ((equal arg '(16)) - (setq expr (read-string "Expression: "))) - ((and (or arg (region-active-p)) - (< (- (region-end) (region-beginning)) 2000)) - (setq beg (region-beginning) - end (region-end))) - (t - (with-syntax-table idlwave-find-symbol-syntax-table - ;; Move to beginning of current or previous expression - (if (looking-at "\\<\\|(") - ;; At beginning of expression, don't move backwards unless - ;; this is at the end of an identifier. - (if (looking-at "\\>") - (backward-sexp)) - (backward-sexp)) - (if (looking-at "\\>") - ;; Move to beginning of identifier - must be an array or - ;; function expression. - (backward-sexp)) - ;; Move to end of expression - (setq beg (point)) - (forward-sexp) - (while (looking-at "\\>[[(]\\|\\.") - ;; an array - (forward-sexp)) - (setq end (point))))) - - ;; Get expression, but first move the begin mark if a - ;; process-mark is inside the region, to keep the overlay from - ;; wandering in the Shell. - (when (and beg end) - (if (and process-mark (> process-mark beg) (< process-mark end)) - (setq beg (marker-position process-mark))) - (setq expr (buffer-substring beg end))) - - ;; Show the overlay(s) and attach any necessary hooks and filters - (when (and beg end idlwave-shell-expression-overlay) - (move-overlay idlwave-shell-expression-overlay beg end - (current-buffer)) - (add-hook 'pre-command-hook - #'idlwave-shell-delete-expression-overlay)) - (add-hook 'pre-command-hook - #'idlwave-shell-delete-output-overlay) - - ;; Remove empty or comment-only lines - (while (string-match "\n[ \t]*\\(;.*\\)?\r*\n" expr) - (setq expr (replace-match "\n" t t expr))) - ;; Concatenate continuation lines - (while (string-match "[ \t]*\\$[ \t]*\\(;.*\\)?\\(\n[ \t]*\\|$\\)" expr) - (setq expr (replace-match "" t t expr))) - ;; Remove final newline - (if (string-match "\n[ \t\r]*\\'" expr) - (setq expr (replace-match "" t t expr))) - - (catch 'exit - ;; Pop-up or complete on the examine selection list, if appropriate - (if (or - complete-help-type - (and ev idlwave-shell-examine-alist) - (consp help)) - (let ((help-cons - (if (consp help) help - (assoc - ;; A cons from either a pop-up or mini-buffer completion - (if complete-help-type - (idlwave-one-key-select 'idlwave-shell-examine-alist - "Examine with: " 1.5) -;; (idlwave-completing-read -;; "Examine with: " -;; idlwave-shell-examine-alist nil nil nil -;; 'idlwave-shell-examine-completion-list -;; "Print") - (idlwave-popup-select - ev - (mapcar #'car idlwave-shell-examine-alist) - "Examine with")) - idlwave-shell-examine-alist)))) - (setq help (cdr help-cons)) - (if (null help) (throw 'exit nil)) - (if idlwave-shell-separate-examine-output - (setq idlwave-shell-examine-label - (concat - (format "==>%s<==\n%s:" expr (car help-cons)) - stack-label "\n")))) - ;; The regular help label (no popups, cons cells, etc.) - (setq idlwave-shell-examine-label - (concat - (format "==>%s<==\n%s:" expr - (cond ((null help) "print") - ((stringp help) help) - (t (symbol-name help)))) - stack-label "\n"))) - - ;; Send the command - (if stack-label - (setq expr (idlwave-retrieve-expression-from-level - expr - idlwave-shell-calling-stack-index))) - (setq cmd (idlwave-shell-help-statement help expr)) - ;;(idlwave-shell-recenter-shell-window) - (idlwave-shell-send-command - cmd - 'idlwave-shell-check-compiled-and-display - (if idlwave-shell-separate-examine-output 'hide)))))) - -(defvar idlwave-shell-examine-window-alist nil - "Variable to hold the win/height pairs for all *Examine* windows.") - -(defvar idlwave-shell-examine-map (make-sparse-keymap)) -(define-key idlwave-shell-examine-map "q" #'idlwave-shell-examine-display-quit) -(define-key idlwave-shell-examine-map "c" #'idlwave-shell-examine-display-clear) - -(defun idlwave-shell-check-compiled-and-display () - "Check examine output for warning about undefined procedure/function." - (if (string-match "% Attempt to call undefined" idlwave-shell-command-output) - (idlwave-shell-compile-helper-routines)) - (if idlwave-shell-separate-examine-output - (idlwave-shell-examine-display) - (idlwave-shell-examine-highlight))) - -(defun idlwave-shell-examine-display () - "View the examine command output in a separate buffer." - (let (win cur-beg cur-end) - (with-current-buffer (get-buffer-create "*Examine*") - (use-local-map idlwave-shell-examine-map) - (setq buffer-read-only nil) - (goto-char (point-max)) - (save-restriction - (narrow-to-region (point) (point)) - (if (string-match "^% Syntax error." idlwave-shell-command-output) - (insert "% Syntax error.\n") - (insert idlwave-shell-command-output) - ;; Just take the last bit between the prompts (if more than one). - (let* ((end (or - (re-search-backward idlwave-shell-prompt-pattern nil t) - (point-max))) - (beg (progn - (goto-char - (or (progn (if (re-search-backward - idlwave-shell-prompt-pattern nil t) - (match-end 0))) - (point-min))) - (re-search-forward "\n"))) - (str (buffer-substring beg end))) - (delete-region (point-min) (point-max)) - (insert str) - (if idlwave-shell-examine-label - (progn (goto-char (point-min)) - (insert idlwave-shell-examine-label) - (setq idlwave-shell-examine-label nil))))) - (setq cur-beg (point-min) - cur-end (point-max)) - (setq buffer-read-only t) - (move-overlay idlwave-shell-output-overlay cur-beg cur-end - (current-buffer)) - - ;; Look for the examine buffer in all windows. If one is - ;; found in a frame all by itself, use that, otherwise, switch - ;; to or create an examine window in this frame, and resize if - ;; it's a newly created window - (let* ((winlist (get-buffer-window-list "*Examine*" nil 'visible))) - (setq win (idlwave-display-buffer - "*Examine*" - nil - (let ((list winlist) thiswin) - (catch 'exit - (save-selected-window - (while (setq thiswin (pop list)) - (select-window thiswin) - (if (one-window-p) - (throw 'exit (window-frame thiswin))))))))) - (set-window-start win (point-min)) ; Ensure the point is visible. - (save-selected-window - (select-window win) - (let ((elt (assoc win idlwave-shell-examine-window-alist))) - (when (and (not (one-window-p)) - (or (not (memq win winlist)) ;a newly created window - (eq (window-height) (cdr elt)))) - ;; Autosize it. - (enlarge-window (- (/ (frame-height) 2) - (window-height))) - (shrink-window-if-larger-than-buffer) - ;; Clean the window list of dead windows - (setq idlwave-shell-examine-window-alist - (delq nil - (mapcar (lambda (x) (if (window-live-p (car x)) x)) - idlwave-shell-examine-window-alist))) - ;; And add the new value. - (if (setq elt (assoc win idlwave-shell-examine-window-alist)) - (setcdr elt (window-height)) - (add-to-list 'idlwave-shell-examine-window-alist - (cons win (window-height))))))))) - ;; Recenter for maximum output, after widened - (save-selected-window - (select-window win) - (goto-char (point-max)) - (skip-chars-backward "\n") - (recenter -1))))) - -(defun idlwave-shell-examine-display-quit () - (interactive) - (let ((win (selected-window))) - (if (one-window-p) - (delete-frame (window-frame win)) - (delete-window win)))) - -(defun idlwave-shell-examine-display-clear () - (interactive) - (let ((buf (get-buffer "*Examine*"))) - (when (bufferp buf) - (with-current-buffer buf - (let ((inhibit-read-only t)) - (erase-buffer)))))) - -(defun idlwave-retrieve-expression-from-level (expr level) - "Return IDL command to print the expression EXPR from stack level LEVEL. - -It does not seem possible to evaluate an expression on a different -level than the current. Therefore, this function retrieves variables -by reference from other levels, and then includes that variable in -place of the chosen one. - -Since this function depends upon the undocumented IDL routine -routine_names, there is no guarantee that this will work with future -versions of IDL." - (let ((fetch (- 0 level)) - (start 0) - var fetch-start fetch-end pre post) - - ;; FIXME: In the following we try to find the variables in expression - ;; This is quite empirical - I don't know in what situations this will - ;; break. We will look for identifiers and exclude cases where we - ;; know it is not a variable. To distinguish array references from - ;; function calls, we require that arrays use [] instead of () - - (while (string-match - "\\(\\`\\|[^a-zA-Z0-9$_][ \t]*\\)\\([a-zA-Z][a-zA-Z0-9$_]*\\)\\([ \t]*[^a-zA-Z0-9$_]\\|\\'\\)" expr start) - (setq var (match-string 2 expr) - start (match-end 2) - pre (substring expr 0 (match-beginning 2)) - post (substring expr (match-end 2))) - (cond - ((or - ;; Exclude identifiers which are not variables - (string-match ",[ \t$\n]*/\\'" pre) ;; a `/' KEYWORD - (and (string-match "[,(][ \t\n]*\\'" pre) - (string-match "\\`[ \t]*=" post)) ;; a `=' KEYWORD - (string-match "\\`(" post) ;; a function - (string-match "->[ \t]*\\'" pre) ;; a method - (string-match "\\.\\'" pre))) ;; structure member - - ;; Skip over strings - ((and (string-match "\\([\"']\\)[^\1]*$" pre) - (string-match (concat "^[^" (match-string 1 pre) "]*" - (match-string 1 pre)) post)) - (setq start (+ start (match-end 0)))) - - - ;; seems to be a variable - delimit its name - (t - (put-text-property start (- start (length var)) 'fetch t expr)))) - - (setq start 0) - (while (setq fetch-start - (next-single-property-change start 'fetch expr)) - (if (get-text-property start 'fetch expr) ; it's on in range - (setq fetch-end fetch-start ;it's off in range - fetch-start start) - (setq fetch-end (next-single-property-change fetch-start 'fetch expr))) - (unless fetch-end (setq fetch-end (length expr))) - (remove-text-properties fetch-start fetch-end '(fetch nil) expr) - (setq expr (concat (substring expr 0 fetch-start) - (format "(routine_names('%s',fetch=%d))" - (substring expr fetch-start fetch-end) - fetch) - (substring expr fetch-end))) - (setq start fetch-end)) - (if (get-text-property 0 'fetch expr) ; Full expression, left over - (setq expr (format "(routine_names('%s',fetch=%d))" expr fetch))) - expr)) - - -(defun idlwave-shell-help-statement (help expr) - "Construct a help statement for printing expression EXPR. - -HELP can be non-nil for `help,', nil for `print,' or any string into which -to insert expression in place of the marker ___, e.g.: print, -size(___,/DIMENSIONS)" - (cond - ((null help) - (concat "idlwave_print_safe, " expr "," - (number-to-string idlwave-shell-max-print-length))) - ((stringp help) - (if (string-match "\\(^\\|[^_]\\)\\(___\\)\\([^_]\\|$\\)" help) - (concat (substring help 0 (match-beginning 2)) - expr - (substring help (match-end 2))))) - (t - (concat "help, " expr)))) - - -(defun idlwave-shell-examine-highlight () - "Highlight the most recent IDL output." - (let* ((buffer (get-buffer (idlwave-shell-buffer))) - (process (get-buffer-process buffer)) - (process-mark (if process (process-mark process))) - output-begin output-end) - (with-current-buffer buffer - (goto-char process-mark) - (beginning-of-line) - (setq output-end (point)) - (re-search-backward idlwave-shell-prompt-pattern nil t) - (beginning-of-line 2) - (setq output-begin (point))) - - ;; First make sure the shell window is visible - (idlwave-display-buffer (idlwave-shell-buffer) - nil (idlwave-shell-shell-frame)) - (if (and idlwave-shell-output-overlay process-mark) - (move-overlay idlwave-shell-output-overlay - output-begin output-end buffer)))) - -(defun idlwave-shell-delete-output-overlay () - (unless (memql this-command '(ignore handle-switch-frame)) - (condition-case nil - (if idlwave-shell-output-overlay - (delete-overlay idlwave-shell-output-overlay)) - (error nil)) - (remove-hook 'pre-command-hook #'idlwave-shell-delete-output-overlay))) - -(defun idlwave-shell-delete-expression-overlay () - (unless (memql this-command '(ignore handle-switch-frame)) - (condition-case nil - (if idlwave-shell-expression-overlay - (delete-overlay idlwave-shell-expression-overlay)) - (error nil)) - (remove-hook 'pre-command-hook #'idlwave-shell-delete-expression-overlay))) - -(defvar idlwave-shell-bp-alist nil - "Alist of breakpoints. -A breakpoint is a cons cell \((file line) . \((index module) data)) - -The car is the `frame' for the breakpoint: -file - full path file name. -line - line number of breakpoint - integer. - -The first element of the cdr is a list of internal IDL data: -index - the index number of the breakpoint internal to IDL. -module - the module for breakpoint internal to IDL. - -Remaining elements of the cdr: -data - Data associated with the breakpoint by `idlwave-shell' currently -contains four items: - -count - number of times to execute breakpoint. When count reaches 0 - the breakpoint is cleared and removed from the alist. - -command - command to execute when breakpoint is reached, either a - Lisp function to be called with `funcall' with no arguments or a - list to be evaluated with `eval'. - -condition - any condition to apply to the breakpoint. - -disabled - whether the bp is disabled.") - -(defun idlwave-shell-run-region (beg end &optional n) - "Compile and run the region using the IDL process. -Copies the region to a temporary file `idlwave-shell-temp-pro-file' -and issues the IDL .run command for the file. Because the region -is compiled and run as a main program there is no problem with -begin-end blocks extending over multiple lines - which would be -a problem if `idlwave-shell-evaluate-region' was used. -An END statement is appended to the region if necessary. - -If there is a prefix argument, display IDL process." - (interactive "r\nP") - (let ((oldbuf (current-buffer))) - (with-current-buffer (idlwave-find-file-noselect - (idlwave-shell-temp-file 'pro) 'tmp) - (set (make-local-variable 'comment-start-skip) ";+[ \t]*") - (set (make-local-variable 'comment-start) ";") - (erase-buffer) - (insert-buffer-substring oldbuf beg end) - (if (not (save-excursion - (idlwave-previous-statement) - (idlwave-look-at "\\"))) - (insert "\nend\n")) - (save-buffer 0))) - (idlwave-shell-send-command (concat ".run \"" - idlwave-shell-temp-pro-file "\"") - nil - (if (idlwave-shell-hide-p 'run) 'mostly) - nil t) - (if n - (idlwave-display-buffer (idlwave-shell-buffer) - nil (idlwave-shell-shell-frame)))) - -(defun idlwave-shell-evaluate-region (beg end &optional n) - "Send region to the IDL process. -If there is a prefix argument, display IDL process. -Does not work for a region with multiline blocks - use -`idlwave-shell-run-region' for this." - (interactive "r\nP") - (idlwave-shell-send-command (buffer-substring beg end)) - (if n - (idlwave-display-buffer (idlwave-shell-buffer) - nil (idlwave-shell-shell-frame)))) - -(defun idlwave-shell-delete-temp-files () - "Delete the temporary files and kill associated buffers." - (if (stringp idlwave-shell-temp-pro-file) - (condition-case nil - (let ((buf (find-buffer-visiting idlwave-shell-temp-pro-file))) - (if (buffer-live-p buf) - (kill-buffer buf)) - (delete-file idlwave-shell-temp-pro-file)) - (error nil))) - (if (stringp idlwave-shell-temp-rinfo-save-file) - (condition-case nil - (delete-file idlwave-shell-temp-rinfo-save-file) - (error nil)))) - -(defun idlwave-display-buffer (buf not-this-window-p &optional frame) - ;; Force the frame ourselves. - (let ((this-frame (selected-frame))) - (save-excursion ;; make sure we end up in the same buffer - (if (frame-live-p frame) - (select-frame frame)) - (if (eq this-frame (selected-frame)) - ;; same frame: use display buffer, to make sure the current - ;; window stays. - (display-buffer buf) - ;; different frame - (if (one-window-p) - ;; only window: switch - (progn - (switch-to-buffer buf) - (selected-window)) ; must return the window. - ;; several windows - use display-buffer - (display-buffer buf not-this-window-p)))))) - -(defvar idlwave-shell-bp-buffer " *idlwave-shell-bp*" - "Scratch buffer for parsing IDL breakpoint lists and other stuff.") - -(defun idlwave-shell-bp-query (&optional no-show) - "Reconcile idlwave-shell's breakpoint list with IDL's. -Queries IDL using the string in `idlwave-shell-bp-query'." - (interactive) - (idlwave-shell-send-command idlwave-shell-bp-query - `(progn - (idlwave-shell-filter-bp (quote ,no-show))) - 'hide)) - -(defun idlwave-shell-bp-get (bp &optional item) - "Get a value for a breakpoint. -BP has the form of elements in `idlwave-shell-bp-alist'. -Optional second arg ITEM is the particular value to retrieve. -ITEM can be `file', `line', `index', `module', `count', `cmd', -`condition', `disabled', `type', or `data'. `data' returns a list -of `count', `cmd' and `condition'. Defaults to `index'." - (cond - ;; Frame - ((eq item 'line) (nth 1 (car bp))) - ((eq item 'file) (nth 0 (car bp))) - ;; idlwave-shell breakpoint data - ((eq item 'data) (cdr (cdr bp))) - ((eq item 'count) (nth 0 (cdr (cdr bp)))) - ((eq item 'cmd) (nth 1 (cdr (cdr bp)))) - ((eq item 'condition) (nth 2 (cdr (cdr bp)))) - ((eq item 'disabled) (nth 3 (cdr (cdr bp)))) - ;; IDL breakpoint info - ((eq item 'module) - (let ((module (nth 1 (car (cdr bp))))) - (if (listp module) (car module) module))) - ((eq item 'type) - (let ((module (nth 1 (car (cdr bp))))) - (if (listp module) (nth 1 module)))) - ;; index - default - (t (nth 0 (car (cdr bp)))))) - -(defun idlwave-shell-filter-bp (&optional no-show) - "Get the breakpoints from `idlwave-shell-command-output'. -Create `idlwave-shell-bp-alist' updating breakpoint count and command -data from previous breakpoint list. If NO-SHOW is set, don't update -the breakpoint overlays." - (with-current-buffer (get-buffer-create idlwave-shell-bp-buffer) - (erase-buffer) - (insert idlwave-shell-command-output) - (goto-char (point-min)) - (let ((old-bp-alist idlwave-shell-bp-alist) - ;; Searching the breakpoints - ;; In IDL 5.5, the breakpoint reporting format changed. - (bp-re54 "^[ \t]*\\([0-9]+\\)[ \t]+\\(\\S-+\\)?[ \t]+\\([0-9]+\\)[ \t]+\\(\\S-+\\)") - (bp-re55 - (concat - "^\\s-*\\([0-9]+\\)" ; 1 index - "\\s-+\\([0-9]+\\)" ; 2 line number - "\\s-+\\(Uncompiled\\|" ; 3-6 either uncompiled or routine name - "\\(\\(Func=\\|Pro=\\)\\(\\$?[a-zA-Z][a-zA-Z0-9$_:]*\\$?\\)\\)\\)" - "\\(\\s-*,\\s-*After=[0-9]+/\\([0-9]+\\)?\\)?" ; 7-8 After part - "\\(\\s-*,\\s-*\\(BreakOnce\\)\\)?" ; 9-10 BreakOnce - "\\(\\s-*,\\s-*\\(Condition='\\(.*\\)'\\)\n?\\)?" ; 11-13 Condition - "\\(\\s-*,\\s-*\\(Disabled\\)\n?\\)?" ; 14-15 Disabled - "\\s-+\\(\\S-+\\)")) ; 16 File name - file line index module - count condition disabled - bp-re indmap) - (setq idlwave-shell-bp-alist (list nil)) - ;; Search for either header type, and set the correct regexp - (when (or - (if (re-search-forward "^\\s-*Index.*\n\\s-*-" nil t) - (setq bp-re bp-re54 ; versions <= 5.4 - indmap '(1 2 3 4))) ;index module line file - (if (re-search-forward - "^\\s-*Index\\s-*Line\\s-*Attributes\\s-*File" nil t) - (setq bp-re bp-re55 ; versions >= 5.5 - indmap '(1 6 2 16)))) ; index module line file - ;; There seems to be a breakpoint listing here, parse breakpoint lines. - (while (re-search-forward bp-re nil t) - (setq index (string-to-number (match-string (nth 0 indmap))) - module (match-string (nth 1 indmap)) - line (string-to-number (match-string (nth 2 indmap))) - file (idlwave-shell-file-name (match-string (nth 3 indmap)))) - (if (eq bp-re bp-re55) - (setq count (if (match-string 10) 1 - (if (match-string 8) - (string-to-number (match-string 8)))) - condition (match-string 13) - disabled (not (null (match-string 15))))) - - ;; Add the breakpoint info to the list - (nconc idlwave-shell-bp-alist - (list (cons (list file line) - (list - (list index module) - ;; bp data: count, command, condition, disabled - count nil condition disabled)))))) - (setq idlwave-shell-bp-alist (cdr idlwave-shell-bp-alist)) - ;; Update breakpoint data - (mapc (if (eq bp-re bp-re54) - #'idlwave-shell-update-bp - #'idlwave-shell-update-bp-command-only) - old-bp-alist))) - ;; Update the breakpoint overlays - (unless no-show (idlwave-shell-update-bp-overlays)) - ;; Return the new list - idlwave-shell-bp-alist) - -(defun idlwave-shell-update-bp-command-only (bp) - (idlwave-shell-update-bp bp t)) - -(defun idlwave-shell-update-bp (bp &optional command-only) - "Update BP data in breakpoint list. -If BP frame is in `idlwave-shell-bp-alist' updates the breakpoint data." - (let ((match (assoc (car bp) idlwave-shell-bp-alist))) - (if match - (if command-only - (setf (nth 1 (cdr (cdr match))) (nth 1 (cdr (cdr match)))) - (setcdr (cdr match) (cdr (cdr bp))))))) - -(defun idlwave-shell-set-bp-data (bp data) - "Set the data of BP to DATA." - (setcdr (cdr bp) data)) - -(defun idlwave-shell-bp (frame &optional data module) - "Create a breakpoint structure containing FRAME and DATA. -Second and third args, DATA and MODULE, are optional. Returns -a breakpoint of the format used in `idlwave-shell-bp-alist'. -Can be used in commands attempting match a breakpoint in -`idlwave-shell-bp-alist'." - (cons frame ;; (file line) - (cons (list nil module) ;; (index_id (module type) | module) - data))) ;; (count command condition disabled) - -(defvar idlwave-shell-old-bp nil - "List of breakpoints previous to setting a new breakpoint.") - -(defun idlwave-shell-sources-bp (bp) - "Check `idlwave-shell-sources-alist' for source of breakpoint using BP. -If an equivalency is found, return the IDL internal source name. -Otherwise return the filename in BP." - (let* - ((bp-file (idlwave-shell-bp-get bp 'file)) - (bp-module (idlwave-shell-bp-get bp 'module)) - (internal-file-list - (if bp-module - (cdr (assoc bp-module idlwave-shell-sources-alist))))) - (if (and internal-file-list - (equal bp-file (nth 0 internal-file-list))) - (nth 1 internal-file-list) - bp-file))) - -(defun idlwave-shell-set-bp (bp &optional no-show) - "Try to set a breakpoint BP. -The breakpoint will be placed at the beginning of the statement on the -line specified by BP or at the next IDL statement if that line is not -a statement. Determines IDL's internal representation for the -breakpoint, which may have occurred at a different line than -specified. If NO-SHOW is non-nil, don't do any updating." - ;; Get and save the old breakpoints - (idlwave-shell-send-command - idlwave-shell-bp-query - `(progn - (idlwave-shell-filter-bp (quote ,no-show)) - (setq idlwave-shell-old-bp idlwave-shell-bp-alist)) - 'hide) - - ;; Get sources for this routine in the sources list - (idlwave-shell-module-source-query (idlwave-shell-bp-get bp 'module) - (idlwave-shell-bp-get bp 'type)) - (let* - ((count (idlwave-shell-bp-get bp 'count)) - (condition (idlwave-shell-bp-get bp 'condition)) - (disabled (idlwave-shell-bp-get bp 'disabled)) - (key (concat (if (and count (numberp count)) - (cond - ((= count 1) ",/once") - ((> count 1) (format ",after=%d" count)))) - (if condition (concat ",CONDITION=\"" condition "\"")) - ;; IDL can't simultaneously set a condition/count - ;; and disable a breakpoint, but it does keep both - ;; of these when resetting the same BP. We assume - ;; DISABLE and CONDITION/COUNT are not set - ;; together for a newly created breakpoint. - (if (and disabled (not condition) (not count)) - ",/DISABLE"))) - (line (idlwave-shell-bp-get bp 'line))) - (idlwave-shell-send-command - (concat "breakpoint,'" - (idlwave-shell-sources-bp bp) "'," - (if (integerp line) (setq line (int-to-string line))) - key) - ;; Check for failure and adjust breakpoint to match IDL's list - `(progn - (if (idlwave-shell-set-bp-check (quote ,bp)) - (idlwave-shell-set-bp-adjust (quote ,bp) (quote ,no-show)))) - ;; hide output? - (idlwave-shell-hide-p 'breakpoint) - 'preempt t))) - -(defun idlwave-shell-set-bp-adjust (bp &optional no-show) - "Find the breakpoint in IDL's internal list of breakpoints." - (idlwave-shell-send-command - idlwave-shell-bp-query - `(progn - (idlwave-shell-filter-bp 'no-show) - (idlwave-shell-new-bp (quote ,bp)) - (unless (quote ,no-show) - (idlwave-shell-update-bp-overlays))) - 'hide - 'preempt)) - -(defun idlwave-shell-find-bp (frame) - "Return breakpoint from `idlwave-shell-bp-alist' for frame. -Returns nil if frame not found." - (assoc frame idlwave-shell-bp-alist)) - -(defun idlwave-shell-find-current-bp () - "Find breakpoint here, or at halt location." - (let ((bp (idlwave-shell-find-bp (idlwave-shell-current-frame)))) - (when (not bp) - ;; Try moving to beginning of halted-at statement - (save-excursion - (idlwave-shell-goto-frame) - (idlwave-beginning-of-statement) - (setq bp (idlwave-shell-find-bp (idlwave-shell-current-frame)))) - (unless bp - (beep) - (message "Cannot identify breakpoint for this line"))) - bp)) - -(defun idlwave-shell-new-bp (bp) - "Find the new breakpoint in IDL's list and update with DATA. -The actual line number for a breakpoint in IDL may be different from -the line number used with the IDL breakpoint command. -Looks for a new breakpoint index number in the list. This is -considered the new breakpoint if the file name of frame matches." - (let ((obp-index (mapcar #'idlwave-shell-bp-get idlwave-shell-old-bp)) - (bpl idlwave-shell-bp-alist)) - (while (and (member (idlwave-shell-bp-get (car bpl)) obp-index) - (setq bpl (cdr bpl)))) - (if (and - (not bpl) - ;; No additional breakpoint. - ;; Need to check if we are just replacing a breakpoint. - (setq bpl (assoc (car bp) idlwave-shell-bp-alist))) - (setq bpl (list bpl))) - (if (and bpl - (equal (idlwave-shell-bp-get (setq bpl (car bpl)) 'file) - (idlwave-shell-bp-get bp 'file))) - ;; Got the breakpoint - add count, command to it. - ;; This updates `idlwave-shell-bp-alist' because a deep copy was - ;; not done for bpl. - (idlwave-shell-set-bp-data bpl (idlwave-shell-bp-get bp 'data)) - (beep) - (message "Failed to identify breakpoint in IDL")))) - -(defvar idlwave-shell-bp-overlays nil - "Alist of overlays marking breakpoints.") -(defvar idlwave-shell-bp-glyph) - -(defvar idlwave-shell-debug-line-map (make-sparse-keymap)) -(define-key idlwave-shell-debug-line-map [mouse-3] - #'idlwave-shell-mouse-active-bp) - -(defun idlwave-shell-update-bp-overlays () - "Update the overlays which mark breakpoints in the source code. -Existing overlays are recycled, in order to minimize consumption." - (when idlwave-shell-mark-breakpoints - (let ((ov-alist (copy-alist idlwave-shell-bp-overlays)) - (bp-list idlwave-shell-bp-alist) - (use-glyph (and (memq idlwave-shell-mark-breakpoints '(t glyph)) - idlwave-shell-bp-glyph)) - ov ov-list bp buf old-buffers) - - ;; Delete the old overlays from their buffers - (if ov-alist - (while (setq ov-list (pop ov-alist)) - (while (setq ov (pop (cdr ov-list))) - (cl-pushnew (overlay-buffer ov) old-buffers) - (delete-overlay ov)))) - - (setq ov-alist idlwave-shell-bp-overlays - idlwave-shell-bp-overlays - (if idlwave-shell-bp-glyph - (mapcar #'list (mapcar #'car idlwave-shell-bp-glyph)) - (list (list 'bp)))) - (while (setq bp (pop bp-list)) - (save-excursion - (idlwave-shell-goto-frame (car bp)) - (let* ((end (line-end-position)) - (beg (progn (beginning-of-line 1) (point))) - (condition (idlwave-shell-bp-get bp 'condition)) - (count (idlwave-shell-bp-get bp 'count)) - (disabled (idlwave-shell-bp-get bp 'disabled)) - (type (if idlwave-shell-bp-glyph - (cond - (condition 'bp-cond ) - (count - (cond - ((<= count 0) 'bp) - ((<= count 4) - (intern - (concat "bp-" (number-to-string count)))) - (t 'bp-n))) - (t 'bp)) - 'bp)) - (help-list - (delq nil - (list - (if count - (concat "after:" (int-to-string count))) - (if condition - (concat "condition:" condition)) - (if disabled "disabled")))) - (help-text (concat - "BP " - (int-to-string (idlwave-shell-bp-get bp)) - (if help-list - (concat - " - " - (mapconcat #'identity help-list ", "))) - (if (and (not count) (not condition)) - " (use mouse-3 for breakpoint actions)"))) - (full-type (if disabled - (intern (concat (symbol-name type) - "-disabled")) - type)) - (ov-existing (assq full-type ov-alist)) - (ov (or (and (cdr ov-existing) - (pop (cdr ov-existing))) - (idlwave-shell-make-new-bp-overlay type disabled))) - match) - (if idlwave-shell-breakpoint-popup-menu - (overlay-put ov 'help-echo help-text)) - (move-overlay ov beg end) - (if (setq match (assq full-type idlwave-shell-bp-overlays)) - (push ov (cdr match)) - (nconc idlwave-shell-bp-overlays - (list (list full-type ov))))) - ;; Take care of margins if using a glyph - (when use-glyph - (if old-buffers - (setq old-buffers (delq (current-buffer) old-buffers))) - (if (< left-margin-width 2) - (setq left-margin-width 2)) - (let ((window (get-buffer-window (current-buffer) 0))) - (if window - (set-window-margins - window left-margin-width right-margin-width)))))) - (if use-glyph - (while (setq buf (pop old-buffers)) - (with-current-buffer buf - (setq left-margin-width 0) - (let ((window (get-buffer-window buf 0))) - (if window - (set-window-margins - window left-margin-width right-margin-width))))))))) - -(defun idlwave-shell-make-new-bp-overlay (&optional type disabled) - "Make a new overlay for highlighting breakpoints. - -This stuff is strongly dependent upon the version of Emacs. If TYPE -is passed, make an overlay of that type (`bp' or `bp-cond', currently -only for glyphs)." - (let ((ov (make-overlay 1 1)) - (use-glyph (and (memq idlwave-shell-mark-breakpoints '(t glyph)) - idlwave-shell-bp-glyph)) - (type (or type 'bp)) - (face (if disabled - idlwave-shell-disabled-breakpoint-face - idlwave-shell-breakpoint-face))) - (when idlwave-shell-breakpoint-popup-menu - (overlay-put ov 'mouse-face 'highlight) - (overlay-put ov 'keymap idlwave-shell-debug-line-map)) - (cond - (window-system - (if use-glyph - (let ((image-props (cdr (assq type idlwave-shell-bp-glyph))) - string) - - (if disabled (setq image-props - (append image-props - (list :conversion 'disabled)))) - (setq string - (propertize "@" - 'display - (list (list 'margin 'left-margin) - image-props))) - (overlay-put ov 'before-string string)) - ;; just the face - (overlay-put ov 'face face))) - - ;; use a face - (idlwave-shell-mark-breakpoints - (overlay-put ov 'face face)) - - ;; No marking - (t nil)) - ov)) - -(defun idlwave-shell-mouse-active-bp (ev) - "Does right-click mouse action on breakpoint lines." - (interactive "e") - (if ev (mouse-set-point ev)) - (let ((bp (idlwave-shell-find-bp (idlwave-shell-current-frame))) - index condition count select cmd disabled) - (unless bp - (error "Breakpoint not found")) - (setq index (int-to-string (idlwave-shell-bp-get bp)) - condition (idlwave-shell-bp-get bp 'condition) - cmd (idlwave-shell-bp-get bp 'cmd) - count (idlwave-shell-bp-get bp 'count) - disabled (idlwave-shell-bp-get bp 'disabled)) - (setq select (idlwave-popup-select - ev - (delq nil - (list (if disabled "Enable" "Disable") - "Clear" - "Clear All" - (if condition "Remove Condition" "Add Condition") - (if condition "Change Condition") - (if count "Remove Repeat Count" - "Add Repeat Count") - (if count "Change Repeat Count"))) - (concat "BreakPoint " index))) - (if select - (cond - ((string-equal select "Clear All") - (idlwave-shell-clear-all-bp)) - ((string-equal select "Clear") - (idlwave-shell-clear-current-bp)) - ((string-match "Condition" select) - (idlwave-shell-break-here count cmd - (if (or (not condition) - (string-match "Change" select)) - (read-string "Break Condition: ")) - disabled)) - ((string-match "Count" select) - (idlwave-shell-break-here (if (or (not count) - (string-match "Change" select)) - (string-to-number - (read-string "Break After Count: "))) - cmd condition disabled)) - ((string-match "able$" select) - (idlwave-shell-toggle-enable-current-bp)) - (t - (message "Unimplemented: %s" select)))))) - -(defun idlwave-shell-edit-default-command-line () - "Edit the current execute command." - (interactive) - (setq idlwave-shell-command-line-to-execute - (read-string "IDL> " idlwave-shell-command-line-to-execute))) - -(defun idlwave-shell-execute-default-command-line (arg) - "Execute a command line. On first use, ask for the command. -Also with prefix arg, ask for the command. You can also use the command -`idlwave-shell-edit-default-command-line' to edit the line." - (interactive "P") - (cond - ((equal arg '(16)) - (setq idlwave-shell-command-line-to-execute nil)) - ((equal arg '(4)) - (setq idlwave-shell-command-line-to-execute - (read-string "IDL> " idlwave-shell-command-line-to-execute)))) - (idlwave-shell-reset 'hidden) - (idlwave-shell-send-command - (or idlwave-shell-command-line-to-execute - (with-current-buffer (idlwave-shell-buffer) - (ring-ref comint-input-ring 0))) - '(idlwave-shell-redisplay 'hide))) - -(defun idlwave-shell-save-and-run () - "Save file and run it in IDL. -Runs `save-buffer' and sends a '.RUN' command for the associated file to IDL. -When called from the shell buffer, re-run the file which was last handled by -one of the save-and-.. commands." - (interactive) - (idlwave-shell-save-and-action 'run)) - -(defun idlwave-shell-save-and-compile () - "Save file and run it in IDL. -Runs `save-buffer' and sends '.COMPILE' command for the associated file to IDL. -When called from the shell buffer, re-compile the file which was last handled by -one of the save-and-.. commands." - (interactive) - (idlwave-shell-save-and-action 'compile)) - -(defun idlwave-shell-save-and-batch () - "Save file and batch it in IDL. -Runs `save-buffer' and sends a '@file' command for the associated file to IDL. -When called from the shell buffer, re-batch the file which was last handled by -one of the save-and-.. commands." - (interactive) - (idlwave-shell-save-and-action 'batch)) - -(defun idlwave-shell-save-and-action (action) - "Save file and compile it in IDL. -Runs `save-buffer' and sends a '.RUN' command for the associated file to IDL. -When called from the shell buffer, re-compile the file which was last -handled by this command." - ;; Remove the stop overlay. - (if idlwave-shell-stop-line-overlay - (delete-overlay idlwave-shell-stop-line-overlay)) - (if idlwave-shell-is-stopped - (idlwave-shell-electric-debug-all-off)) - (setq idlwave-shell-is-stopped nil) - (setq overlay-arrow-string nil) - (let (buf) - (cond - ((derived-mode-p 'idlwave-mode) - (save-buffer) - (setq idlwave-shell-last-save-and-action-file (buffer-file-name))) - (idlwave-shell-last-save-and-action-file - (if (setq buf (find-buffer-visiting - idlwave-shell-last-save-and-action-file)) - (with-current-buffer buf - (save-buffer)))) - (t (setq idlwave-shell-last-save-and-action-file - (read-file-name "File: "))))) - (if (file-regular-p idlwave-shell-last-save-and-action-file) - (progn - (idlwave-shell-send-command - (concat (cond ((eq action 'run) ".run ") - ((eq action 'compile) ".compile ") - ((eq action 'batch) "@") - (t (error "Unknown action %s" action))) - "\"" - idlwave-shell-last-save-and-action-file - "\"") - `(idlwave-shell-maybe-update-routine-info nil - ,idlwave-shell-last-save-and-action-file) - (if (idlwave-shell-hide-p 'run) 'mostly) nil t) - (idlwave-shell-bp-query)) - (let ((msg (format "No such file %s" - idlwave-shell-last-save-and-action-file))) - (setq idlwave-shell-last-save-and-action-file nil) - (error msg)))) - -(defun idlwave-shell-maybe-update-routine-info (&optional wait file) - "Update the routine info if the shell is not stopped at an error." - (if (and (not idlwave-shell-is-stopped) - (or (eq t idlwave-auto-routine-info-updates) - (memq 'compile-buffer idlwave-auto-routine-info-updates)) - idlwave-query-shell-for-routine-info - idlwave-routines) - (idlwave-shell-update-routine-info t nil wait file))) - -(defvar idlwave-shell-sources-query "help,/source,/full" - "IDL command to obtain source files for compiled procedures.") - -(defvar idlwave-shell-sources-alist nil - "Alist of IDL procedure names and compiled source files. -Elements of the alist have the form: - - (module name . (source-file-truename idlwave-internal-filename))") - -(defun idlwave-shell-module-source-query (module &optional type) - "Determine the source file for a given module. -Query as a function if TYPE set to something beside `pro'." - (if module - (idlwave-shell-send-command - (format "print,(routine_info('%s',/SOURCE%s)).PATH" module - (if (eq type 'pro) "" ",/FUNCTIONS")) - `(idlwave-shell-module-source-filter ,module) - 'hide 'wait))) - -(defun idlwave-shell-module-source-filter (module) - "Get module source, and update `idlwave-shell-sources-alist'." - (let ((old (assoc (upcase module) idlwave-shell-sources-alist)) - filename) - (when (string-match ".PATH *[\n\r]\\([^%][^\r\n]+\\)[\n\r]" - idlwave-shell-command-output) - (setq filename (substring idlwave-shell-command-output - (match-beginning 1) (match-end 1))) - (if old - (setcdr old (list (idlwave-shell-file-name filename) filename)) - (setq idlwave-shell-sources-alist - (append idlwave-shell-sources-alist - (list (cons (upcase module) - (list (idlwave-shell-file-name filename) - filename))))))))) - -(defun idlwave-shell-sources-query () - "Determine source files for all IDL compiled procedures. -Queries IDL using the string in `idlwave-shell-sources-query'." - (interactive) - (idlwave-shell-send-command idlwave-shell-sources-query - 'idlwave-shell-sources-filter - 'hide)) - -(defun idlwave-shell-sources-filter () - "Get source files from `idlwave-shell-sources-query' output. -Create `idlwave-shell-sources-alist' consisting of list elements -of the form: - (module name . (source-file-truename idlwave-internal-filename))" - (with-current-buffer (get-buffer-create idlwave-shell-bp-buffer) - (erase-buffer) - (insert idlwave-shell-command-output) - (goto-char (point-min)) - (let (cpro cfun) - (if (re-search-forward "Compiled Procedures:" nil t) - (progn - (forward-line) ; Skip $MAIN$ - (setq cpro (point)))) - (if (re-search-forward "Compiled Functions:" nil t) - (progn - (setq cfun (point)) - (setq idlwave-shell-sources-alist - (append - ;; compiled procedures - (progn - (narrow-to-region cpro (line-beginning-position)) - (goto-char (point-min)) - (idlwave-shell-sources-grep)) - ;; compiled functions - (progn - (widen) - (goto-char cfun) - (idlwave-shell-sources-grep))))))))) - -(defun idlwave-shell-sources-grep () - (save-excursion - (let ((al (list nil))) - (while (and - (not (progn (forward-line) (eobp))) - (re-search-forward - "\\s-*\\(\\S-+\\)\\s-+\\(\\S-+\\)" nil t)) - (nconc al - (list - (cons - (buffer-substring ; name - (match-beginning 1) (match-end 1)) - (let ((internal-filename - (buffer-substring ; source - (match-beginning 2) (match-end 2)))) - (list - (idlwave-shell-file-name internal-filename) - internal-filename)) - )))) - (cdr al)))) - -(defun idlwave-shell-clear-all-bp () - "Remove all breakpoints in IDL." - (interactive) - (idlwave-shell-send-command - idlwave-shell-bp-query - '(progn - (idlwave-shell-filter-bp) - (mapcar (lambda (x) (idlwave-shell-clear-bp x 'no-query)) - idlwave-shell-bp-alist) - (idlwave-shell-bp-query)) - 'hide)) - -(defun idlwave-shell-list-all-bp () - "List all breakpoints in IDL." - (interactive) - (idlwave-shell-send-command - idlwave-shell-bp-query)) - -(defvar idlwave-shell-error-last 0 - "Position of last syntax error in `idlwave-shell-error-buffer'.") - -(defun idlwave-shell-goto-next-error () - "Move point to next IDL syntax error." - (interactive) - (let (frame col) - (with-current-buffer idlwave-shell-error-buffer - (goto-char idlwave-shell-error-last) - (if (or - (re-search-forward idlwave-shell-syntax-error nil t) - (re-search-forward idlwave-shell-other-error nil t)) - (progn - (setq frame - (list - (save-match-data - (idlwave-shell-file-name - (buffer-substring (match-beginning 1 ) - (match-end 1)))) - (string-to-number - (buffer-substring (match-beginning 2) - (match-end 2))))) - ;; Try to find the column of the error - (save-excursion - (setq col - (if (re-search-backward "\\^" nil t) - (current-column) - 0))))) - (setq idlwave-shell-error-last (point))) - (if frame - (progn - (idlwave-shell-display-line frame col 'disable)) - (beep) - (message "No more errors.")))) - -(defun idlwave-shell-file-name (name) - "If `idlwave-shell-use-truename' is non-nil, convert file name to true name. -Otherwise, just expand the file name." - (let ((def-dir (if (derived-mode-p 'idlwave-shell-mode) - default-directory - idlwave-shell-default-directory))) - (if idlwave-shell-use-truename - (file-truename name def-dir) - (expand-file-name name def-dir)))) - -;; Keybindings ------------------------------------------------------------ - -(defvar idlwave-shell-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map comint-mode-map) - - ;;(define-key map "\M-?" 'comint-dynamic-list-completions) - ;;(define-key map "\t" 'comint-dynamic-complete) - - (define-key map "\C-w" #'comint-kill-region) - (define-key map "\t" #'idlwave-shell-complete) - (define-key map "\M-\t" #'idlwave-shell-complete) - (define-key map "\C-c\C-s" #'idlwave-shell) - (define-key map "\C-c?" #'idlwave-routine-info) - (define-key map "\C-g" #'idlwave-keyboard-quit) - (define-key map "\M-?" #'idlwave-context-help) - (define-key map [(control meta ?\?)] - #'idlwave-help-assistant-help-with-topic) - (define-key map "\C-c\C-i" #'idlwave-update-routine-info) - (define-key map "\C-c\C-y" #'idlwave-shell-char-mode-loop) - (define-key map "\C-c\C-x" #'idlwave-shell-send-char) - (define-key map "\C-c=" #'idlwave-resolve) - (define-key map "\C-c\C-v" #'idlwave-find-module) - (define-key map "\C-c\C-k" #'idlwave-kill-autoloaded-buffers) - (define-key map idlwave-shell-prefix-key - #'idlwave-shell-debug-map) - (define-key map [(up)] #'idlwave-shell-up-or-history) - (define-key map [(down)] #'idlwave-shell-down-or-history) - (define-key idlwave-shell-mode-map [(shift mouse-3)] - #'idlwave-mouse-context-help) - map) - "Keymap for `idlwave-mode'.") - -(defvar idlwave-shell-electric-debug-mode-map - (let ((map (make-sparse-keymap))) - ;; A few extras in the electric debug map - (define-key map " " #'idlwave-shell-step) - (define-key map "+" #'idlwave-shell-stack-up) - (define-key map "=" #'idlwave-shell-stack-up) - (define-key map "-" #'idlwave-shell-stack-down) - (define-key map "_" #'idlwave-shell-stack-down) - (define-key map "e" (lambda () (interactive) (idlwave-shell-print '(16)))) - (define-key map "q" #'idlwave-shell-retall) - (define-key map "t" - (lambda () (interactive) (idlwave-shell-send-command "help,/TRACE"))) - (define-key map [(control ??)] #'idlwave-shell-electric-debug-help) - (define-key map "x" - (lambda (arg) (interactive "P") - (idlwave-shell-print arg nil nil t))) - map)) - -(defvar idlwave-shell-mode-prefix-map (make-sparse-keymap)) -(defalias 'idlwave-shell-mode-prefix-map idlwave-shell-mode-prefix-map) -(defvar idlwave-mode-prefix-map (make-sparse-keymap)) -(defalias 'idlwave-mode-prefix-map idlwave-mode-prefix-map) - -(defun idlwave-shell-define-key-both (key hook) - "Define a key in both the shell and buffer mode maps." - (define-key idlwave-mode-map key hook) - (define-key idlwave-shell-mode-map key hook)) -(define-key idlwave-mode-map "\C-c\C-y" #'idlwave-shell-char-mode-loop) -(define-key idlwave-mode-map "\C-c\C-x" #'idlwave-shell-send-char) - -;; The mouse bindings for PRINT and HELP -(idlwave-shell-define-key-both [(shift down-mouse-2)] - #'idlwave-shell-mouse-print) -(idlwave-shell-define-key-both [(control meta down-mouse-2)] - #'idlwave-shell-mouse-help) -(idlwave-shell-define-key-both [(control shift down-mouse-2)] - #'idlwave-shell-examine-select) - -;; We need to turn off the button release events. - -(idlwave-shell-define-key-both [(shift mouse-2)] #'ignore) -(idlwave-shell-define-key-both [(shift control mouse-2)] #'ignore) -(idlwave-shell-define-key-both [(control meta mouse-2)] #'ignore) - - -;; The following set of bindings is used to bind the debugging keys. -;; If `idlwave-shell-activate-prefix-keybindings' is non-nil, the -;; first key in the list gets bound the C-c C-d prefix map. If -;; `idlwave-shell-debug-modifiers' is non-nil, the second key in the -;; list gets bound with the specified modifiers in both -;; `idlwave-mode-map' and `idlwave-shell-mode-map'. The next list -;; item, if non-nil, means to bind this as a single key in the -;; electric-debug-mode-map. -;; -;; [C-c C-d]-binding debug-modifier-key command bind-electric-debug buf-only -;; Used keys: abcdef hijklmnopqrstuvwxyz -;; Unused keys: g -(let* ((specs - '(([(control ?b)] ?b idlwave-shell-break-here t t) - ([(control ?i)] ?i idlwave-shell-break-in t t) - ([(control ?j)] ?j idlwave-shell-break-this-module t t) - ([(control ?d)] ?d idlwave-shell-clear-current-bp t) - ([(control ?a)] ?a idlwave-shell-clear-all-bp t) - ([(control ?\\)] ?\\ idlwave-shell-toggle-enable-current-bp t) - ([(control ?s)] ?s idlwave-shell-step t) - ([(control ?n)] ?n idlwave-shell-stepover t) - ([(control ?k)] ?k idlwave-shell-skip t) - ([(control ?u)] ?u idlwave-shell-up t) - ([(control ?o)] ?o idlwave-shell-out t) - ([(control ?m)] ?m idlwave-shell-return t) - ([(control ?h)] ?h idlwave-shell-to-here t t) - ([(control ?r)] ?r idlwave-shell-cont t) - ([(control ?y)] ?y idlwave-shell-execute-default-command-line) - ([(control ?z)] ?z idlwave-shell-reset t) - ([(control ?q)] ?q idlwave-shell-quit) - ([(control ?p)] ?p idlwave-shell-print t) - ([( ??)] ?? idlwave-shell-help-expression t) - ([(control ?v)] ?v idlwave-shell-toggle-electric-debug-mode t t) - ([(control ?x)] ?x idlwave-shell-goto-next-error) - ([(control ?c)] ?c idlwave-shell-save-and-run t) - ([( ?@)] ?@ idlwave-shell-save-and-batch) - ([(control ?e)] ?e idlwave-shell-run-region) - ([(control ?w)] ?w idlwave-shell-resync-dirs) - ([(control ?l)] ?l idlwave-shell-redisplay t) - ([(control ?t)] ?t idlwave-shell-toggle-toolbar) - ([(control up)] up idlwave-shell-stack-up) - ([(control down)] down idlwave-shell-stack-down) - ([( ?\[)] ?\[ idlwave-shell-goto-previous-bp t t) - ([( ?\])] ?\] idlwave-shell-goto-next-bp t t) - ([(control ?f)] ?f idlwave-shell-window))) - (mod (and (listp idlwave-shell-debug-modifiers) - idlwave-shell-debug-modifiers)) - (shift (memq 'shift mod)) - (mod-noshift (delete 'shift (copy-sequence mod))) - s k1 c2 k2 cmd electric only-buffer cannotshift) - (while (setq s (pop specs)) - (setq k1 (nth 0 s) - c2 (nth 1 s) - cmd (nth 2 s) - electric (nth 3 s) - only-buffer (nth 4 s) - cannotshift (and shift (characterp c2) (eq c2 (upcase c2)))) - - ;; The regular prefix keymap. - (when (and idlwave-shell-activate-prefix-keybindings k1) - (unless only-buffer - (define-key idlwave-shell-mode-prefix-map k1 cmd)) - (define-key idlwave-mode-prefix-map k1 cmd)) - ;; The debug modifier map - (when (and mod window-system) - (if (char-or-string-p c2) - (setq k2 (vector (append mod-noshift - (list (if shift (upcase c2) c2))))) - (setq k2 (vector (append mod (list c2))))) - (unless cannotshift - (define-key idlwave-mode-map k2 cmd) - (unless only-buffer (define-key idlwave-shell-mode-map k2 cmd)))) - ;; The electric debug single-keystroke map - (if (and electric (char-or-string-p c2)) - (define-key idlwave-shell-electric-debug-mode-map (char-to-string c2) - cmd)))) - -; Enter the prefix map in two places. -(defalias 'idlwave-debug-map idlwave-mode-prefix-map) -(defalias 'idlwave-shell-debug-map idlwave-shell-mode-prefix-map) - -;; The Electric Debug Minor Mode -------------------------------------------- - -(defun idlwave-shell-toggle-electric-debug-mode () - "Toggle electric-debug-mode, suppressing re-entry into mode if turned off." - (interactive) - ;; If turning it off, make sure it stays off throughout the debug - ;; session until we return or hit $MAIN$. Cancel this suppression - ;; if it's explicitly turned on. - (if idlwave-shell-electric-debug-mode - (progn ;; Turn it off, and make sure it stays off. - (setq idlwave-shell-suppress-electric-debug t) - (idlwave-shell-electric-debug-mode 0)) - (setq idlwave-shell-suppress-electric-debug nil) - (idlwave-shell-electric-debug-mode t))) - -(defvar idlwave-shell-electric-debug-read-only) -(defvar idlwave-shell-electric-debug-buffers nil) - -(define-minor-mode idlwave-shell-electric-debug-mode - "Toggle Idlwave Shell Electric Debug mode. - -When Idlwave Shell Electric Debug mode is enabled, the Idlwave -Shell debugging commands are available as single key sequences." - :lighter " *Debugging*" - (cond - (idlwave-shell-electric-debug-mode - (set (make-local-variable 'idlwave-shell-electric-debug-read-only) - buffer-read-only) - (setq buffer-read-only t) - (add-to-list 'idlwave-shell-electric-debug-buffers (current-buffer)) - (if idlwave-shell-stop-line-overlay - (overlay-put idlwave-shell-stop-line-overlay 'face - idlwave-shell-electric-stop-line-face)) - (if (facep 'fringe) - (set-face-foreground 'fringe idlwave-shell-electric-stop-color - (selected-frame))) - (message - "Electric Debugging mode entered. Press [C-?] for help, [q] to quit")) - (t - ;; Return to previous read-only state - (setq buffer-read-only (if (boundp 'idlwave-shell-electric-debug-read-only) - idlwave-shell-electric-debug-read-only)) - (setq idlwave-shell-electric-debug-buffers - (delq (current-buffer) idlwave-shell-electric-debug-buffers)) - (if idlwave-shell-stop-line-overlay - (overlay-put idlwave-shell-stop-line-overlay 'face - idlwave-shell-stop-line-face) - (if (facep 'fringe) - (set-face-foreground 'fringe (face-foreground 'default))))))) - -;; Turn it off in all relevant buffers -(defvar idlwave-shell-electric-debug-buffers nil) -(defun idlwave-shell-electric-debug-all-off () - (setq idlwave-shell-suppress-electric-debug nil) - (let ((buffers idlwave-shell-electric-debug-buffers) - buf) - (save-excursion - (while (setq buf (pop buffers)) - (when (buffer-live-p buf) - (set-buffer buf) - (when (and (derived-mode-p 'idlwave-mode) - buffer-file-name - idlwave-shell-electric-debug-mode) - (idlwave-shell-electric-debug-mode 0)))))) - (setq idlwave-shell-electric-debug-buffers nil)) - -;; Show the help text -(defun idlwave-shell-electric-debug-help () - (interactive) - (with-output-to-temp-buffer "*IDLWAVE Electric Debug Help*" - (princ idlwave-shell-electric-debug-help)) - (let* ((current-window (selected-window)) - (window (get-buffer-window "*IDLWAVE Electric Debug Help*")) - (window-lines (window-height window))) - (select-window window) - (enlarge-window (1+ (- (count-lines 1 (point-max)) window-lines))) - (select-window current-window))) - - -;; The Menus -------------------------------------------------------------- -(defvar idlwave-shell-menu-def - `("Debug" - ["Electric Debug Mode" - idlwave-shell-electric-debug-mode - :style toggle :selected idlwave-shell-electric-debug-mode - :included (derived-mode-p 'idlwave-mode) :keys "C-c C-d C-v"] - "--" - ("Compile & Run" - ["Save and .RUN" idlwave-shell-save-and-run - (or (derived-mode-p 'idlwave-mode) - idlwave-shell-last-save-and-action-file)] - ["Save and .COMPILE" idlwave-shell-save-and-compile - (or (derived-mode-p 'idlwave-mode) - idlwave-shell-last-save-and-action-file)] - ["Save and @Batch" idlwave-shell-save-and-batch - (or (derived-mode-p 'idlwave-mode) - idlwave-shell-last-save-and-action-file)] - "--" - ["Goto Next Error" idlwave-shell-goto-next-error t] - "--" - ["Compile and Run Region" idlwave-shell-run-region - (derived-mode-p 'idlwave-mode)] - ["Evaluate Region" idlwave-shell-evaluate-region - (derived-mode-p 'idlwave-mode)] - "--" - ["Execute Default Cmd" idlwave-shell-execute-default-command-line t] - ["Edit Default Cmd" idlwave-shell-edit-default-command-line t]) - ("Breakpoints" - ["Set Breakpoint" idlwave-shell-break-here - :keys "C-c C-d C-b" :active (derived-mode-p 'idlwave-mode)] - ("Set Special Breakpoint" - ["Set After Count Breakpoint" - (progn - (let ((count (string-to-number (read-string "Break after count: ")))) - (if (integerp count) (idlwave-shell-break-here count)))) - :active (derived-mode-p 'idlwave-mode)] - ["Set Condition Breakpoint" - (idlwave-shell-break-here '(4)) - :active (derived-mode-p 'idlwave-mode)]) - ["Break in Module" idlwave-shell-break-in - :keys "C-c C-d C-i" :active (derived-mode-p 'idlwave-mode)] - ["Break in this Module" idlwave-shell-break-this-module - :keys "C-c C-d C-j" :active (derived-mode-p 'idlwave-mode)] - ["Clear Breakpoint" idlwave-shell-clear-current-bp t] - ["Clear All Breakpoints" idlwave-shell-clear-all-bp t] - ["Disable/Enable Breakpoint" idlwave-shell-toggle-enable-current-bp t] - ["Goto Previous Breakpoint" idlwave-shell-goto-previous-bp - :keys "C-c C-d [" :active (derived-mode-p 'idlwave-mode)] - ["Goto Next Breakpoint" idlwave-shell-goto-next-bp - :keys "C-c C-d ]" :active (derived-mode-p 'idlwave-mode)] - ["List All Breakpoints" idlwave-shell-list-all-bp t] - ["Resync Breakpoints" idlwave-shell-bp-query t]) - ("Continue/Step" - ["Step (into)" idlwave-shell-step t] - ["Step (over)" idlwave-shell-stepover t] - ["Skip One Statement" idlwave-shell-skip t] - ["Continue" idlwave-shell-cont t] - ["... to End of Block" idlwave-shell-up t] - ["... to End of Subprog" idlwave-shell-return t] - ["... to End of Subprog+1" idlwave-shell-out t] - ["... to Here (Cursor Line)" idlwave-shell-to-here - :keys "C-c C-d C-h" :active (derived-mode-p 'idlwave-mode)]) - ("Examine Expressions" - ["Print expression" idlwave-shell-print t] - ["Help on expression" idlwave-shell-help-expression t] - ("Examine nearby expression with" - ,@(mapcar (lambda(x) - `[ ,(car x) (idlwave-shell-print nil ',x) t ]) - idlwave-shell-examine-alist)) - ("Examine region with" - ,@(mapcar (lambda(x) - `[ ,(car x) (idlwave-shell-print '(4) ',x) t ]) - idlwave-shell-examine-alist))) - ("Call Stack" - ["Stack Up" idlwave-shell-stack-up t] - ["Stack Down" idlwave-shell-stack-down t] - "--" - ["Redisplay and Sync" idlwave-shell-redisplay t]) - ("Show Commands" - ["Everything" (if (eq idlwave-shell-show-commands 'everything) - (progn - (setq idlwave-shell-show-commands - (get 'idlwave-shell-show-commands 'last-val)) - (put 'idlwave-shell-show-commands 'last-val nil)) - (put 'idlwave-shell-show-commands 'last-val - idlwave-shell-show-commands) - (setq idlwave-shell-show-commands 'everything)) - :style toggle :selected (and (not (listp idlwave-shell-show-commands)) - (eq idlwave-shell-show-commands - 'everything))] - "--" - ["Compiling Commands" (idlwave-shell-add-or-remove-show 'run) - :style toggle - :selected (not (idlwave-shell-hide-p - 'run - (get 'idlwave-shell-show-commands 'last-val))) - :active (not (eq idlwave-shell-show-commands 'everything))] - ["Breakpoint Commands" (idlwave-shell-add-or-remove-show 'breakpoint) - :style toggle - :selected (not (idlwave-shell-hide-p - 'breakpoint - (get 'idlwave-shell-show-commands 'last-val))) - :active (not (eq idlwave-shell-show-commands 'everything))] - ["Debug Commands" (idlwave-shell-add-or-remove-show 'debug) - :style toggle - :selected (not (idlwave-shell-hide-p - 'debug - (get 'idlwave-shell-show-commands 'last-val))) - :active (not (eq idlwave-shell-show-commands 'everything))] - ["Miscellaneous Commands" (idlwave-shell-add-or-remove-show 'misc) - :style toggle - :selected (not (idlwave-shell-hide-p - 'misc - (get 'idlwave-shell-show-commands 'last-val))) - :active (not (eq idlwave-shell-show-commands 'everything))]) - ("Input Mode" - ["Send one char" idlwave-shell-send-char t] - ["Temporary Character Mode" idlwave-shell-char-mode-loop t] - "--" - ["Use Input Mode Magic" - (setq idlwave-shell-use-input-mode-magic - (not idlwave-shell-use-input-mode-magic)) - :style toggle :selected idlwave-shell-use-input-mode-magic]) - "--" - ["Update Working Dir" idlwave-shell-resync-dirs t] - ["Save Path Info" - (idlwave-shell-send-command idlwave-shell-path-query - 'idlwave-shell-get-path-info - 'hide) - t] - ["Reset IDL" idlwave-shell-reset t] - "--" - ["Toggle Toolbar" idlwave-shell-toggle-toolbar t] - ["Exit IDL" idlwave-shell-quit t])) - -(easy-menu-define idlwave-mode-debug-menu idlwave-mode-map - "IDL debugging menus." - idlwave-shell-menu-def) -(easy-menu-define idlwave-shell-mode-menu idlwave-shell-mode-map - "IDL shell menus." - idlwave-shell-menu-def) - -;; The Breakpoint Glyph ------------------------------------------------------- - -(defvar idlwave-shell-bp-glyph nil - "The glyphs to mark breakpoint lines in the source code.") - -(let ((image-alist - '((bp . "/* XPM */ -static char * file[] = { -\"14 12 3 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"R c #FFFF00000000\", -\" \", -\" .... \", -\" .RRRR. \", -\" .RRRRRR. \", -\" .RRRRRRRR. \", -\" .RRRRRRRR. \", -\" .RRRRRRRR. \", -\" .RRRRRRRR. \", -\" .RRRRRR. \", -\" .RRRR. \", -\" .... \", -\" \"};") - (bp-cond . "/* XPM */ -static char * file[] = { -\"14 12 4 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"R c #FFFF00000000\", -\"B c #000000000000\", -\" \", -\" .... \", -\" .RRRR. \", -\" .RRRRRR. \", -\" .RRRRRRRR. \", -\" .RRBBBBRR. \", -\" .RRRRRRRR. \", -\" .RRBBBBRR. \", -\" .RRRRRR. \", -\" .RRRR. \", -\" .... \", -\" \"};") - (bp-1 . "/* XPM */ -static char * file[] = { -\"14 12 4 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"X c #FFFF00000000\", -\"o c #000000000000\", -\" \", -\" .... \", -\" .XXXX. \", -\" .XXooXX. \", -\" .XXoooXXX. \", -\" .XXXooXXX. \", -\" .XXXooXXX. \", -\" .XXooooXX. \", -\" .XooooX. \", -\" .XXXX. \", -\" .... \", -\" \"};") - (bp-2 . "/* XPM */ -static char * file[] = { -\"14 12 4 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"X c #FFFF00000000\", -\"o c #000000000000\", -\" \", -\" .... \", -\" .XXXX. \", -\" .XoooXX. \", -\" .XXoXooXX. \", -\" .XXXXooXX. \", -\" .XXXooXXX. \", -\" .XXooXXXX. \", -\" .XooooX. \", -\" .XXXX. \", -\" .... \", -\" \"};") - (bp-3 . "/* XPM */ -static char * file[] = { -\"14 12 4 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"X c #FFFF00000000\", -\"o c #000000000000\", -\" \", -\" .... \", -\" .XXXX. \", -\" .XoooXX. \", -\" .XXXXooXX. \", -\" .XXXooXXX. \", -\" .XXXXooXX. \", -\" .XXoXooXX. \", -\" .XoooXX. \", -\" .XXXX. \", -\" .... \", -\" \"};") - (bp-4 . "/* XPM */ -static char * file[] = { -\"14 12 4 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"X c #FFFF00000000\", -\"o c #000000000000\", -\" \", -\" .... \", -\" .XXXX. \", -\" .XoXXoX. \", -\" .XXoXXoXX. \", -\" .XXooooXX. \", -\" .XXXXooXX. \", -\" .XXXXooXX. \", -\" .XXXooX. \", -\" .XXXX. \", -\" .... \", -\" \"};") - (bp-n . "/* XPM */ -static char * file[] = { -\"14 12 4 1\", -\" c None s backgroundColor\", -\". c #4B4B4B4B4B4B\", -\"X c #FFFF00000000\", -\"o c #000000000000\", -\" \", -\" .... \", -\" .XXXX. \", -\" .XXXXXX. \", -\" .XXoXoXXX. \", -\" .XXooXoXX. \", -\" .XXoXXoXX. \", -\" .XXoXXoXX. \", -\" .XoXXoX. \", -\" .XXXX. \", -\" .... \", -\" \"};"))) im-cons im) - - (while (setq im-cons (pop image-alist)) - (setq im (cond ((and (fboundp 'image-type-available-p) - (image-type-available-p 'xpm)) - (list 'image :type 'xpm :data (cdr im-cons) - :ascent 'center)) - (t nil))) - (if im (push (cons (car im-cons) im) idlwave-shell-bp-glyph)))) - -(provide 'idlw-shell) -(provide 'idlwave-shell) - -;; Load the toolbar when wanted by the user. - -(autoload 'idlwave-toolbar-toggle "idlw-toolbar" - "Toggle the IDLWAVE toolbar.") -(autoload 'idlwave-toolbar-add-everywhere "idlw-toolbar" - "Add IDLWAVE toolbar.") -(defun idlwave-shell-toggle-toolbar () - "Toggle the display of the debugging toolbar." - (interactive) - (idlwave-toolbar-toggle)) - -(if idlwave-shell-use-toolbar - (add-hook 'idlwave-shell-mode-hook #'idlwave-toolbar-add-everywhere)) - -;;; idlw-shell.el ends here diff --git a/lisp/progmodes/idlw-toolbar.el b/lisp/progmodes/idlw-toolbar.el deleted file mode 100644 index c6cb47baa40..00000000000 --- a/lisp/progmodes/idlw-toolbar.el +++ /dev/null @@ -1,931 +0,0 @@ -;;; idlw-toolbar.el --- a debugging toolbar for IDLWAVE -*- lexical-binding: t; -*- - -;; Copyright (C) 1999-2024 Free Software Foundation, Inc. - -;; Author: Carsten Dominik -;; Maintainer: emacs-devel@gnu.org -;; Keywords: processes -;; Package: idlwave - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This file implements a debugging toolbar for IDLWAVE. -;; It requires toolbar and xpm support. - -;; New versions of IDLWAVE, documentation, and more information -;; available from: -;; https://github.com/jdtsmith/idlwave - - -;;; Code: - -(defun idlwave-toolbar-make-button (image) - (list 'image :type 'xpm :data image)) - -(defvar idlwave-toolbar) -(defvar default-toolbar) -(defvar idlwave-toolbar-is-possible) - -(if (not (and (boundp 'tool-bar-button-margin) ; need toolbar - (fboundp 'image-type-available-p) ; need image stuff - (image-type-available-p 'xpm)) ; need xpm - ) - ;; oops - cannot do the toolbar - (message "Sorry, IDLWAVE xpm toolbar cannot be used on this version of Emacs") -;; OK, we can define a toolbar - -(defconst idlwave-toolbar-is-possible t - "When defined, indicates that a toolbar is possible with this Emacs.") -(defvar idlwave-toolbar-compile-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 2 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\" \", -\" \", -\" \", -\" . \", -\" .. ... .. \", -\" .... ... .... \", -\" ............. \", -\" ........... \", -\" ................... \", -\" ........ ........ \", -\" ..... ........ \", -\" .... ......... \", -\" ..... .. ... ..... \", -\" ...... .. .. ...... \", -\" ..... ... .. ..... \", -\" ......... .... \", -\" ........ ..... \", -\" ........ ........ \", -\" ................... \", -\" ........... \", -\" ............. \", -\" .... ... .... \", -\" .. ... .. \", -\" . \", -\" \", -\" \", -\" \", -\" \"};") - "The compile icon.") - -(defvar idlwave-toolbar-next-error-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" R \", -\" RR RRR RR \", -\" RRRR RRR RRRR \", -\" RRRRRRRRRRRRR \", -\" RRRRRRRRRRR \", -\" RRRRRRRRRRRRRRRRRRR \", -\" RRRRRRRR \", -\" RRRRR \", -\" RRRR \", -\" ........ \", -\" ........ \", -\" ......... \", -\" ..... .. ... ..... \", -\" ...... .. .. ...... \", -\" ..... ... .. ..... \", -\" ......... .... \", -\" ........ ..... \", -\" ........ ........ \", -\" ................... \", -\" ........... \", -\" ............. \", -\" .... ... .... \", -\" .. ... .. \", -\" . \", -\" \", -\" \"};") - "The Next Error icon.") - -(defvar idlwave-toolbar-stop-at-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" \", -\" ........ \", -\" .RRRRRRRR. \", -\" .RRRRRRRRRR. \", -\" .RRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRR. \", -\" .RRRRRRRRRR. \", -\" .RRRRRRRR. \", -\" ........ \", -\" \", -\" \", -\" \", -\" \"};") - "The Stop At icon.") - - -(defvar idlwave-toolbar-clear-at-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" ... ... \", -\" ... ........ ... \", -\" ... .RRRRRRRR. ... \", -\" ....RRRRRRRRRR.... \", -\" ...RRRRRRRRRR... \", -\" ....RRRRRRRR.... \", -\" .RR...RRRRRR...RR. \", -\" .RRRR...RRRR...RRRR. \", -\" .RRRRR...RR...RRRRR. \", -\" .RRRRRR......RRRRRR. \", -\" .RRRRRRR....RRRRRRR. \", -\" .RRRRRRR....RRRRRRR. \", -\" .RRRRRR......RRRRRR. \", -\" .RRRRR...RR...RRRRR. \", -\" .RRRR...RRRR...RRRR. \", -\" .RR...RRRRRR...RR. \", -\" ....RRRRRRRR.... \", -\" ...RRRRRRRRRR... \", -\" ....RRRRRRRRRR.... \", -\" ... .RRRRRRRR. ... \", -\" ... ........ ... \", -\" ... ... \", -\" \", -\" \", -\" \"};") - "The Clear At icon.") - -(defvar idlwave-toolbar-clear-all-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 4 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"X c #FFFFFFFFFFFF\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" .. .... .... .. \", -\" ...RRRR. .RRRR... \", -\" ...RRRR. .RRRR... \", -\" .R...RRRR. .RRRR...R. \", -\" .RR...RRR. .RRR...RR. \", -\" .RRR...RR. .RR...RRR. \", -\" .RRRR...R. .R...RRRR. \", -\" .RRRR... ...RRRR. \", -\" .RRRR... ...RRRR. \", -\" .... ... ... .... \", -\" ..... \", -\" ... \", -\" .... ..... .... \", -\" .RRRR.... ....RRRR. \", -\" .RRRRR... ...RRRRR. \", -\" .RRRRR.... ....RRRRR. \", -\" .RRRR...R. .R...RRRR. \", -\" .RRR...RR. .RR...RRR. \", -\" .RR...RRR. .RRR...RR. \", -\" ....RRR. .RRR.... \", -\" ...RRR. .RRR... \", -\" ....... ....... \", -\" \", -\" \", -\" \"};") - "The Clear-All icon.") - -(defvar idlwave-toolbar-stop-beginning-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 4 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"X c #FFFF00000000\", -\"_ c #FFFFFFFFFFFF\", -\" \", -\" \", -\" \", -\" \", -\" ........ \", -\" .XXXXXXXX. \", -\" .XXXXXXXXXX. \", -\" .XXXXXXXXXXXX. \", -\" .XX..XXXXXXXXXX. \", -\" .XX.XX.X______XXX. \", -\" .XXX.XX.X______XXXX. \", -\" .XXXX..XXXXXXXXXXXX. \", -\" .XXXXXXXXXX____XXXX. \", -\" .XXXXXXXXXX____XXXX. \", -\" .XXXXXXXXXXXXXXXXXX. \", -\" .XXXXXXXXXX____XXXX. \", -\" .XXXXXXXXXX____XXXX. \", -\" .XXXXXXXXXXXXXXXXXX. \", -\" .XXXXXXXXX____XXX. \", -\" .XXXXXXXX____XX. \", -\" .XXXXXXXXXXXX. \", -\" .XXXXXXXXXX. \", -\" .XXXXXXXX. \", -\" ........ \", -\" \", -\" \", -\" \", -\" \"};") - "The Stop at Beginning icon.") - -(defvar idlwave-toolbar-stop-in-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 4 1\", -\" c None s backgroundToolBarColor\", -\"_ c #FFFFFFFFFFFF\", -\". c #000000000000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" \", -\" ........ \", -\" .RRRRRRRR. \", -\" .RRRRRRRRRR. \", -\" .RRRRRRRRRRRR. \", -\" .RRR___RR___RRR. \", -\" .RRRR__RRRR__RRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRR__RRRRRR__RRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRRR__RRRR__RRRRR. \", -\" .RRRR___RR___RRRR. \", -\" .RRRRRRRRRRRRRR. \", -\" .RRRRRRRRRRRR. \", -\" .RRRRRRRRRR. \", -\" .RRRRRRRR. \", -\" ........ \", -\" \", -\" \", -\" \", -\" \"};") - "The Stop in icon.") - -(defvar idlwave-toolbar-edit-cmd-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 2 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" .. \", -\" .. \", -\" .. \", -\" .. \", -\" .. \", -\" \", -\" \", -\" ................. \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The edit-cmd icon.") - -(defvar idlwave-toolbar-run-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". s FgColor c #000000000000\", -\"G c #0000BBBB0000\", -\" \", -\" \", -\" \", -\" \", -\" ..... \", -\" .GGG. \", -\" .GGG. \", -\" .GGG. ....... \", -\" .GGG. \", -\" .GGG. \", -\" .GGG. ....... \", -\" .GGG. \", -\" ....GGG.... \", -\" .GGGGGGG. ....... \", -\" .GGGGG. \", -\" .GGG. \", -\" .G. ....... \", -\" . \", -\" \", -\" ....... \", -\" \", -\" \", -\" ....... \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Run icon.") - -(defvar idlwave-toolbar-cont-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". s FgColor c #000000000000\", -\"G c #0000BBBB0000\", -\" \", -\" \", -\" \", -\" ....... \", -\" \", -\" ....... \", -\" .GGGGGG. ....... \", -\" .GGGGGGG. \", -\" .GGG..... \", -\" .GGG. ....... \", -\" .GGG. \", -\" .GGG. \", -\" .GGG. ....... \", -\" .GGG. \", -\" ....GGG.... \", -\" .GGGGGGG. ....... \", -\" .GGGGG. \", -\" .GGG. \", -\" .G. ....... \", -\" . \", -\" \", -\" ....... \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Cont icon.") - -(defvar idlwave-toolbar-to-here-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 4 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"G c #0000BBBB0000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" ..... ........ \", -\" .GGGG. \", -\" .GGGGG. \", -\" .GG.... ........ \", -\" .GG. \", -\" .GG. . \", -\" .GG. .. \", -\" .GG. .G. ...... \", -\" .GG...GG. \", -\" .GGGGGGGG. RRRRRR \", -\" .GGGGGGGGG. RRRRRR \", -\" .GGGGGGG. RRRRRR \", -\" ....GG. \", -\" .G. ...... \", -\" .. \", -\" . \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Cont-to-here icon.") - -(defvar idlwave-toolbar-step-over-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"G c #0000BBBB0000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" ..... \", -\" .GGGG. ....... \", -\" .GGGGG. \", -\" .GG.... \", -\" .GG. ....... \", -\" .GG. . \", -\" .GG. .. \", -\" .GG. .G. ....... \", -\" .GG...GG. \", -\" .GGGGGGGG. \", -\" .GGGGGGGGG. ....... \", -\" .GGGGGGG. \", -\" ....GG. \", -\" .G. ....... \", -\" .. \", -\" . \", -\" ....... \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Step Over icon.") - -(defvar idlwave-toolbar-step-into-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"G c #0000BBBB0000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" ..... ....... \", -\" .GGGG. \", -\" .GGGGG. \", -\" .GG.... ........ \", -\" .GG. \", -\" .GG. . \", -\" .GG. .. \", -\" .GG. .G. \", -\" .GG...GG. ....... \", -\" .GGGGGGGG. \", -\" .GGGGGGGGG. \", -\" .GGGGGGG. ....... \", -\" ....GG. \", -\" .G. \", -\" .. ....... \", -\" . \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Step Into icon.") - -(defvar idlwave-toolbar-step-out-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\"G c #0000BBBB0000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" . \", -\" .. ........ \", -\" .G. \", -\" ....GG. \", -\" .GGGGGGG. ........ \", -\" .GGGGGGGGG. \", -\" .GGGGGGGG. \", -\" .GG...GG. ........ \", -\" .GG. .G. \", -\" .GG. .. \", -\" .GG. . \", -\" .GG. \", -\" .GG....... ....... \", -\" .GGGGGGGG. \", -\" .GGGGGGG. \", -\" ........ ....... \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Step up icon.") - - -(defvar idlwave-toolbar-eval-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 2 1\", -\" c None s backgroundToolBarColor\", -\". c #000000000000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" .... \", -\" .. .. ...... \", -\" .. .. ...... \", -\" .. .. \", -\" .. .. ...... \", -\" .. .. ...... \", -\" .... \", -\" .. \", -\" .. \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \", -\" \"};") - "The Evaluate icon.") - -(defvar idlwave-toolbar-stack-up-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 5 1\", -\" c None s backgroundToolBarColor\", -\". s FgColor c #000000000000\", -\"_ c #FFFFFFFFFFFF\", -\"G c #0000BBBB0000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" ........ . \", -\" .______. ... \", -\" .______. ..... \", -\" .______. ....... \", -\" .______. ... \", -\" .______. ... \", -\" ........ ... \", -\" .GGGGGG. ... \", -\" .GGGGGG. ... \", -\" .GGGGGG. \", -\" .GGGGGG. \", -\" .GGGGGG. \", -\" ........ \", -\" .RRRRRR. \", -\" .RRRRRR. \", -\" .RRRRRR. \", -\" .RRRRRR. \", -\" .RRRRRR. \", -\" ........ \", -\" \", -\" \", -\" \", -\" \"};") - "The Stack Up icon.") - -(defvar idlwave-toolbar-stack-down-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 5 1\", -\" c None s backgroundToolBarColor\", -\". s FgColor c #000000000000\", -\"_ c #FFFFFFFFFFFF\", -\"G c #0000BBBB0000\", -\"R c #FFFF00000000\", -\" \", -\" \", -\" \", -\" \", -\" \", -\" ........ \", -\" .______. \", -\" .______. \", -\" .______. \", -\" .______. \", -\" .______. \", -\" ........ \", -\" .GGGGGG. \", -\" .GGGGGG. \", -\" .GGGGGG. \", -\" .GGGGGG. ... \", -\" .GGGGGG. ... \", -\" ........ ... \", -\" .RRRRRR. ... \", -\" .RRRRRR. ... \", -\" .RRRRRR. ....... \", -\" .RRRRRR. ..... \", -\" .RRRRRR. ... \", -\" ........ . \", -\" \", -\" \", -\" \", -\" \"};") - "The Stack Down icon.") - -(defvar idlwave-toolbar-reset-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 3 1\", -\" c None s backgroundToolBarColor\", -\"G c #0000BBBB0000\", -\". c #000000000000\", -\" \", -\" \", -\" \", -\" . \", -\" .G. . \", -\" .GGG.. .G. \", -\" .GGGGG..GG. \", -\" ..GGGGGGGG. \", -\" ..GGGGGG. \", -\" ..GGGGG. \", -\" .GGGGGG. \", -\" .G...... \", -\" \", -\" ..... \", -\" ......... \", -\" ......... \", -\" ......... \", -\" . ..... . \", -\" . . \", -\" . . \", -\" . . \", -\" . . \", -\" . . \", -\" .. .. \", -\" ....... \", -\" ..... \", -\" \", -\" \"};") - "The Reset icon.") - -(defvar idlwave-toolbar-electric-debug-icon - (idlwave-toolbar-make-button - "/* XPM */ -static char * file[] = { -\"28 28 8 1\", -\" c None s backgroundToolBarColor\", -\". c #CFC854\", -\"+ c #EEDB0E\", -\"@ c #D2C739\", -\"# c #A39C54\", -\"$ c #CDC020\", -\"% c #020202\", -\"& c #D60E36\", -\" \", -\" \", -\" .. \", -\" +++++@ \", -\" ++++++ \", -\" +++++@ \", -\" +++++ \", -\" #++++@ \", -\" $+++@ %% %% \", -\" ++++++$ % % \", -\" #+++++$ % % \", -\" #++$# %%% \", -\" #+++ %%%%%%% \", -\" .++ %%%%%%%%%%% \", -\" ++$$ %%%%%%%%%%% \", -\" .+@# &&%%%%%%%&& \", -\" .++++# &&&&&%%%&&&&& \", -\" +++++$ &&%%&&&&&%%&& \", -\" $+++$ &&%%&&&&&%%&& \", -\" $++@ &&&&&&%&&&&&& \", -\" $+@ &&&&&&%&&&&&& \", -\" @+ &&%%&&&&&%%&& \", -\" ++. &%%&&%&&%%& \", -\" +. &&&&%%%&&&& \", -\" .+ &&%%%%%&& \", -\" ++ %%%%%%% \", -\" . %%% \", -\" \"};") - "The electric debug icon.") - -(defvar idlwave-toolbar - '( - [idlwave-toolbar-compile-icon - idlwave-shell-save-and-compile - t - "Save and Compile this file (or recompile last)"] - [idlwave-toolbar-next-error-icon - idlwave-shell-goto-next-error - t - "Goto Next Error"] - [idlwave-toolbar-stop-at-icon - idlwave-shell-break-here - (derived-mode-p 'idlwave-mode) - "Set Breakpoint at selected position"] - [idlwave-toolbar-clear-at-icon - idlwave-shell-clear-current-bp - t - "Clear Breakpoint at selected position"] - [idlwave-toolbar-clear-all-icon - idlwave-shell-clear-all-bp - t - "Clear all Breakpoints"] - [idlwave-toolbar-stop-beginning-icon - idlwave-shell-break-this-module - (derived-mode-p 'idlwave-mode) - "Stop at beginning of enclosing Routine"] - [idlwave-toolbar-stop-in-icon - idlwave-shell-break-in - t - "Stop in Routine with name near point"] - [idlwave-toolbar-edit-cmd-icon - idlwave-shell-edit-default-command-line - t - "Edit Default Command Line"] - [idlwave-toolbar-run-icon - idlwave-shell-execute-default-command-line - t - "Reset, then Execute Default Command Line"] - [idlwave-toolbar-cont-icon - idlwave-shell-cont - t - "Continue Current Program"] - [idlwave-toolbar-to-here-icon - idlwave-shell-to-here - (derived-mode-p 'idlwave-mode) - "Continue to Here (cursor position)"] - [idlwave-toolbar-step-over-icon - idlwave-shell-stepover - t - "Step Over (aka next)"] - [idlwave-toolbar-step-into-icon - idlwave-shell-step - t - "Step Into (aka step)"] - [idlwave-toolbar-step-out-icon - idlwave-shell-out - t - "Step Out (of subroutine)"] - [idlwave-toolbar-eval-icon - idlwave-shell-print - t - "Print Expression at or before Point"] - [idlwave-toolbar-stack-up-icon - idlwave-shell-stack-up - t - "Stack Up (towards \"cooler\" - less recently visited - frames)"] - [idlwave-toolbar-stack-down-icon - idlwave-shell-stack-down - t - "Stack Down (towards \"warmer\" - more recently visited - frames)"] - [idlwave-toolbar-reset-icon - idlwave-shell-reset - t - "Reset IDL (RETALL & CLOSE,/ALL and more)"] - [idlwave-toolbar-electric-debug-icon - idlwave-shell-electric-debug-mode - (derived-mode-p 'idlwave-mode) - "Toggle Electric Debug Mode"] - )) - -;; When the shell exits, arrange to remove the special toolbar everywhere. -(add-hook 'idlwave-shell-cleanup-hook - #'idlwave-toolbar-remove-everywhere) -);; End can define toolbar - -(define-obsolete-function-alias 'idlwave-toolbar-add #'ignore "28.1") - -(define-obsolete-function-alias 'idlwave-toolbar-remove #'ignore "28.1") - -(defvar idlwave-shell-mode-map) -(defvar idlwave-mode-map) -(defvar idlwave-toolbar-visible nil) -(defun idlwave-toolbar-add-everywhere () - "Add the toolbar in all appropriate buffers." - (when (boundp 'idlwave-toolbar-is-possible) - - ;; Then add it to all existing buffers - ;; For Emacs, add the key definitions to the mode maps - (mapc (lambda (x) - (let* ((icon (aref x 0)) - (func (aref x 1)) - (show (aref x 2)) - (help (aref x 3)) - (key (vector 'tool-bar func)) - (def (list 'menu-item - "" - func - :image (symbol-value icon) - :visible show - :help help))) - (define-key idlwave-mode-map key def) - (define-key idlwave-shell-mode-map key def))) - (reverse idlwave-toolbar)) - (setq idlwave-toolbar-visible t))) - -(defun idlwave-toolbar-remove-everywhere () - "Remove the toolbar in all appropriate buffers." - ;; First make sure new buffers won't get the toolbar - (when idlwave-toolbar-is-possible - ;; Then remove it in all existing buffers. - ;; For Emacs, remove the key definitions from the mode maps - (mapc (lambda (x) - (let* (;;(icon (aref x 0)) - (func (aref x 1)) - ;;(show (aref x 2)) - ;;(help (aref x 3)) - (key (vector 'tool-bar func))) - (define-key idlwave-mode-map key nil) - (define-key idlwave-shell-mode-map key nil))) - idlwave-toolbar) - (setq idlwave-toolbar-visible nil))) - -(defun idlwave-toolbar-toggle (&optional force-on) - (interactive) - (if idlwave-toolbar-visible - (or force-on (idlwave-toolbar-remove-everywhere)) - (idlwave-toolbar-add-everywhere)) - ;; On Emacs, redraw the frame to make sure the Toolbar is updated. - (redraw-frame)) - -(provide 'idlw-toolbar) -(provide 'idlwave-toolbar) - -;;; idlw-toolbar.el ends here diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el deleted file mode 100644 index 3628449d8e1..00000000000 --- a/lisp/progmodes/idlwave.el +++ /dev/null @@ -1,9081 +0,0 @@ -;;; idlwave.el --- IDL editing mode for GNU Emacs -*- lexical-binding: t; -*- - -;; Copyright (C) 1999-2024 Free Software Foundation, Inc. - -;; Authors: JD Smith -;; Carsten Dominik -;; Chris Chase -;; Maintainer: emacs-devel@gnu.org -;; Version: 6.1.22 -;; Keywords: languages - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; IDLWAVE enables feature-rich development and interaction with IDL, -;; the Interactive Data Language. It provides a compelling, -;; full-featured alternative to the IDLDE development environment -;; bundled with IDL. - -;; In the remotely distant past, based on pascal.el, though bears -;; little resemblance to it now. -;; -;; Incorporates many ideas, such as abbrevs, action routines, and -;; continuation line indenting, from wave.el. -;; wave.el original written by Lubos Pochman, Precision Visuals, Boulder. -;; -;; See the mode description ("C-h m" in idlwave-mode or "C-h f idlwave-mode") -;; for features, key bindings, and info. -;; Also, Info format documentation is available with `M-x idlwave-info' -;; -;; New versions of IDLWAVE, documentation, and more information -;; available from: -;; https://github.com/jdtsmith/idlwave -;; -;; INSTALLATION -;; ============ -;; -;; Follow the instructions in the INSTALL file of the distribution. -;; In short, put this file on your load path and add the following -;; lines to your init file: -;; -;; (autoload 'idlwave-mode "idlwave" "IDLWAVE Mode" t) -;; (autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t) -;; (setq auto-mode-alist (cons '("\\.pro\\'" . idlwave-mode) auto-mode-alist)) -;; -;; -;; SOURCE -;; ====== -;; -;; The newest version of this file is available from the maintainer's -;; Webpage: -;; -;; https://github.com/jdtsmith/idlwave -;; -;; DOCUMENTATION -;; ============= -;; -;; IDLWAVE is documented online in info format. A printable version -;; of the documentation is available from the maintainers webpage (see -;; SOURCE). -;; -;; -;; ACKNOWLEDGMENTS -;; =============== -;; -;; Thanks to the following people for their contributions and comments: -;; -;; Ulrik Dickow -;; Eric E. Dors -;; Stein Vidar H. Haugan -;; David Huenemoerder -;; Kevin Ivory -;; Dick Jackson -;; Xuyong Liu -;; Simon Marshall -;; Laurent Mugnier -;; Lubos Pochman -;; Bob Portmann -;; Patrick M. Ryan -;; Marty Ryba -;; Paul Sorenson -;; Phil Sterne -;; Phil Williams -;; -;; CUSTOMIZATION: -;; ============= -;; -;; IDLWAVE has extensive customize support; to learn about the -;; variables which control the mode's behavior, use `M-x -;; idlwave-customize'. -;; -;; You can set your own preferred values with Customize, or with Lisp -;; code in .emacs. For an example of what to put into .emacs, check -;; the TexInfo documentation or see a complete .emacs available at the -;; website. -;; -;; KNOWN PROBLEMS: -;; ============== -;; -;; IDLWAVE support for the IDL-derived PV-WAVE CL language of Visual -;; Numerics, Inc. is growing less and less complete as the two -;; languages grow increasingly apart. The mode probably shouldn't -;; even have "WAVE" in its title, but it's catchy, and was required -;; to avoid conflict with the CORBA idl.el mode. Caveat WAVEor. -;; -;; Moving the point backwards in conjunction with abbrev expansion -;; does not work as I would like it, but this is a problem with -;; Emacs abbrev expansion done by the self-insert-command. It ends -;; up inserting the character that expanded the abbrev after moving -;; point backward, e.g., "\cl" expanded with a space becomes -;; "LONG( )" with point before the close paren. This is solved by -;; using a temporary function in `post-command-hook' - not pretty, -;; but it works. -;; -;; Tabs and spaces are treated equally as whitespace when filling a -;; comment paragraph. To accomplish this, tabs are permanently -;; replaced by spaces in the text surrounding the paragraph, which -;; may be an undesirable side-effect. Replacing tabs with spaces is -;; limited to comments only and occurs only when a comment -;; paragraph is filled via `idlwave-fill-paragraph'. -;; -;; Multi-statement lines (using "&") on block begin and end lines can -;; ruin the formatting. For example, multiple end statements on a -;; line: endif & endif. Using "&" outside of block begin/end lines -;; should be okay. -;; -;; Determining the expression at point for printing and other -;; examination commands is somewhat rough: currently only fairly -;; simple entities are found. You can always drag-select or examine -;; a pre-selected region. -;; -;; When forcing completion of method keywords, the initial -;; query for a method has multiple entries for some methods. Would -;; be too difficult to fix this hardly used case. -;; - -;;; Code: - - -(eval-when-compile (require 'cl-lib)) -(require 'idlw-help) - -(declare-function idlwave-shell-get-path-info "idlw-shell") -(declare-function idlwave-shell-temp-file "idlw-shell") -(declare-function idlwave-shell-is-running "idlw-shell") -(declare-function widget-value "wid-edit" (widget)) -(declare-function comint-dynamic-complete-filename "comint" ()) - -(defgroup idlwave nil - "Major mode for editing IDL .pro files." - :tag "IDLWAVE" - :link '(url-link :tag "Website" - "https://github.com/jdtsmith/idlwave") - :link '(emacs-commentary-link :tag "Commentary in idlw-shell.el" - "idlw-shell.el") - :link '(emacs-commentary-link :tag "Commentary in idlwave.el" "idlwave.el") - :link '(custom-manual "(idlwave)Top") - :prefix "idlwave" - :group 'languages) - - -;;; Variables for indentation behavior --------------------------------------- - -(defgroup idlwave-code-formatting nil - "Indentation and formatting options for IDLWAVE mode." - :group 'idlwave) - -(defcustom idlwave-main-block-indent 2 - "Extra indentation for the main block of code. -That is the block between the FUNCTION/PRO statement and the END -statement for that program unit." - :group 'idlwave-code-formatting - :type 'integer) - -(defcustom idlwave-block-indent 3 - "Extra indentation applied to block lines. -If you change this, you probably also want to change `idlwave-end-offset'." - :group 'idlwave-code-formatting - :type 'integer) - -(defcustom idlwave-end-offset -3 - "Extra indentation applied to block END lines. -A value equal to negative `idlwave-block-indent' will make END lines -line up with the block BEGIN lines." - :group 'idlwave-code-formatting - :type 'integer) - -(defcustom idlwave-continuation-indent 3 - "Extra indentation applied to continuation lines. -This extra offset applies to the first of a set of continuation lines. -The following lines receive the same indentation as the first." - :group 'idlwave-code-formatting - :type 'integer) - -(defcustom idlwave-max-extra-continuation-indent 40 - "Maximum additional indentation for special continuation indent. -Several special indentations are tried to help line up continuation -lines in routine calls or definitions, other statements with -parentheses, or assignment statements. This variable specifies a -maximum amount by which this special indentation can exceed the -standard continuation indentation, otherwise defaulting to a fixed -offset. Set to 0 to effectively disable all special continuation -indentation, or to a large number (like 100) to enable it in all -cases. See also `idlwave-indent-to-open-paren', which can override -this variable." - :group 'idlwave-code-formatting - :type 'integer) - -(defcustom idlwave-indent-to-open-paren t - "Non-nil means, indent continuation lines to innermost open parenthesis. -This indentation occurs even if otherwise disallowed by -`idlwave-max-extra-continuation-indent'. Matching parens and the -interleaving args are lined up. Example: - - x = function_a(function_b(function_c( a, b, [1,2,3, $ - 4,5,6 $ - ], $ - c, d $ - ))) - -When this variable is nil, paren alignment may still occur, based on -the value of `idlwave-max-extra-continuation-indent', which, if zero, -would yield: - - x = function_a(function_b(function_c( a, b, [1,2,3, $ - 4,5,6 $ - ], $ - c, d $ - )))" - :group 'idlwave-code-formatting - :type 'boolean) - -(defcustom idlwave-indent-parens-nested nil - "Non-nil means indent continuation lines with parens by nesting -lines at consecutively deeper levels." - :group 'idlwave-code-formatting - :type 'boolean) - - -(defcustom idlwave-hanging-indent t - "If set non-nil then comment paragraphs are indented under the -hanging indent given by `idlwave-hang-indent-regexp' match in the first line -of the paragraph." - :group 'idlwave-code-formatting - :type 'boolean) - -(defcustom idlwave-hang-indent-regexp "- " - "Regular expression matching the position of the hanging indent -in the first line of a comment paragraph. The size of the indent -extends to the end of the match for the regular expression." - :group 'idlwave-code-formatting - :type 'regexp) - -(defcustom idlwave-use-last-hang-indent nil - "If non-nil then use last match on line for `idlwave-hang-indent-regexp'." - :group 'idlwave-code-formatting - :type 'boolean) - -(defcustom idlwave-fill-comment-line-only t - "If non-nil then auto fill will only operate on comment lines." - :group 'idlwave-code-formatting - :type 'boolean) - -(defcustom idlwave-auto-fill-split-string t - "If non-nil then auto fill will split strings with the IDL `+' operator. -When the line end falls within a string, string concatenation with the -`+' operator will be used to distribute a long string over lines. -If nil and a string is split then a terminal beep and warning are issued. - -This variable is ignored when `idlwave-fill-comment-line-only' is -non-nil, since in this case code is not auto-filled." - :group 'idlwave-code-formatting - :type 'boolean) - -(defcustom idlwave-split-line-string t - "If non-nil then `idlwave-split-line' will split strings with `+'. -When the splitting point of a line falls inside a string, split the string -using the `+' string concatenation operator. If nil and a string is -split then a terminal beep and warning are issued." - :group 'idlwave-code-formatting - :type 'boolean) - -(defcustom idlwave-no-change-comment ";;;" - "The indentation of a comment that starts with this regular -expression will not be changed. Note that the indentation of a comment -at the beginning of a line is never changed." - :group 'idlwave-code-formatting - :type 'regexp) - -(defcustom idlwave-begin-line-comment nil - "A comment anchored at the beginning of line. -A comment matching this regular expression will not have its -indentation changed. If nil the default is \"^;\", i.e., any line -beginning with a \";\". Expressions for comments at the beginning of -the line should begin with \"^\"." - :group 'idlwave-code-formatting - :type '(choice (const :tag "Any line beginning with `;'" nil) - regexp)) - -(defcustom idlwave-code-comment ";;[^;]" - "A comment that starts with this regular expression on a line by -itself is indented as if it is a part of IDL code. As a result if -the comment is not preceded by whitespace it is unchanged." - :group 'idlwave-code-formatting - :type 'regexp) - -;; Comments not matching any of the above will be indented as a -;; right-margin comment, i.e., to a minimum of `comment-column'. - -;;; Routine Info and Completion --------------------------------------- - -(defgroup idlwave-routine-info nil - "Routine Info options for IDLWAVE mode." - :group 'idlwave) - -(defcustom idlwave-use-library-catalogs t - "Non-nil means search the IDL path for library catalog files. - -These files, named .idlwave_catalog, document routine information for -individual directories and libraries of IDL .pro files. Many popular -libraries come with catalog files by default, so leaving this on is -usually a good idea." - :group 'idlwave-routine-info - :type 'boolean) - -(defcustom idlwave-init-rinfo-when-idle-after 10 - "Seconds of idle time before routine info is automatically initialized. -Initializing the routine info can take a long time, in particular if a -large number of library catalogs are involved. When Emacs is idle for -more than the number of seconds specified by this variable, it starts -the initialization. The process is split into five steps, in order to -keep work interruption as short as possible. If one of the steps -finishes, and no user input has arrived in the mean time, initialization -proceeds immediately to the next step. A good value for this variable -is about 1/3 of the time initialization take in your setup. So if you -have a fast machine and no problems with a slow network connection, -don't hesitate to set this to 2 seconds. A value of 0 means, don't -initialize automatically, but instead wait until routine information is -needed, and initialize then." - :group 'idlwave-routine-info - :type 'number) - -(defcustom idlwave-scan-all-buffers-for-routine-info t - "Non-nil means, scan buffers for IDL programs when updating info. -The scanning is done by the command `idlwave-update-routine-info'. -The following values are allowed: - -nil Don't scan any buffers. -t Scan all `idlwave-mode' buffers in the current editing session. -`current' Scan only the current buffer, but no other buffers." - :group 'idlwave-routine-info - :type '(choice - (const :tag "No buffer" nil) - (const :tag "All buffers" t) - (const :tag "Current buffer only" current))) - -(defcustom idlwave-query-shell-for-routine-info t - "Non-nil means query the shell for info about compiled routines. -Querying the shell is useful to get information about compiled modules, -and it is turned on by default. However, when you have a complete library -scan, this is not necessary." - :group 'idlwave-routine-info - :type 'boolean) - -(defcustom idlwave-auto-routine-info-updates - '(find-file save-buffer kill-buffer compile-buffer) - "Controls under what circumstances routine info is updated automatically. -Possible values: -nil Never -t All available -\(...) A list of circumstances. Allowed members are: - find-file Add info for new IDLWAVE buffers. - save-buffer Update buffer info when buffer is saved - kill-buffer Remove buffer info when buffer gets killed - compile-buffer Update shell info after `idlwave-shell-save-and...'" - :group 'idlwave-routine-info - :type '(choice - (const :tag "Never" nil) - (const :tag "As often as possible" t) - (set :tag "Checklist" :greedy t - (const :tag "When visiting a file" find-file) - (const :tag "When saving a buffer" save-buffer) - (const :tag "After a buffer was killed" kill-buffer) - (const :tag "After a buffer was compiled successfully, update shell info" compile-buffer)))) - -(defcustom idlwave-rinfo-max-source-lines 5 - "Maximum number of source files displayed in the Routine Info window. -When an integer, it is the maximum number of source files displayed. -A value of t means to show all source files." - :group 'idlwave-routine-info - :type 'integer) - -(defcustom idlwave-library-path nil - "Library path for Windows and Mac OS (OS9). Not needed under UNIX. -When selecting the directories to scan for IDL user catalog routine -info, IDLWAVE can, under UNIX, query the shell for the exact search -path (the value of !PATH). However, under MS-Windows, the -IDLWAVE shell does not work. In this case, this variable can be -set to specify the paths where IDLWAVE can find PRO files. The -shell will only be asked for a list of paths when this variable -is nil. The value is a list of directories. A directory -preceded by a `+' will be searched recursively. If you set this -variable on a UNIX system, the shell will not be queried. See -also `idlwave-system-directory'." - :group 'idlwave-routine-info - :type '(repeat (directory))) - -(defcustom idlwave-system-directory "" - "The IDL system directory for Windows and Mac OS. Not needed under -UNIX. Set this to the value of the `!DIR' system variable in IDL. -IDLWAVE uses this to find out which of the library routines belong to -the official system library. All files inside the `lib' subdirectory -are considered system library files - so don't install private stuff -in this directory. On UNIX systems, IDLWAVE queries the shell for the -value of `!DIR'. See also `idlwave-library-path'." - :group 'idlwave-routine-info - :type 'directory) - -;; Configuration files -(defcustom idlwave-config-directory - (locate-user-emacs-file "idlwave" ".idlwave") - "Directory for configuration files and user-library catalog." - :version "24.4" ; added locate-user-emacs-file - :group 'idlwave-routine-info - :type 'file) - -(defvar idlwave-user-catalog-file "idlusercat.el") -(defvar idlwave-xml-system-rinfo-converted-file "idl_xml_rinfo.el") -(defvar idlwave-path-file "idlpath.el") - -(defcustom idlwave-special-lib-alist nil - "Alist of regular expressions matching special library directories. -When listing routine source locations, IDLWAVE gives a short hint where -the file defining the routine is located. By default it lists `SystemLib' -for routines in the system library `!DIR/lib' and `Library' for anything -else. This variable can define additional types. The car of each entry -is a regular expression matching the file name (they normally will match -on the path). The cdr is the string to be used as identifier. Max 10 -chars are allowed." - :group 'idlwave-routine-info - :type '(repeat - (cons regexp string))) - -(defcustom idlwave-auto-write-paths t - "Write out path (!PATH) and system directory (!DIR) info automatically. -Path info is needed to locate library catalog files. If non-nil, -whenever the path-list changes as a result of shell-query, etc., it is -written to file. Otherwise, the menu option \"Write Paths\" can be -used to force a write." - :group 'idlwave-routine-info - :type 'boolean) - -(defgroup idlwave-completion nil - "Completion options for IDLWAVE mode." - :prefix "idlwave" - :group 'idlwave) - -(eval-and-compile - (defconst idlwave-tmp - '(choice :tag "by applying the function" - (const upcase) - (const downcase) - (const capitalize) - (const preserve) - (symbol :tag "Other")))) - -(defcustom idlwave-completion-case '((routine . upcase) - (keyword . upcase) - (class . preserve) - (method . preserve)) - "Association list setting the case of completed words. - -This variable determines the case (UPPER/lower/Capitalized...) of -words inserted into the buffer by completion. The preferred case can -be specified separately for routine names, keywords, classes and -methods. -This alist should therefore have entries for `routine' (normal -functions and procedures, i.e. non-methods), `keyword', `class', and -`method'. Plausible values are - -upcase upcase whole word, like `BOX_CURSOR' -downcase downcase whole word, like `read_ppm' -capitalize capitalize each part, like `Widget_Control' -preserve preserve case as is, like `IDLgrView' - -The value can also be any Emacs Lisp function which transforms the -case of characters in a string. - -A value of `preserve' means that the case of the completed word is -identical to the way it was written in the definition statement of the -routine. This was implemented to allow for mixed-case completion, in -particular of object classes and methods. -If a completable word is defined in multiple locations, the meaning of -`preserve' is not unique since the different definitions might be -cased differently. Therefore IDLWAVE always takes the case of the -*first* definition it encounters during routine info collection and -uses the case derived from it consistently. - -Note that a lowercase-only string in the buffer will always be completed in -lower case (but see the variable `idlwave-completion-force-default-case'). - -After changing this variable, you need to either restart Emacs or press -`C-u C-c C-i' to update the internal lists." - :group 'idlwave-completion - :type `(repeat - (cons (symbol :tag "Derive completion case for") - ,idlwave-tmp))) - -(defcustom idlwave-completion-force-default-case nil - "Non-nil means, completion will always honor `idlwave-completion-case'. -When nil, only the completion of a mixed case or upper case string -will honor the default settings in `idlwave-completion-case', while -the completion of lower case strings will be completed entirely in -lower case." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-complete-empty-string-as-lower-case nil - "Non-nil means, the empty string is considered downcase for completion. -The case of what is already in the buffer determines the case of completions. -When this variable is non-nil, the empty string is considered to be downcase. -Completing on the empty string then offers downcase versions of the possible -completions." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-buffer-case-takes-precedence nil - "Non-nil means, the case of tokens in buffers dominates over system stuff. -To make this possible, we need to re-case everything each time we update -the routine info from the buffers. This is slow. -The default is to consider the case given in the system and library files -first which makes updating much faster." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-highlight-help-links-in-completion t - "Non-nil means, highlight completions for which system help is available. -Help can then be accessed with mouse-3. -This option is only effective when the online help system is installed." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-support-inheritance t - "Non-nil means, treat inheritance with completion, online help etc. -When nil, IDLWAVE only knows about the native methods and tags of a class, -not about inherited ones." - :group 'idlwave-routine-info - :type 'boolean) - -(defcustom idlwave-keyword-class-inheritance '("^[gs]etproperty$" "^init$") - "List of regular expressions for class-driven keyword inheritance. -Keyword inheritance is often tied to class inheritance by \"chaining\" -up the class tree. While it cannot be assumed that the presence of an -_EXTRA or _REF_EXTRA symbol guarantees such chaining will occur, for -certain methods this assumption is almost always true. The methods -for which to assume this can be set here." - :group 'idlwave-routine-info - :type '(repeat (regexp :tag "Match method:"))) - - -(defcustom idlwave-completion-show-classes 1 - "Number of classes to show when completing object methods and keywords. -When completing methods or keywords for an object with unknown class, -the *Completions* buffer will show the valid classes for each completion -like this: - -MyMethod - -The value of this variable may be nil to inhibit display, or an integer to -indicate the maximum number of classes to display." - :group 'idlwave-completion - :type '(choice (const :tag "Don't show" nil) - (integer :tag "Number of classes shown" 1))) - -(defcustom idlwave-completion-fontify-classes t - "Non-nil means, fontify the classes in completions buffer. -This makes it easier to distinguish the completion items from the extra -class info listed. See `idlwave-completion-show-classes'." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-query-class '((method-default . nil) - (keyword-default . nil)) - "Association list governing specification of object classes for completion. - -When IDLWAVE tries to complete object-oriented methods, it usually -cannot determine the class of a given object from context. In order -to provide the user with a correct list of methods or keywords, it -needs to determine the appropriate class. IDLWAVE has two ways of -doing this (well, three ways if you count the shell... see -`idlwave-shell-query-for-class'): - -1. Combine the items of all available classes which contain this - method for the purpose of completion. So when completing a method, - all methods of all known classes are available, and when completing - a keyword, all keywords allowed for this method in any class are - shown. This behavior is very much like normal completion and is - therefore the default. It works much better than one might think - - only for the INIT, GETPROPERTY and SETPROPERTY the keyword lists - become uncomfortably long. See also - `idlwave-completion-show-classes'. - -2. The second possibility is to ask the user on each occasion. To - make this less interruptive, IDLWAVE can store the class as a text - property on the object operator `->'. For a given object in the - source code, class selection will then be needed only once - - for example to complete the method. Keywords to the method can - then be completed directly, because the class is already known. - You will have to turn on the storage of the selected class - explicitly with the variable `idlwave-store-inquired-class'. - -This variable allows you to configure IDLWAVE's method and -method-keyword completion behavior. Its value is an alist, which -should contain at least two elements: (method-default . VALUE) and -\(keyword-default . VALUE), where VALUE is either t or nil. These -specify if the class should be found during method and keyword -completion, respectively. - -The alist may have additional entries specifying exceptions from the -keyword completion rule for specific methods, like INIT or -GETPROPERTY. In order to turn on class specification for the INIT -method, add an entry (\"INIT\" . t). The method name must be ALL-CAPS." - :group 'idlwave-completion - :type '(list - (cons (const method-default) - (boolean :tag "Determine class when completing METHODS ")) - (cons (const keyword-default) - (boolean :tag "Determine class when completing KEYWORDS ")) - (repeat - :tag "Exceptions to defaults" - :inline t - (cons (string :tag "MODULE" :value "") - (boolean :tag "Determine class for this method"))))) - -(defcustom idlwave-store-inquired-class t - "Non-nil means, store class of a method call as text property on `->'. -IDLWAVE sometimes has to ask the user for the class associated with a -particular object method call. This happens during the commands -`idlwave-routine-info' and `idlwave-complete', depending upon the -value of the variable `idlwave-query-class'. - -When you specify a class, this information can be stored as a text -property on the `->' arrow in the source code, so that during the same -editing session, IDLWAVE will not have to ask again. When this -variable is non-nil, IDLWAVE will store and reuse the class information. -The class stored can be checked and removed with \\[idlwave-routine-info] -on the arrow. - -The default of this variable is nil, since the result of commands then -is more predictable. However, if you know what you are doing, it can -be nice to turn this on. - -An arrow which knows the class will be highlighted with -`idlwave-class-arrow-face'. The command \\[idlwave-routine-info] -displays (with prefix arg: deletes) the class stored on the arrow -at point." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-class-arrow-face 'bold - "Face to highlight object operator arrows `->' which carry a class property. -When IDLWAVE stores a class name as text property on an object arrow -\(see variable `idlwave-store-inquired-class', it highlights the arrow -with this font in order to remind the user that this arrow is special." - :group 'idlwave-completion - :type 'symbol) - -(defcustom idlwave-resize-routine-help-window t - "Non-nil means, resize the Routine-info *Help* window to fit the content." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-keyword-completion-adds-equal t - "Non-nil means, completion automatically adds `=' after completed keywords." - :group 'idlwave-completion - :type 'boolean) - -(defcustom idlwave-function-completion-adds-paren t - "Non-nil means, completion automatically adds `(' after completed function. -nil means, don't add anything. -A value of `2' means, also add the closing parenthesis and position cursor -between the two." - :group 'idlwave-completion - :type '(choice (const :tag "Nothing" nil) - (const :tag "(" t) - (const :tag "()" 2))) - -(defcustom idlwave-completion-restore-window-configuration t - "Non-nil means, try to restore the window configuration after completion. -When completion is not unique, Emacs displays a list of completions. -This messes up your window configuration. With this variable set, IDLWAVE -restores the old configuration after successful completion." - :group 'idlwave-completion - :type 'boolean) - -;;; Variables for abbrev and action behavior ----------------------------- - -(defgroup idlwave-abbrev-and-indent-action nil - "IDLWAVE performs actions when expanding abbreviations or indenting lines. -The variables in this group govern this." - :group 'idlwave) - -(defcustom idlwave-do-actions nil - "Non-nil means performs actions when indenting. -The actions that can be performed are listed in `idlwave-indent-action-table'." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-abbrev-start-char "\\" - "A single character string used to start abbreviations in abbrev mode. -Possible characters to choose from: ~\\=`% -or even `?'. `.' is not a good choice because it can make structure -field names act like abbrevs in certain circumstances. - -Changes to this in `idlwave-mode-hook' will have no effect. Instead a user -must set it directly using `setq' in the init file before idlwave.el -is loaded." - :group 'idlwave-abbrev-and-indent-action - :type 'string) - -(defcustom idlwave-surround-by-blank nil - "Non-nil means, enable `idlwave-surround'. -If non-nil, `=',`<',`>',`&',`,', `->' are surrounded with spaces by -`idlwave-surround'. -See help for `idlwave-indent-action-table' for symbols using `idlwave-surround'. - -Also see the default key bindings for keys using `idlwave-surround'. -Keys are bound and made into actions calling `idlwave-surround' with -`idlwave-action-and-binding'. -See help for `idlwave-action-and-binding' for examples. - -Also see help for `idlwave-surround'." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-pad-keyword t - "Non-nil means pad `=' in keywords (routine calls or defs) like assignment. -Whenever `idlwave-surround' is non-nil then this affects how `=' is -padded for keywords and for variables. If t, pad the same as for -assignments. If nil then spaces are removed. With any other value, -spaces are left unchanged." - :group 'idlwave-abbrev-and-indent-action - :type '(choice - (const :tag "Pad like assignments" t) - (const :tag "Remove space near `='" nil) - (other :tag "Keep space near `='" keep))) - -(defcustom idlwave-show-block t - "Non-nil means point blinks to block beginning for `idlwave-show-begin'." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-expand-generic-end nil - "Non-nil means expand generic END to ENDIF/ENDELSE/ENDWHILE etc." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-reindent-end t - "Non-nil means re-indent line after END was typed." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-abbrev-move t - "Non-nil means the abbrev hook can move point. -Set to nil by `idlwave-expand-region-abbrevs'. To see the abbrev -definitions, use the command `list-abbrevs', for abbrevs that move -point. Moving point is useful, for example, to place point between -parentheses of expanded functions. - -See `idlwave-modify-abbrev'." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-abbrev-change-case nil - "Non-nil means all abbrevs will be forced to either upper or lower case. -If the value t, all expanded abbrevs will be upper case. -If the value is `down' then abbrevs will be forced to lower case. -If nil, the case will not change. -If `idlwave-reserved-word-upcase' is non-nil, reserved words will always be -upper case, regardless of this variable." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -(defcustom idlwave-reserved-word-upcase nil - "Non-nil means, reserved words will be made upper case via abbrev expansion. -If nil case of reserved words is controlled by `idlwave-abbrev-change-case'. -Has effect only if in `abbrev-mode'." - :group 'idlwave-abbrev-and-indent-action - :type 'boolean) - -;;; Action/Expand Tables. -;; -;; The average user may have difficulty modifying this directly. It -;; can be modified/set in idlwave-mode-hook, but it is easier to use -;; idlwave-action-and-binding. See help for idlwave-action-and-binding for -;; examples of how to add an action. -;; -;; The action table is used by `idlwave-indent-line' whereas both the -;; action and expand tables are used by `idlwave-indent-and-action'. In -;; general, the expand table is only used when a line is explicitly -;; indented. Whereas, in addition to being used when the expand table -;; is used, the action table is used when a line is indirectly -;; indented via line splitting, auto-filling or a new line creation. -;; -;; Example actions: -;; -;; Capitalize system vars -;; (idlwave-action-and-binding idlwave-sysvar -;; (lambda (_) (capitalize-word 1)) t) -;; -;; Capitalize procedure name -;; (idlwave-action-and-binding "\\<\\(pro\\|function\\)\\>[ \t]*\\<" -;; (lambda (_) (capitalize-word 1)) t) -;; -;; Capitalize common block name -;; (idlwave-action-and-binding "\\[ \t]+\\<" -;; (lambda (_) (capitalize-word 1)) t) -;; Capitalize label -;; (idlwave-action-and-binding (concat "^[ \t]*" idlwave-label) -;; (lambda (_) (capitalize-word 1)) t) - -(defvar idlwave-indent-action-table nil - "Associated array containing action lists of search string (car), -and function as a cdr. This table is used by `idlwave-indent-line'. -See documentation for `idlwave-do-action' for a complete description of -the action lists. - -Additions to the table are made with `idlwave-action-and-binding' when a -binding is not requested. -See help on `idlwave-action-and-binding' for examples.") - -(defvar idlwave-indent-expand-table nil - "Associated array containing action lists of search string (car), -and function as a cdr. The table is used by the -`idlwave-indent-and-action' function. See documentation for -`idlwave-do-action' for a complete description of the action lists. - -Additions to the table are made with `idlwave-action-and-binding' when a -binding is requested. -See help on `idlwave-action-and-binding' for examples.") - -;;; Documentation header and history keyword --------------------------------- - -(defgroup idlwave-documentation nil - "Options for documenting IDLWAVE files." - :group 'idlwave) - -;; FIXME: make defcustom? -(defvar idlwave-file-header - (list nil - ";+ -; NAME: -; -; -; -; PURPOSE: -; -; -; -; CATEGORY: -; -; -; -; CALLING SEQUENCE: -; -; -; -; INPUTS: -; -; -; -; OPTIONAL INPUTS: -; -; -; -; KEYWORD PARAMETERS: -; -; -; -; OUTPUTS: -; -; -; -; OPTIONAL OUTPUTS: -; -; -; -; COMMON BLOCKS: -; -; -; -; SIDE EFFECTS: -; -; -; -; RESTRICTIONS: -; -; -; -; PROCEDURE: -; -; -; -; EXAMPLE: -; -; -; -; MODIFICATION HISTORY: -; -;- -") - "A list (PATHNAME STRING) specifying the doc-header template to use for -summarizing a file. If PATHNAME is non-nil then this file will be included. -Otherwise STRING is used. If nil, the file summary will be omitted. -For example you might set PATHNAME to the path for the -lib_template.pro file included in the IDL distribution.") - -(defcustom idlwave-header-to-beginning-of-file t - "Non-nil means, the documentation header will always be at start of file. -When nil, the header is positioned between the PRO/FUNCTION line of -the current routine and the code, allowing several routine headers in -a file." - :group 'idlwave-documentation - :type 'boolean) - -(defcustom idlwave-timestamp-hook 'idlwave-default-insert-timestamp - "The hook function used to update the timestamp of a function." - :group 'idlwave-documentation - :type 'function) - -(defcustom idlwave-doc-modifications-keyword "HISTORY" - "The modifications keyword to use with the log documentation commands. -A `:' is added to the keyword end. -Inserted by doc-header and used to position logs by doc-modification. -If nil it will not be inserted." - :group 'idlwave-documentation - :type 'string) - -(defcustom idlwave-doclib-start "^;+\\+" - "Regexp matching the start of a document library header." - :group 'idlwave-documentation - :type 'regexp) - -(defcustom idlwave-doclib-end "^;+-" - "Regexp matching the end of a document library header." - :group 'idlwave-documentation - :type 'regexp) - -;;; External Programs ------------------------------------------------------- - -(defgroup idlwave-external-programs nil - "Path locations of external commands used by IDLWAVE." - :group 'idlwave) - -(defcustom idlwave-shell-explicit-file-name "idl" - "If non-nil, this is the command to run IDL. -Should be an absolute file path or path relative to the current environment -execution search path. If you want to specify command line switches -for the IDL program, use `idlwave-shell-command-line-options'. - -I know the name of this variable is badly chosen, but I cannot change -it without compromising backwards-compatibility." - :group 'idlwave-external-programs - :type 'string) - -(defcustom idlwave-shell-command-line-options nil - "A list of command line options for calling the IDL program. -Since IDL is executed directly without going through a shell like /bin/sh, -this should be a list of strings like (\"-rt=file\" \"-nw\") with a separate -string for each argument. But you may also give a single string which -contains the options whitespace-separated. Emacs will be kind enough to -split it for you." - :type '(choice - string - (repeat (string :value ""))) - :group 'idlwave-external-programs) - -(defcustom idlwave-help-application "idlhelp" - "The external application providing reference help for programming. -Obsolete, if the IDL Assistant is being used for help." - :group 'idlwave-external-programs - :type 'string) - -;;; Some Shell variables which must be defined here.----------------------- - -(defcustom idlwave-shell-debug-modifiers '() - "List of modifiers to be used for the debugging commands. -Will be used to bind debugging commands in the shell buffer and in all -source buffers. These are additional convenience bindings, the debugging -commands are always available with the \\`C-c C-d' prefix. -If you set this to (control shift), this means setting a breakpoint will -be on \\`C-S-b', compiling a source file on \\`C-S-c' etc. Possible modifiers -are `control', `meta', `super', `hyper', `alt', and `shift'." - :group 'idlwave-shell-general-setup - :type '(set :tag "Specify modifiers" - (const control) - (const meta) - (const super) - (const hyper) - (const alt) - (const shift))) - -(defcustom idlwave-shell-automatic-start nil - "If non-nil attempt invoke `idlwave-shell' if not already running. -This is checked when an attempt to send a command to an -IDL process is made." - :group 'idlwave-shell-general-setup - :type 'boolean) - -;;; Miscellaneous variables ------------------------------------------------- - -(defgroup idlwave-misc nil - "Miscellaneous options for IDLWAVE mode." - :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) - :group 'idlwave) - -(defcustom idlwave-startup-message t - "Non-nil displays a startup message when `idlwave-mode' is first called." - :group 'idlwave-misc - :type 'boolean) - -(defcustom idlwave-default-font-lock-items - '(pros-and-functions batch-files idlwave-idl-keywords label goto - common-blocks class-arrows) - "Items which should be fontified on the default fontification level 2. -IDLWAVE defines 3 levels of fontification. Level 1 is very little, level 3 -is everything and level 2 is specified by this list. -This variable must be set before IDLWAVE gets loaded. -It is a list of symbols; the following symbols are allowed: - -pros-and-functions Procedure and Function definitions -batch-files Batch Files -idlwave-idl-keywords IDL Keywords -label Statement Labels -goto Goto Statements -common-blocks Common Blocks -keyword-parameters Keyword Parameters in routine definitions and calls -system-variables System Variables -class-arrows Object Arrows with class property" - :group 'idlwave-misc - :type '(set - :inline t :greedy t - (const :tag "Procedure and Function definitions" pros-and-functions) - (const :tag "Batch Files" batch-files) - (const :tag "IDL Keywords (reserved words)" idlwave-idl-keywords) - (const :tag "Statement Labels" label) - (const :tag "Goto Statements" goto) - (const :tag "Tags in Structure Definition" structtag) - (const :tag "Structure Name" structname) - (const :tag "Common Blocks" common-blocks) - (const :tag "Keyword Parameters" keyword-parameters) - (const :tag "System Variables" system-variables) - (const :tag "Object Arrows with class property " class-arrows))) - -(defcustom idlwave-mode-hook nil - "Normal hook. Executed when a buffer is put into `idlwave-mode'." - :group 'idlwave-misc - :type 'hook) - -(defcustom idlwave-load-hook nil - "Normal hook. Executed when idlwave.el is loaded." - :group 'idlwave-misc - :type 'hook) -(make-obsolete-variable 'idlwave-load-hook - "use `with-eval-after-load' instead." "28.1") - -(defvar idlwave-experimental nil - "Non-nil means turn on a few experimental features. -This variable is only for the maintainer, to test difficult stuff, -while still distributing stable releases. -As a user, you should not set this to t.") - -;;; -;;; End customization variables section -;;; - -;;; Non customization variables - -;;; font-lock mode - Additions by Phil Williams, Ulrik Dickow and -;;; Simon Marshall -;;; and Carsten Dominik... - -;; The following are the reserved words in IDL. Maybe we should -;; highlight some more stuff as well? -;; Procedure declarations. Fontify keyword plus procedure name. -(defvar idlwave-idl-keywords - ;; To update this regexp, update the list of keywords and - ;; evaluate the form. - ;; (insert - ;; (prin1-to-string - ;; (concat - ;; "\\<\\(" - ;; (regexp-opt - ;; '("||" "&&" "and" "or" "xor" "not" - ;; "eq" "ge" "gt" "le" "lt" "ne" - ;; "for" "do" "endfor" - ;; "if" "then" "endif" "else" "endelse" - ;; "case" "of" "endcase" - ;; "switch" "break" "continue" "endswitch" - ;; "begin" "end" - ;; "repeat" "until" "endrep" - ;; "while" "endwhile" - ;; "goto" "return" - ;; "inherits" "mod" - ;; "compile_opt" "forward_function" - ;; "on_error" "on_ioerror")) ; on_error is not officially reserved - ;; "\\)\\>"))) - "\\<\\(&&\\|and\\|b\\(egin\\|reak\\)\\|c\\(ase\\|o\\(mpile_opt\\|ntinue\\)\\)\\|do\\|e\\(lse\\|nd\\(case\\|else\\|for\\|if\\|rep\\|switch\\|while\\)?\\|q\\)\\|for\\(ward_function\\)?\\|g\\(oto\\|[et]\\)\\|i\\(f\\|nherits\\)\\|l[et]\\|mod\\|n\\(e\\|ot\\)\\|o\\(n_\\(error\\|ioerror\\)\\|[fr]\\)\\|re\\(peat\\|turn\\)\\|switch\\|then\\|until\\|while\\|xor\\|||\\)\\>") - - -(defmacro idlwave--dlet (binders &rest body) - "Like `dlet' but without warnings about non-prefixed var names." - (declare (indent 1) (debug let)) - (let ((vars (mapcar (lambda (binder) - (if (consp binder) (car binder) binder)) - binders))) - `(with-suppressed-warnings ((lexical ,@vars)) - (dlet ,binders ,@body)))) - -(idlwave--dlet - (;; Procedure declarations. Fontify keyword plus procedure name. - ;; Function declarations. Fontify keyword plus function name. - (pros-and-functions - '("\\<\\(function\\|pro\\)\\>[ \t]+\\(\\sw+\\(::\\sw+\\)?\\)" - (1 font-lock-keyword-face) - (2 font-lock-function-name-face nil t))) - - ;; Common blocks - (common-blocks - '("\\<\\(common\\)\\>[ \t]*\\(\\sw+\\)?[ \t]*,?" - (1 font-lock-keyword-face) ; "common" - (2 font-lock-constant-face nil t) ; block name - ("[ \t]*\\(\\sw+\\)[ ,]*" - ;; Start with point after block name and comma - nil nil (1 font-lock-variable-name-face)))) ; variable names - - ;; Batch files - (batch-files - '("^[ \t]*\\(@[^ \t\n]+\\)" (1 font-lock-string-face))) - - ;; Labels - (label - '("^[ \t]*\\([a-zA-Z]\\sw*:\\)" (1 font-lock-constant-face))) - - ;; The goto statement and its label - (goto - '("\\(goto\\)[ \t]*,[ \t]*\\([a-zA-Z]\\sw*\\)" - (1 font-lock-keyword-face) - (2 font-lock-constant-face))) - - ;; Tags in structure definitions. Note that this definition - ;; actually collides with labels, so we have to use the same - ;; face. It also matches named subscript ranges, - ;; e.g. vec{bottom:top]. No good way around this. - (structtag - '("\\<\\([a-zA-Z][a-zA-Z0-9_]*:\\)[^:]" (1 font-lock-constant-face))) - - ;; Structure names - (structname - '("\\({\\|\\#]" (0 font-lock-keyword-face))) - - ;; All operators (not used because too noisy) - ;; (all-operators - ;; '("[-*^#+<>/]" (0 font-lock-keyword-face))) - - ;; Arrows with text property `idlwave-class' - (class-arrows - '(idlwave-match-class-arrows (0 idlwave-class-arrow-face)))) - - (defconst idlwave-font-lock-keywords-1 - (list pros-and-functions batch-files) - "Subdued level highlighting for IDLWAVE mode.") - - (defconst idlwave-font-lock-keywords-2 - (mapcar #'symbol-value idlwave-default-font-lock-items) - "Medium level highlighting for IDLWAVE mode.") - - (defconst idlwave-font-lock-keywords-3 - (list pros-and-functions - batch-files - idlwave-idl-keywords - label goto - structtag - structname - common-blocks - keyword-parameters - system-variables - class-arrows) - "Gaudy level highlighting for IDLWAVE mode.")) - -(defun idlwave-match-class-arrows (limit) - ;; Match an object arrow with class property - (and idlwave-store-inquired-class - (re-search-forward "->" limit 'limit) - (get-text-property (match-beginning 0) 'idlwave-class))) - -(defvar idlwave-font-lock-keywords idlwave-font-lock-keywords-2 - "Default expressions to highlight in IDLWAVE mode.") - -(defvar idlwave-font-lock-defaults - '((idlwave-font-lock-keywords - idlwave-font-lock-keywords-1 - idlwave-font-lock-keywords-2 - idlwave-font-lock-keywords-3) - nil t - ((?$ . "w") (?_ . "w") (?. . "w") (?| . "w") (?& . "w")) - beginning-of-line)) - -(defconst idlwave-comment-line-start-skip "^[ \t]*;" - "Regexp to match the start of a full-line comment. -That is the _beginning_ of a line containing a comment delimiter `;' preceded -only by whitespace.") - -(defconst idlwave-begin-block-reg - "\\<\\(pro\\|function\\|begin\\|case\\|switch\\)\\>" - "Regular expression to find the beginning of a block. -The case does not matter. The search skips matches in comments.") - -(defconst idlwave-begin-unit-reg "^\\s-*\\(pro\\|function\\)\\>\\|\\`" - "Regular expression to find the beginning of a unit. -The case does not matter.") - -(defconst idlwave-end-unit-reg "^\\s-*\\(pro\\|function\\)\\>\\|\\'" - "Regular expression to find the line that indicates the end of unit. -This line is the end of buffer or the start of another unit. -The case does not matter. The search skips matches in comments.") - -(defconst idlwave-continue-line-reg "\\<\\$" - "Regular expression to match a continued line.") - -(defconst idlwave-end-block-reg - "\\" - "Regular expression to find the end of a block. -The case does not matter. The search skips matches in comments.") - -(defconst idlwave-block-matches - '(("pro" . "end") - ("function" . "end") - ("case" . "endcase") - ("else" . "endelse") - ("for" . "endfor") - ("then" . "endif") - ("repeat" . "endrep") - ("switch" . "endswitch") - ("while" . "endwhile")) - "Matches between statements and the corresponding END variant. -The cars are the reserved words starting a block. If the block really -begins with BEGIN, the cars are the reserved words before the begin -which can be used to identify the block type. -This is used to check for the correct END type, to close blocks and -to expand generic end statements to their detailed form.") - -(defconst idlwave-block-match-regexp - "\\<\\(else\\|for\\|then\\|repeat\\|while\\)\\>" -"Regular expression matching reserved words which can stand before -blocks starting with a BEGIN statement. The matches must have associations -`idlwave-block-matches'.") - -(defconst idlwave-identifier "[a-zA-Z_][a-zA-Z0-9$_]*" - "Regular expression matching an IDL identifier.") - -(defconst idlwave-sysvar (concat "!" idlwave-identifier) - "Regular expression matching IDL system variables.") - -(defconst idlwave-variable (concat idlwave-identifier "\\|" idlwave-sysvar) - "Regular expression matching IDL variable names.") - -(defconst idlwave-label (concat idlwave-identifier ":") - "Regular expression matching IDL labels.") - -(defconst idlwave-method-call (concat idlwave-identifier "\\s *->" - "\\(\\s *" idlwave-identifier "::\\)?" -)) - -(defconst idlwave-statement-match - (list - ;; "endif else" is the only possible "end" that can be - ;; followed by a statement on the same line. - '(endelse . ("end\\(\\|if\\)\\s +else" "end\\(\\|if\\)\\s +else")) - ;; all other "end"s can not be followed by a statement. - (cons 'end (list idlwave-end-block-reg nil)) - '(if . ("if\\>" "then")) - '(for . ("for\\>" "do")) - '(begin . ("begin\\>" nil)) - '(pdef . ("pro\\>\\|function\\>" nil)) - '(while . ("while\\>" "do")) - '(repeat . ("repeat\\>" "repeat")) - '(goto . ("goto\\>" nil)) - '(case . ("case\\>" nil)) - '(switch . ("switch\\>" nil)) - (cons 'call (list (concat "\\(" idlwave-variable "\\) *= *" - "\\(" idlwave-method-call "\\s *\\)?" - idlwave-identifier - "\\s *(") - nil)) - (cons 'call (list (concat - "\\(" idlwave-method-call "\\s *\\)?" - idlwave-identifier - "\\( *\\($\\|\\$\\)\\|\\s *,\\)") - nil)) - (cons 'assign (list (concat - "\\(" idlwave-variable "\\) *=") - nil))) - - "Associated list of statement matching regular expressions. -Each regular expression matches the start of an IDL statement. -The first element of each association is a symbol giving the statement -type. The associated value is a list. The first element of this list -is a regular expression matching the start of an IDL statement for -identifying the statement type. The second element of this list is a -regular expression for finding a substatement for the type. The -substatement starts after the end of the found match modulo -whitespace. If it is nil then the statement has no substatement. The -list order matters since matching an assignment statement exactly is -not possible without parsing. Thus assignment statement become just -the leftover unidentified statements containing an equal sign.") - -(defvar idlwave-comment-indent-function 'comment-indent-function - "IDL mode comment indent function.") - -;; Note that this is documented in the v18 manuals as being a string -;; of length one rather than a single character. -;; The code in this file accepts either format for compatibility. -(defvar idlwave-comment-indent-char ?\s - "Character to be inserted for IDL comment indentation. -Normally a space.") - -(defconst idlwave-continuation-char ?$ - "Character which is inserted as a last character on previous line by -\\[idlwave-split-line] to begin a continuation line. Normally $.") - -(defconst idlwave-mode-version "6.1_em22") - -(defun idlwave-keyword-abbrev (&rest args) - "Create a function for abbrev hooks to call `idlwave-modify-abbrev' with args." - (lambda () (apply #'idlwave-modify-abbrev args))) - -(autoload 'idlwave-shell "idlw-shell" - "Run an inferior IDL, with I/O through buffer `(idlwave-shell-buffer)'." t) -(autoload 'idlwave-shell-send-command "idlw-shell") -(autoload 'idlwave-shell-recenter-shell-window "idlw-shell" - "Run `idlwave-shell' and switch back to current window" t) -(autoload 'idlwave-shell-save-and-run "idlw-shell" - "Save and run buffer under the shell." t) -(autoload 'idlwave-shell-break-here "idlw-shell" - "Set breakpoint in current line." t) -(autoload 'idlwave-shell-run-region "idlw-shell" - "Compile and run the region." t) - -(defalias 'idlwave-debug-map (make-sparse-keymap)) - -(defvar idlwave-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "\C-c " #'idlwave-hard-tab) - (define-key map [(control tab)] #'idlwave-hard-tab) - ;;(define-key map "\C-c\C- " #'idlwave-hard-tab) - (define-key map "'" #'idlwave-show-matching-quote) - (define-key map "\"" #'idlwave-show-matching-quote) - (define-key map "\C-g" #'idlwave-keyboard-quit) - (define-key map "\C-c;" #'idlwave-toggle-comment-region) - (define-key map "\C-\M-a" #'idlwave-beginning-of-subprogram) - (define-key map "\C-\M-e" #'idlwave-end-of-subprogram) - (define-key map "\C-c{" #'idlwave-beginning-of-block) - (define-key map "\C-c}" #'idlwave-end-of-block) - (define-key map "\C-c]" #'idlwave-close-block) - (define-key map [(meta control h)] #'idlwave-mark-subprogram) - (define-key map "\M-\C-n" #'idlwave-forward-block) - (define-key map "\M-\C-p" #'idlwave-backward-block) - (define-key map "\M-\C-d" #'idlwave-down-block) - (define-key map "\M-\C-u" #'idlwave-backward-up-block) - (define-key map "\M-\r" #'idlwave-split-line) - (define-key map "\M-\C-q" #'idlwave-indent-subprogram) - (define-key map "\C-c\C-p" #'idlwave-previous-statement) - (define-key map "\C-c\C-n" #'idlwave-next-statement) - ;; (define-key map "\r" #'idlwave-newline) - ;; (define-key map "\t" #'idlwave-indent-line) - (define-key map [(shift iso-lefttab)] #'idlwave-indent-statement) - (define-key map "\C-c\C-a" #'auto-fill-mode) - (define-key map "\M-q" #'idlwave-fill-paragraph) - (define-key map "\M-s" #'idlwave-edit-in-idlde) - (define-key map "\C-c\C-h" #'idlwave-doc-header) - (define-key map "\C-c\C-m" #'idlwave-doc-modification) - (define-key map "\C-c\C-c" #'idlwave-case) - (define-key map "\C-c\C-d" #'idlwave-debug-map) - (when (and (listp idlwave-shell-debug-modifiers) - (not (equal idlwave-shell-debug-modifiers '()))) - ;; Bind the debug commands also with the special modifiers. - (let ((shift (memq 'shift idlwave-shell-debug-modifiers)) - (mods-noshift - (delq 'shift (copy-sequence idlwave-shell-debug-modifiers)))) - (define-key map - (vector (append mods-noshift (list (if shift ?C ?c)))) - #'idlwave-shell-save-and-run) - (define-key map - (vector (append mods-noshift (list (if shift ?B ?b)))) - #'idlwave-shell-break-here) - (define-key map - (vector (append mods-noshift (list (if shift ?E ?e)))) - #'idlwave-shell-run-region))) - (define-key map "\C-c\C-d\C-c" #'idlwave-shell-save-and-run) - (define-key map "\C-c\C-d\C-b" #'idlwave-shell-break-here) - (define-key map "\C-c\C-d\C-e" #'idlwave-shell-run-region) - (define-key map "\C-c\C-f" #'idlwave-for) - ;; (define-key map "\C-c\C-f" #'idlwave-function) - ;; (define-key map "\C-c\C-p" #'idlwave-procedure) - (define-key map "\C-c\C-r" #'idlwave-repeat) - (define-key map "\C-c\C-w" #'idlwave-while) - (define-key map "\C-c\C-k" #'idlwave-kill-autoloaded-buffers) - (define-key map "\C-c\C-s" #'idlwave-shell) - (define-key map "\C-c\C-l" #'idlwave-shell-recenter-shell-window) - (define-key map "\C-c\C-b" #'idlwave-list-buffer-load-path-shadows) - (define-key map "\C-c\C-v" #'idlwave-find-module) - (define-key map "\C-c\C-t" #'idlwave-find-module-this-file) - (define-key map "\C-c?" #'idlwave-routine-info) - (define-key map "\M-?" #'idlwave-context-help) - (define-key map [(control meta ?\?)] - #'idlwave-help-assistant-help-with-topic) - ;; Pickup both forms of Esc/Meta binding - ;; FIXME: Use `completion-at-point'! - (define-key map [(meta tab)] #'idlwave-complete) - (define-key map [?\e?\t] #'idlwave-complete) - (define-key map "\M-\C-i" #'idlwave-complete) - (define-key map "\C-c\C-i" #'idlwave-update-routine-info) - (define-key map "\C-c=" #'idlwave-resolve) - (define-key map [(shift mouse-3)] #'idlwave-mouse-context-help) - map) - "Keymap used in IDL mode.") - -(defvar idlwave-mode-syntax-table - (let ((st (make-syntax-table))) - (modify-syntax-entry ?+ "." st) - (modify-syntax-entry ?- "." st) - (modify-syntax-entry ?* "." st) - (modify-syntax-entry ?/ "." st) - (modify-syntax-entry ?^ "." st) - (modify-syntax-entry ?# "." st) - (modify-syntax-entry ?= "." st) - (modify-syntax-entry ?% "." st) - (modify-syntax-entry ?< "." st) - (modify-syntax-entry ?> "." st) - (modify-syntax-entry ?\' "\"" st) - (modify-syntax-entry ?\" "\"" st) - (modify-syntax-entry ?\\ "." st) - (modify-syntax-entry ?_ "_" st) - (modify-syntax-entry ?{ "(}" st) - (modify-syntax-entry ?} "){" st) - (modify-syntax-entry ?$ "_" st) - (modify-syntax-entry ?. "." st) - (modify-syntax-entry ?\; "<" st) - (modify-syntax-entry ?\n ">" st) - (modify-syntax-entry ?\f ">" st) - st) - "Syntax table in use in `idlwave-mode' buffers.") - -(defvar idlwave-find-symbol-syntax-table - (let ((st (copy-syntax-table idlwave-mode-syntax-table))) - (modify-syntax-entry ?$ "w" st) - (modify-syntax-entry ?_ "w" st) - (modify-syntax-entry ?! "w" st) - (modify-syntax-entry ?. "w" st) - st) - "Syntax table that treats symbol characters as word characters.") - -;;(defmacro idlwave-with-special-syntax (&rest body) -;; "Execute BODY with `idlwave-find-symbol-syntax-table'." -;; `(with-syntax-table idlwave-find-symbol-syntax-table -;; ,@body)) - -(defun idlwave-action-and-binding (key cmd &optional select) - "KEY and CMD are made into a key binding and an indent action. -KEY is a string - same as for the `define-key' function. CMD is a -function of one argument. CMD is bound to -KEY in `idlwave-mode-map' by defining an anonymous function calling -`self-insert-command' followed by CMD. If KEY contains more than one -character a binding will only be set if SELECT is `both'. - -\(KEY . CMD) is also placed in the `idlwave-indent-expand-table', -replacing any previous value for KEY. If a binding is not set then it -will instead be placed in `idlwave-indent-action-table'. - -If the optional argument SELECT is nil then an action and binding are -created. If SELECT is `noaction', then a binding is always set and no -action is created. If SELECT is `both' then an action and binding -will both be created even if KEY contains more than one character. -Otherwise, if SELECT is non-nil then only an action is created. - -Some examples: -No spaces before and 1 after a comma - (idlwave-action-and-binding \",\" (lambda (_) (idlwave-surround 0 1))) -A minimum of 1 space before and after `=' (see `idlwave-expand-equal'). - (idlwave-action-and-binding \"=\" (lambda (_) (idlwave-expand-equal -1 -1))) -Capitalize system variables - action only - (idlwave-action-and-binding idlwave-sysvar - (lambda (_) (capitalize-word 1) t))" - (if (not (equal select 'noaction)) - ;; Add action - (let* ((table (if select 'idlwave-indent-action-table - 'idlwave-indent-expand-table)) - (table-key (regexp-quote key))) - (setf (alist-get table-key (symbol-value table) nil nil #'equal) cmd))) - ;; Make key binding for action - (if (if (null select) (= (length key) 1) - (memq select '(noaction both))) - ;; FIXME: Use `post-self-insert-hook'! - (define-key idlwave-mode-map key - (lambda () - (interactive) - (self-insert-command 1) - (if (functionp cmd) (funcall cmd nil) (eval cmd t)))))) - -;; Set action and key bindings. -;; See description of the function `idlwave-action-and-binding'. -;; Automatically add spaces for the following characters - -;; Actions for & are complicated by && -(idlwave-action-and-binding "&" #'idlwave-custom-ampersand-surround) - -;; Automatically add spaces to equal sign if not keyword. This needs -;; to go ahead of > and <, so >= and <= will be treated correctly -(idlwave-action-and-binding "=" (lambda (_) (idlwave-expand-equal -1 -1))) - -;; Actions for > and < are complicated by >=, <=, and ->... -(idlwave-action-and-binding "<" (lambda (a) (idlwave-custom-ltgtr-surround nil a))) -(idlwave-action-and-binding ">" (lambda (a) (idlwave-custom-ltgtr-surround t a))) - -(idlwave-action-and-binding "," (lambda (a) (idlwave-surround 0 -1 1 a))) - - -;;; -;;; Abbrev Section -;;; -;; When expanding abbrevs and the abbrev hook moves backward, an extra -;; space is inserted (this is the space typed by the user to expanded -;; the abbrev). -;; FIXME: This can be controlled with `no-self-insert' property. -;; -(define-abbrev-table 'idlwave-mode-abbrev-table () - "Abbreviation table used for IDLWAVE mode." - :enable-function (lambda () (not (idlwave-quoted)))) - -(defun idlwave-define-abbrev (name expansion hook &optional noprefix table) - ;; FIXME: `table' is never passed. - "Define-abbrev with backward compatibility. - -If NOPREFIX is non-nil, don't prepend prefix character. Installs into -`idlwave-mode-abbrev-table' unless TABLE is non-nil." - (let ((abbrevs-changed nil) ;; mask the current value to avoid save - (args (list (or table idlwave-mode-abbrev-table) - (if noprefix name (concat idlwave-abbrev-start-char name)) - expansion - hook))) - (condition-case nil - (apply #'define-abbrev (append args '(0 t))) - (error (apply #'define-abbrev args))))) - -(condition-case nil - (modify-syntax-entry (string-to-char idlwave-abbrev-start-char) - "w" idlwave-mode-syntax-table) - (error nil)) - -;; -;; Templates -;; -(idlwave-define-abbrev "c" "" #'idlwave-case) -(idlwave-define-abbrev "sw" "" #'idlwave-switch) -(idlwave-define-abbrev "f" "" #'idlwave-for) -(idlwave-define-abbrev "fu" "" #'idlwave-function) -(idlwave-define-abbrev "pr" "" #'idlwave-procedure) -(idlwave-define-abbrev "r" "" #'idlwave-repeat) -(idlwave-define-abbrev "w" "" #'idlwave-while) -(idlwave-define-abbrev "i" "" #'idlwave-if) -(idlwave-define-abbrev "elif" "" #'idlwave-elif) -;; -;; Keywords, system functions, conversion routines -;; -(idlwave-define-abbrev "ap" "arg_present()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "b" "begin" (idlwave-keyword-abbrev 0 t)) -(idlwave-define-abbrev "co" "common" (idlwave-keyword-abbrev 0 t)) -(idlwave-define-abbrev "cb" "byte()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "cx" "fix()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "cl" "long()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "cf" "float()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "cs" "string()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "cc" "complex()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "cd" "double()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "e" "else" (idlwave-keyword-abbrev 0 t)) -(idlwave-define-abbrev "ec" "endcase" #'idlwave-show-begin) -(idlwave-define-abbrev "es" "endswitch" #'idlwave-show-begin) -(idlwave-define-abbrev "ee" "endelse" #'idlwave-show-begin) -(idlwave-define-abbrev "ef" "endfor" #'idlwave-show-begin) -(idlwave-define-abbrev "ei" "endif else if" #'idlwave-show-begin) -(idlwave-define-abbrev "el" "endif else" #'idlwave-show-begin) -(idlwave-define-abbrev "en" "endif" #'idlwave-show-begin) -(idlwave-define-abbrev "er" "endrep" #'idlwave-show-begin) -(idlwave-define-abbrev "ew" "endwhile" #'idlwave-show-begin) -(idlwave-define-abbrev "g" "goto," (idlwave-keyword-abbrev 0 t)) -(idlwave-define-abbrev "h" "help," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "k" "keyword_set()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "n" "n_elements()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "on" "on_error," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "oi" "on_ioerror," (idlwave-keyword-abbrev 0 1)) -(idlwave-define-abbrev "ow" "openw," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "or" "openr," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "ou" "openu," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "p" "print," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "pt" "plot," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "re" "read," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "rf" "readf," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "ru" "readu," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "rt" "return" (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "sc" "strcompress()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "sn" "strlen()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "sl" "strlowcase()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "su" "strupcase()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "sm" "strmid()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "sp" "strpos()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "st" "strput()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "sr" "strtrim()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "t" "then" (idlwave-keyword-abbrev 0 t)) -(idlwave-define-abbrev "u" "until" (idlwave-keyword-abbrev 0 t)) -(idlwave-define-abbrev "wu" "writeu," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "iap" "if arg_present() then" (idlwave-keyword-abbrev 6)) -(idlwave-define-abbrev "ik" "if keyword_set() then" (idlwave-keyword-abbrev 6)) -(idlwave-define-abbrev "ine" "if n_elements() eq 0 then" (idlwave-keyword-abbrev 11)) -(idlwave-define-abbrev "inn" "if n_elements() ne 0 then" (idlwave-keyword-abbrev 11)) -(idlwave-define-abbrev "np" "n_params()" (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "s" "size()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "wi" "widget_info()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "wc" "widget_control," (idlwave-keyword-abbrev 0)) -(idlwave-define-abbrev "pv" "ptr_valid()" (idlwave-keyword-abbrev 1)) -(idlwave-define-abbrev "ipv" "if ptr_valid() then" (idlwave-keyword-abbrev 6)) - -;; This section is reserved words only. (From IDL user manual) -;; -(idlwave-define-abbrev "and" "and" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "begin" "begin" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "break" "break" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "case" "case" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "common" "common" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "continue" "continue" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "do" "do" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "else" "else" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "end" "end" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endcase" "endcase" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endelse" "endelse" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endfor" "endfor" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endif" "endif" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endrep" "endrep" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endswitch" "endswitch" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endwhi" "endwhi" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "endwhile" "endwhile" #'idlwave-show-begin-check t) -(idlwave-define-abbrev "eq" "eq" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "for" "for" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "function" "function" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "ge" "ge" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "goto" "goto" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "gt" "gt" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "if" "if" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "le" "le" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "lt" "lt" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "mod" "mod" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "ne" "ne" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "not" "not" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "of" "of" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "on_ioerror" "on_ioerror" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "or" "or" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "pro" "pro" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "repeat" "repeat" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "switch" "switch" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "then" "then" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "until" "until" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "while" "while" (idlwave-keyword-abbrev 0 t) t) -(idlwave-define-abbrev "xor" "xor" (idlwave-keyword-abbrev 0 t) t) - -(defvar imenu-create-index-function) -(defvar extract-index-name-function) -(defvar prev-index-position-function) -(defvar imenu-extract-index-name-function) -(defvar imenu-prev-index-position-function) -;; defined later - so just make the compiler hush -(defvar idlwave-mode-menu) -(defvar idlwave-mode-debug-menu) - -;;;###autoload -(define-derived-mode idlwave-mode prog-mode "IDLWAVE" - "Major mode for editing IDL source files (version 6.1_em22). - -The main features of this mode are - -1. Indentation and Formatting - -------------------------- - Like other Emacs programming modes, C-j inserts a newline and indents. - TAB is used for explicit indentation of the current line. - - To start a continuation line, use \\[idlwave-split-line]. This - function can also be used in the middle of a line to split the line - at that point. When used inside a long constant string, the string - is split at that point with the `+' concatenation operator. - - Comments are indented as follows: - - `;;;' Indentation remains unchanged. - `;;' Indent like the surrounding code - `;' Indent to a minimum column. - - The indentation of comments starting in column 0 is never changed. - - Use \\[idlwave-fill-paragraph] to refill a paragraph inside a - comment. The indentation of the second line of the paragraph - relative to the first will be retained. Use - \\[auto-fill-mode] to toggle auto-fill mode for these - comments. When the variable `idlwave-fill-comment-line-only' is - nil, code can also be auto-filled and auto-indented. - - To convert pre-existing IDL code to your formatting style, mark the - entire buffer with \\[mark-whole-buffer] and execute - \\[idlwave-expand-region-abbrevs]. Then mark the entire buffer - again followed by \\[indent-region] (`indent-region'). - -2. Routine Info - ------------ - IDLWAVE displays information about the calling sequence and the - accepted keyword parameters of a procedure or function with - \\[idlwave-routine-info]. \\[idlwave-find-module] jumps to the - source file of a module. These commands know about system - routines, all routines in idlwave-mode buffers and (when the - idlwave-shell is active) about all modules currently compiled under - this shell. It also makes use of pre-compiled or custom-scanned - user and library catalogs many popular libraries ship with by - default. Use \\[idlwave-update-routine-info] to update this - information, which is also used for completion (see item 4). - -3. Online IDL Help - --------------- - - \\[idlwave-context-help] displays the IDL documentation relevant - for the system variable, keyword, or routines at point. A single - key stroke gets you directly to the right place in the docs. See - the manual to configure where and how the HTML help is displayed. - -4. Completion - ---------- - \\[idlwave-complete] completes the names of procedures, functions - class names, keyword parameters, system variables and tags, class - tags, structure tags, filenames and much more. It is context - sensitive and figures out what is expected at point. Lower case - strings are completed in lower case, other strings in mixed or - upper case. - -5. Code Templates and Abbreviations - -------------------------------- - Many Abbreviations are predefined to expand to code fragments and templates. - The abbreviations start generally with a `\\'. Some examples: - - \\pr PROCEDURE template - \\fu FUNCTION template - \\c CASE statement template - \\sw SWITCH statement template - \\f FOR loop template - \\r REPEAT Loop template - \\w WHILE loop template - \\i IF statement template - \\elif IF-ELSE statement template - \\b BEGIN - - For a full list, use \\[idlwave-list-abbrevs]. Some templates also - have direct keybindings - see the list of keybindings below. - - \\[idlwave-doc-header] inserts a documentation header at the - beginning of the current program unit (pro, function or main). - Change log entries can be added to the current program unit with - \\[idlwave-doc-modification]. - -6. Automatic Case Conversion - ------------------------- - The case of reserved words and some abbrevs is controlled by - `idlwave-reserved-word-upcase' and `idlwave-abbrev-change-case'. - -7. Automatic END completion - ------------------------ - If the variable `idlwave-expand-generic-end' is non-nil, each END typed - will be converted to the specific version, like ENDIF, ENDFOR, etc. - -8. Hooks - ----- - Turning on `idlwave-mode' runs `idlwave-mode-hook'. - -9. Documentation and Customization - ------------------------------- - Info documentation for this package is available. Use - \\[idlwave-info] to display (complain to your sysadmin if that does - not work). For Postscript, PDF, and HTML versions of the - documentation, check IDLWAVE's website at URL - `https://github.com/jdtsmith/idlwave'. - IDLWAVE has customize support - see the group `idlwave'. - -10.Keybindings - ----------- - Here is a list of all keybindings of this mode. - If some of the key bindings below show with ??, use \\[describe-key] - followed by the key sequence to see what the key sequence does. - -\\{idlwave-mode-map}" - :abbrev-table idlwave-mode-abbrev-table - (if idlwave-startup-message - (message "Emacs IDLWAVE mode version %s." idlwave-mode-version)) - (setq idlwave-startup-message nil) - - (set (make-local-variable 'indent-line-function) #'idlwave-indent-and-action) - - (set (make-local-variable idlwave-comment-indent-function) - #'idlwave-comment-hook) - - (set (make-local-variable 'comment-start-skip) ";+[ \t]*") - (set (make-local-variable 'comment-start) ";") - (set (make-local-variable 'comment-add) 1) ; ";;" for new and regions - (set (make-local-variable 'abbrev-all-caps) t) - (set (make-local-variable 'indent-tabs-mode) nil) - (set (make-local-variable 'completion-ignore-case) t) - - (setq abbrev-mode t) - - (set (make-local-variable 'normal-auto-fill-function) #'idlwave-auto-fill) - (setq comment-end "") - (set (make-local-variable 'comment-multi-line) nil) - (set (make-local-variable 'paragraph-separate) - "[ \t\f]*$\\|[ \t]*;+[ \t]*$\\|;+[+=-_*]+$") - (set (make-local-variable 'paragraph-start) "[ \t\f]\\|[ \t]*;+[ \t]") - (set (make-local-variable 'paragraph-ignore-fill-prefix) nil) - (set (make-local-variable 'parse-sexp-ignore-comments) t) - - ;; ChangeLog - (set (make-local-variable 'add-log-current-defun-function) - #'idlwave-current-routine-fullname) - - ;; Set tag table list to use IDLTAGS as file name. - (if (boundp 'tag-table-alist) - (add-to-list 'tag-table-alist '("\\.pro\\'" . "IDLTAGS"))) - - ;; Font-lock additions - (set (make-local-variable 'font-lock-defaults) idlwave-font-lock-defaults) - (set (make-local-variable 'font-lock-mark-block-function) - #'idlwave-mark-subprogram) - (set (make-local-variable 'font-lock-fontify-region-function) - #'idlwave-font-lock-fontify-region) - - ;; Imenu setup - ;;(set (make-local-variable 'imenu-create-index-function) - ;; ;; FIXME: Why set it explicitly to the value it already has? - ;; #'imenu-default-create-index-function) - (set (make-local-variable 'imenu-extract-index-name-function) - #'idlwave-unit-name) - (set (make-local-variable 'imenu-prev-index-position-function) - #'idlwave-prev-index-position) - - ;; HideShow setup - (add-to-list 'hs-special-modes-alist - (list 'idlwave-mode - idlwave-begin-block-reg - idlwave-end-block-reg - ";" - 'idlwave-forward-block nil)) - - ;; Make a local post-command-hook and add our hook to it - (add-hook 'post-command-hook #'idlwave-command-hook nil 'local) - - ;; Make local hooks for buffer updates - (add-hook 'kill-buffer-hook #'idlwave-kill-buffer-update nil 'local) - (add-hook 'after-save-hook #'idlwave-save-buffer-update nil 'local) - (add-hook 'after-save-hook #'idlwave-revoke-license-to-kill nil 'local) - - ;; Setup directories and file, if necessary - (idlwave-setup) - - ;; Update the routine info with info about current buffer? - (idlwave-new-buffer-update) - - ;; Check help location - (idlwave-help-check-locations)) - -(defvar idlwave-setup-done nil) -(defun idlwave-setup () - (unless idlwave-setup-done - (if (not (file-directory-p idlwave-config-directory)) - (make-directory idlwave-config-directory)) - (setq - idlwave-user-catalog-file (expand-file-name - idlwave-user-catalog-file - idlwave-config-directory) - idlwave-xml-system-rinfo-converted-file - (expand-file-name - idlwave-xml-system-rinfo-converted-file - idlwave-config-directory) - idlwave-path-file (expand-file-name - idlwave-path-file - idlwave-config-directory)) - (idlwave-read-paths) ; we may need these early - (setq idlwave-setup-done t))) - -(defun idlwave-font-lock-fontify-region (beg end &optional verbose) - "Fontify continuation lines correctly." - (let (pos) - (save-excursion - (goto-char beg) - (forward-line -1) - (when (setq pos (idlwave-is-continuation-line)) - (goto-char pos) - (idlwave-beginning-of-statement) - (setq beg (point))))) - (font-lock-default-fontify-region beg end verbose)) - -;; -;; Code Formatting ---------------------------------------------------- -;; - -(defun idlwave-hard-tab () - "Insert TAB in buffer in current position." - (interactive) - (insert "\t")) - -;;; This stuff is experimental - -(defvar idlwave--command-function nil - "If non-nil, a function called from `post-command-hook'. -It is evaluated in the Lisp function `idlwave-command-hook' which is -placed in `post-command-hook'.") - -(defun idlwave-command-hook () - "Command run after every command. -Evaluates a non-nil value of the *variable* `idlwave--command-function' and -sets the variable to zero afterwards." - (and idlwave--command-function - (with-demoted-errors "idlwave-command-hook: %S" - (funcall (prog1 idlwave--command-function - (setq idlwave--command-function nil)))))) - -;;; End experiment - -;; It would be better to use expand.el for better abbrev handling and -;; versatility. - -(defun idlwave-modify-abbrev (arg &optional reserved) - "Tweak the abbrev we just expanded. -Argument ARG is the number of characters to move point -backward if `idlwave-abbrev-move' is non-nil. -If optional argument RESERVED is non-nil then the expansion -consists of reserved words, which will be capitalized if -`idlwave-reserved-word-upcase' is non-nil. -Otherwise, the abbrev will be capitalized if `idlwave-abbrev-change-case' -is non-nil, unless its value is `down' in which case the abbrev will be -made into all lowercase. -Returns non-nil if abbrev is left expanded." - (if (and reserved idlwave-reserved-word-upcase) - (upcase-region last-abbrev-location (point)) - (cond - ((equal idlwave-abbrev-change-case 'down) - (downcase-region last-abbrev-location (point))) - (idlwave-abbrev-change-case - (upcase-region last-abbrev-location (point))))) - (if (and idlwave-abbrev-move (> arg 0)) - (setq idlwave--command-function (lambda () (backward-char (1+ arg))))) - t) - -(defun idlwave-in-comment () - "Return t if point is inside a comment, nil otherwise." - (save-excursion - (let ((here (point))) - (and (idlwave-goto-comment) (> here (point)))))) - -(defun idlwave-goto-comment () - "Move to start of comment delimiter on current line. -Moves to end of line if there is no comment delimiter. -Ignores comment delimiters in strings. -Returns point if comment found and nil otherwise." - (let ((eos (line-end-position)) - (data (match-data)) - found) - ;; Look for first comment delimiter not in a string - (beginning-of-line) - (setq found (search-forward comment-start eos 'lim)) - (while (and found (idlwave-in-quote)) - (setq found (search-forward comment-start eos 'lim))) - (store-match-data data) - (and found (not (idlwave-in-quote)) - (progn - (backward-char 1) - (point))))) - -(define-obsolete-function-alias 'idlwave-region-active-p #'use-region-p "28.1") - -(defun idlwave-show-matching-quote () - "Insert quote and show matching quote if this is end of a string." - (interactive) - (let ((bq (idlwave-in-quote)) - (inq last-command-event)) - (if (and bq (not (idlwave-in-comment))) - (let ((delim (char-after bq))) - (insert inq) - (if (eq inq delim) - (save-excursion - (goto-char bq) - (sit-for 1)))) - ;; Not the end of a string - (insert inq)))) - -(defun idlwave-show-begin-check () - "Ensure that the previous word was a token before `idlwave-show-begin'. -An END token must be preceded by whitespace." - (if - (save-excursion - (backward-word-strictly 1) - (backward-char 1) - (looking-at "[ \t\n\f]")) - (idlwave-show-begin))) - -(defun idlwave-show-begin () - "Find the start of current block and blinks to it for a second. -Also checks if the correct END statement has been used." - ;; All end statements are reserved words - ;; Re-indent end line - ;;(insert-char ?\ 1) ;; So indent, etc. work well - ;;(backward-char 1) - (let* ((pos (point-marker)) - (last-abbrev-marker (copy-marker last-abbrev-location)) - (eol-pos (line-end-position)) - begin-pos end-pos end end1 ) - (if idlwave-reindent-end (idlwave-indent-line)) - (setq last-abbrev-location (marker-position last-abbrev-marker)) - (when (and (idlwave-modify-abbrev 0 t) - idlwave-show-block) - (save-excursion - ;; Move inside current block - (goto-char last-abbrev-marker) - (idlwave-block-jump-out -1 'nomark) - (setq begin-pos (point)) - (idlwave-block-jump-out 1 'nomark) - (setq end-pos (point)) - (if (> end-pos eol-pos) - (setq end-pos pos)) - (goto-char end-pos) - (setq end (buffer-substring - (progn - (skip-chars-backward "a-zA-Z") - (point)) - end-pos)) - (goto-char begin-pos) - (when (setq end1 (cdr (idlwave-block-master))) - (cond - ((null end1)) ; no-operation - ((string= (downcase end) (downcase end1)) - (sit-for 1)) - ((string= (downcase end) "end") - ;; A generic end - (if idlwave-expand-generic-end - (save-excursion - (goto-char pos) - (backward-char 3) - (insert (if (string= end "END") (upcase end1) end1)) - (delete-char 3))) - (sit-for 1)) - (t - (beep) - (message "Warning: Shouldn't this be \"%s\" instead of \"%s\"?" - end1 end) - (sit-for 1)))))))) - ;;(delete-char 1)) - -(defun idlwave-block-master () - (let ((case-fold-search t)) - (save-excursion - (cond - ((looking-at "pro\\|case\\|switch\\|function\\>") - (assoc (downcase (match-string 0)) idlwave-block-matches)) - ((looking-at "begin\\>") - (let ((limit (save-excursion - (idlwave-beginning-of-statement) - (point)))) - (cond - ((re-search-backward ":[ \t]*\\=" limit t) - ;; seems to be a case thing - '("begin" . "end")) - ((re-search-backward idlwave-block-match-regexp limit t) - (assoc (downcase (match-string 1)) - idlwave-block-matches)) - (t - ;; Just a normal block - '("begin" . "end"))))) - (t nil))))) - -(defun idlwave-close-block () - "Terminate the current block with the correct END statement." - (interactive) - ;; Start new line if we are not in a new line - (unless (save-excursion - (skip-chars-backward " \t") - (bolp)) - (let ((idlwave-show-block nil)) - (newline-and-indent))) - (let ((last-abbrev-location (point))) ; for upcasing - (insert "end") - (idlwave-show-begin))) - -(defun idlwave-custom-ampersand-surround (&optional is-action) - "Surround &, leaving room for && (which surround as well)." - (let* ((prev-char (char-after (- (point) 2))) - (next-char (char-after (point))) - (amp-left (eq prev-char ?&)) - (amp-right (eq next-char ?&)) - (len (if amp-left 2 1))) - (unless amp-right ;no need to do it twice, amp-left will catch it. - (idlwave-surround -1 (if (or is-action amp-left) -1) len)))) - -(defun idlwave-custom-ltgtr-surround (gtr &optional is-action) - "Surround > and < by blanks, leaving room for >= and <=, and considering ->." - (let* ((prev-char (char-after (- (point) 2))) - (next-char (char-after (point))) - (method-invoke (and gtr (eq prev-char ?-))) - (len (if method-invoke 2 1))) - (unless (eq next-char ?=) - ;; Key binding: pad only on left, to save for possible >=/<= - (idlwave-surround -1 (if (or is-action method-invoke) -1) len)))) - -(defun idlwave-surround (&optional before after length _is-action) - "Surround the LENGTH characters before point with blanks. -LENGTH defaults to 1. -Optional arguments BEFORE and AFTER affect the behavior before and -after the characters (see also description of `idlwave-make-space'): - -nil do nothing -0 force no spaces -integer > 0 force exactly n spaces -integer < 0 at least |n| spaces - -The function does nothing if any of the following conditions is true: -- `idlwave-surround-by-blank' is nil -- the character before point is inside a string or comment" - (when (and idlwave-surround-by-blank (not (idlwave-quoted))) - (let ((length (or length 1))) ; establish a default for LENGTH - (backward-char length) - (save-restriction - (let ((here (point))) - (skip-chars-backward " \t") - (if (bolp) - ;; avoid clobbering indent - (progn - (move-to-column (idlwave-calculate-indent)) - (if (<= (point) here) - (narrow-to-region (point) here)) - (goto-char here))) - (idlwave-make-space before)) - (skip-chars-forward " \t")) - (forward-char length) - (idlwave-make-space after) - ;; Check to see if the line should auto wrap - (if (and (equal (char-after (1- (point))) ?\ ) - (> (current-column) fill-column)) - (funcall auto-fill-function))))) - -(defun idlwave-make-space (n) - "Make space at point. -The space affected is all the spaces and tabs around point. -If n is non-nil then point is left abs(n) spaces from the beginning of -the contiguous space. -The amount of space at point is determined by N. -If the value of N is: -nil - do nothing. -> 0 - exactly N spaces. -< 0 - a minimum of -N spaces, i.e., do not change if there are - already -N spaces. -0 - no spaces (i.e. remove any existing space)." - (if (integerp n) - (let - ((start-col (progn (skip-chars-backward " \t") (current-column))) - (left (point)) - (end-col (progn (skip-chars-forward " \t") (current-column)))) - (delete-horizontal-space) - (cond - ((> n 0) - (idlwave-indent-to (+ start-col n)) - (goto-char (+ left n))) - ((< n 0) - (idlwave-indent-to end-col (- n)) - (goto-char (- left n))) - ;; n = 0, done - )))) - -(defun idlwave-newline () - "Insert a newline and indent the current and previous line." - (interactive) - ;; - ;; Handle unterminated single and double quotes - ;; If not in a comment and in a string then insertion of a newline - ;; will mean unbalanced quotes. - ;; - (if (and (not (idlwave-in-comment)) (idlwave-in-quote)) - (progn (beep) - (message "Warning: unbalanced quotes?"))) - (newline) - ;; - ;; The current line is being split, the cursor should be at the - ;; beginning of the new line skipping the leading indentation. - ;; - ;; The reason we insert the new line before indenting is that the - ;; indenting could be confused by keywords (e.g. END) on the line - ;; after the split point. This prevents us from just using - ;; `indent-for-tab-command' followed by `newline-and-indent'. - ;; - (beginning-of-line 0) - (idlwave-indent-line) - (forward-line) - (idlwave-indent-line)) - -;; -;; Use global variable 'comment-column' to set parallel comment -;; -;; Modeled on lisp.el -;; Emacs Lisp and IDL (Wave CL) have identical comment syntax -(defun idlwave-comment-hook () - "Compute indent for the beginning of the IDL comment delimiter." - (if (or (looking-at idlwave-no-change-comment) - (looking-at (or idlwave-begin-line-comment "^;"))) - (current-column) - (if (looking-at idlwave-code-comment) - (if (save-excursion (skip-chars-backward " \t") (bolp)) - ;; On line by itself, indent as code - (let ((tem (idlwave-calculate-indent))) - (if (listp tem) (car tem) tem)) - ;; after code - do not change - (current-column)) - (skip-chars-backward " \t") - (max (if (bolp) 0 (1+ (current-column))) - comment-column)))) - -(defun idlwave-split-line () - "Continue line by breaking line at point and indent the lines. -For a code line insert continuation marker. If the line is a line comment -then the new line will contain a comment with the same indentation. -Splits strings with the IDL operator `+' if `idlwave-split-line-string' is -non-nil." - (interactive) - ;; Expand abbreviation, just like normal RET would. - (and abbrev-mode (expand-abbrev)) - (let (beg) - (if (not (idlwave-in-comment)) - ;; For code line add continuation. - ;; Check if splitting a string. - (progn - (if (setq beg (idlwave-in-quote)) - (if idlwave-split-line-string - ;; Split the string. - (progn (insert (setq beg (char-after beg)) " + " - idlwave-continuation-char beg) - (backward-char 1) - (newline-and-indent) - (forward-char 1)) - ;; Do not split the string. - (beep) - (message "Warning: continuation inside string!!") - (insert " " idlwave-continuation-char)) - ;; Not splitting a string. - (if (not (member (char-before) '(?\ ?\t))) - (insert " ")) - (insert idlwave-continuation-char) - (newline-and-indent))) - (indent-new-comment-line)) - ;; Indent previous line - (setq beg (- (point-max) (point))) - (forward-line -1) - (idlwave-indent-line) - (goto-char (- (point-max) beg)) - ;; Reindent new line - (idlwave-indent-line))) - -(defun idlwave-beginning-of-subprogram (&optional nomark) - "Move point to the beginning of the current program unit. -If NOMARK is non-nil, do not push mark." - (interactive) - (idlwave-find-key idlwave-begin-unit-reg -1 nomark)) - -(defun idlwave-end-of-subprogram (&optional nomark) - "Move point to the start of the next program unit. -If NOMARK is non-nil, do not push mark." - (interactive) - (idlwave-end-of-statement) - (idlwave-find-key idlwave-end-unit-reg 1 nomark)) - -(defun idlwave-mark-statement () - "Mark current IDL statement." - (interactive) - (idlwave-end-of-statement) - (let ((end (point))) - (idlwave-beginning-of-statement) - (push-mark end nil t))) - -(defun idlwave-mark-block () - "Mark containing block." - (interactive) - (idlwave-end-of-statement) - (idlwave-backward-up-block -1) - (idlwave-end-of-statement) - (let ((end (point))) - (idlwave-backward-block) - (idlwave-beginning-of-statement) - (push-mark end nil t))) - - -(defun idlwave-mark-subprogram () - "Put mark at beginning of program, point at end. -The marks are pushed." - (interactive) - (idlwave-end-of-statement) - (idlwave-beginning-of-subprogram) - (let ((beg (point))) - (idlwave-forward-block) - (push-mark beg nil t)) - (exchange-point-and-mark)) - -(defun idlwave-backward-up-block (&optional arg) - "Move to beginning of enclosing block if prefix ARG >= 0. -If prefix ARG < 0 then move forward to enclosing block end." - (interactive "p") - (idlwave-block-jump-out (- arg) 'nomark)) - -(defun idlwave-beginning-of-block () - "Go to the beginning of the current block." - (interactive) - (idlwave-block-jump-out -1 'nomark) - (forward-word-strictly 1)) - -(defun idlwave-end-of-block () - "Go to the beginning of the current block." - (interactive) - (idlwave-block-jump-out 1 'nomark) - (backward-word-strictly 1)) - -(defun idlwave-forward-block (&optional arg) - "Move across next nested block." - (interactive) - (let ((arg (or arg 1))) - (if (idlwave-down-block arg) - (idlwave-block-jump-out arg 'nomark)))) - -(defun idlwave-backward-block () - "Move backward across previous nested block." - (interactive) - (if (idlwave-down-block -1) - (idlwave-block-jump-out -1 'nomark))) - -(defun idlwave-down-block (&optional arg) - "Go down a block. -With ARG: ARG >= 0 go forwards, ARG < 0 go backwards. -Returns non-nil if successful." - (interactive "p") - (let (status) - (if (< arg 0) - ;; Backward - (let ((eos (save-excursion - (idlwave-block-jump-out -1 'nomark) - (point)))) - (if (setq status (idlwave-find-key - idlwave-end-block-reg -1 'nomark eos)) - (idlwave-beginning-of-statement) - (message "No nested block before beginning of containing block."))) - ;; Forward - (let ((eos (save-excursion - (idlwave-block-jump-out 1 'nomark) - (point)))) - (if (setq status (idlwave-find-key - idlwave-begin-block-reg 1 'nomark eos)) - (idlwave-end-of-statement) - (message "No nested block before end of containing block.")))) - status)) - -(defun idlwave-mark-doclib () - "Put point at beginning of doc library header, mark at end. -The marks are pushed." - (interactive) - (let (beg - (here (point))) - (goto-char (point-max)) - (if (re-search-backward idlwave-doclib-start nil t) - (progn - (setq beg (progn (beginning-of-line) (point))) - (if (re-search-forward idlwave-doclib-end nil t) - (progn - (forward-line 1) - (push-mark beg nil t) - (message "Could not find end of doc library header."))) - (message "Could not find doc library header start.") - (goto-char here))))) - -(defun idlwave-current-routine-fullname () - (let ((name (idlwave-current-routine))) - (idlwave-make-full-name (nth 2 name) (car name)))) - -(defun idlwave-current-routine () - "Return (NAME TYPE CLASS) of current routine." - (idlwave-routines) - (save-excursion - (idlwave-beginning-of-subprogram 'nomark) - (if (looking-at "[ \t]*\\<\\(pro\\|function\\)\\>\\s-+\\(\\([a-zA-Z0-9$_]+\\)::\\)?\\([a-zA-Z0-9$_]+\\)") - (let* ((type (if (string= (downcase (match-string 1)) "pro") - 'pro 'function)) - (class (idlwave-sintern-class (match-string 3))) - (name (idlwave-sintern-routine-or-method (match-string 4) class))) - (list name type class))))) - -(defvar idlwave-shell-prompt-pattern) -(defun idlwave-beginning-of-statement () - "Move to beginning of the current statement. -Skips back past statement continuations. -Point is placed at the beginning of the line whether or not this is an -actual statement." - (interactive) - (cond - ((derived-mode-p 'idlwave-shell-mode) - (if (re-search-backward idlwave-shell-prompt-pattern nil t) - (goto-char (match-end 0)))) - (t - (if (save-excursion (forward-line -1) (idlwave-is-continuation-line)) - (idlwave-previous-statement) - (beginning-of-line))))) - -(defun idlwave-previous-statement () - "Move point to beginning of the previous statement. -Returns t if the current line before moving is the beginning of -the first non-comment statement in the file, and nil otherwise." - (interactive) - (let (first-statement) - (if (not (= (forward-line -1) 0)) - ;; first line in file - t - ;; skip blank lines, label lines, include lines and line comments - (while (and - ;; The current statement is the first statement until we - ;; reach another statement. - (setq first-statement - (or - (looking-at idlwave-comment-line-start-skip) - (looking-at "[ \t]*$") - (looking-at (concat "[ \t]*" idlwave-label "[ \t]*$")) - (looking-at "^@"))) - (= (forward-line -1) 0))) - ;; skip continuation lines - (while (and - (save-excursion - (forward-line -1) - (idlwave-is-continuation-line)) - (= (forward-line -1) 0))) - first-statement))) - -(defun idlwave-end-of-statement () - "Move point to the end of the current IDL statement. -If not in a statement just moves to end of line. Returns position." - (interactive) - (while (and (idlwave-is-continuation-line) - (= (forward-line 1) 0)) - (while (and (idlwave-is-comment-or-empty-line) - (= (forward-line 1) 0)))) - (end-of-line) - (point)) - -(defun idlwave-end-of-statement0 () - "Move point to the end of the current IDL statement. -If not in a statement just moves to end of line. Returns position." - (interactive) - (while (and (idlwave-is-continuation-line) - (= (forward-line 1) 0))) - (end-of-line) - (point)) - -(defun idlwave-next-statement () - "Move point to beginning of the next IDL statement. -Returns t if that statement is the last non-comment IDL statement -in the file, and nil otherwise." - (interactive) - (let (last-statement) - (idlwave-end-of-statement) - ;; skip blank lines, label lines, include lines and line comments - (while (and (= (forward-line 1) 0) - ;; The current statement is the last statement until - ;; we reach a new statement. - (setq last-statement - (or - (looking-at idlwave-comment-line-start-skip) - (looking-at "[ \t]*$") - (looking-at (concat "[ \t]*" idlwave-label "[ \t]*$")) - (looking-at "^@"))))) - last-statement)) - -(defun idlwave-skip-multi-commands (&optional lim) - "Skip past multiple commands on a line (with `&')." - (let ((save-point (point))) - (when (re-search-forward ".*&" lim t) - (goto-char (match-end 0)) - (if (idlwave-quoted) - (goto-char save-point) - (if (eq (char-after (- (point) 2)) ?&) (goto-char save-point)))) - (point))) - -(defun idlwave-skip-label-or-case () - "Skip label or case statement element. -Returns position after label. -If there is no label point is not moved and nil is returned." - ;; Case expressions and labels are terminated by a colon. - ;; So we find the first colon in the line and make sure - ;; - no `?' is before it (might be a ? b : c) - ;; - it is not in a comment - ;; - not in a string constant - ;; - not in parenthesis (like a[0:3]) - ;; - not followed by another ":" in explicit class, ala a->b::c - ;; As many in this mode, this function is heuristic and not an exact - ;; parser. - (let* ((start (point)) - (eos (save-excursion (idlwave-end-of-statement) (point))) - (end (idlwave-find-key ":" 1 'nomark eos))) - (if (and end - (= (nth 0 (parse-partial-sexp start end)) 0) - (not (string-search "?" (buffer-substring start end))) - (not (string-match "^::" (buffer-substring end eos)))) - (progn - (forward-char) - (point)) - (goto-char start) - nil))) - -(defun idlwave-start-of-substatement (&optional pre) - "Move to start of next IDL substatement after point. -Uses the type of the current IDL statement to determine if the next -statement is on a new line or is a subpart of the current statement. -Returns point at start of substatement modulo whitespace. -If optional argument is non-nil move to beginning of current -substatement." - (let ((orig (point)) - (eos (idlwave-end-of-statement)) - (ifnest 0) - st nst last) - (idlwave-beginning-of-statement) - (idlwave-skip-label-or-case) - (if (< (point) orig) - (idlwave-skip-multi-commands orig)) - (setq last (point)) - ;; Continue looking for substatements until we are past orig - (while (and (<= (point) orig) (not (eobp))) - (setq last (point)) - (setq nst (nth 1 (cdr (setq st (car (idlwave-statement-type)))))) - (if (equal (car st) 'if) (setq ifnest (1+ ifnest))) - (cond ((and nst - (idlwave-find-key nst 1 'nomark eos)) - (goto-char (match-end 0))) - ((and (> ifnest 0) (idlwave-find-key "\\" 1 'nomark eos)) - (setq ifnest (1- ifnest)) - (goto-char (match-end 0))) - (t (setq ifnest 0) - (idlwave-next-statement)))) - (if pre (goto-char last)) - ;; If a continuation line starts here, move to next line - (if (looking-at "[ \t]*\\$\\([ \t]*\\(;\\|$\\)\\)") - (beginning-of-line 2)) - (point))) - -(defun idlwave-statement-type () - "Return the type of the current IDL statement. -Uses `idlwave-statement-match' to return a cons of (type . point) with -point the ending position where the type was determined. Type is the -association from `idlwave-statement-match', i.e. the cons cell from the -list not just the type symbol. Returns nil if not an identifiable -statement." - (save-excursion - ;; Skip whitespace within a statement which is spaces, tabs, continuations - ;; and possibly comments - (while (looking-at "[ \t]*\\$") - (forward-line 1)) - (skip-chars-forward " \t") - (let ((st idlwave-statement-match) - (case-fold-search t)) - (while (and (not (looking-at (nth 0 (cdr (car st))))) - (setq st (cdr st)))) - (if st - (append st (match-end 0)))))) - -(defun idlwave-expand-equal (&optional before after _is-action) - "Pad `=' with spaces. -Two cases: Assignment statement, and keyword assignment. -Which case is determined using `idlwave-start-of-substatement' and -`idlwave-statement-type'. The equal sign will be surrounded by BEFORE -and AFTER blanks. If `idlwave-pad-keyword' is t then keyword assignment -is treated just like assignment statements. When nil, spaces are -removed for keyword assignment. Any other value keeps the current space -around the `='. Limits in for loops are treated as keyword assignment. - -Starting with IDL 6.0, a number of op= assignments are available. -Since ambiguities of the form: - -r and= b -rand= b - -can occur, alphanumeric operator assignment will never be pre-padded, -only post-padded. You must use a space before these to disambiguate -\(not just for padding, but for proper parsing by IDL too!). Other -operators, such as ##=, ^=, etc., will be pre-padded. - -IS-ACTION is ignored. - -See `idlwave-surround'." - (if idlwave-surround-by-blank - (let - ((non-an-ops "\\(##\\|\\*\\|\\+\\|-\\|/\\|<\\|>\\|\\^\\)\\=") - (an-ops - "\\s-\\(AND\\|EQ\\|GE\\|GT\\|LE\\|LT\\|MOD\\|NE\\|OR\\|XOR\\)\\=") - (len 1)) - - (save-excursion - (let ((case-fold-search t)) - (backward-char) - (if (or - (re-search-backward non-an-ops nil t) - ;; Why doesn't ##? work for both? - (re-search-backward "\\(#\\)\\=" nil t)) - (setq len (1+ (length (match-string 1)))) - (when (re-search-backward an-ops nil t) - ;(setq begin nil) ; won't modify begin - (setq len (1+ (length (match-string 1)))))))) - - (if (eq t idlwave-pad-keyword) - ;; Everything gets padded equally - (idlwave-surround before after len) - ;; Treating keywords/for variables specially... - (let ((st (save-excursion ; To catch "for" variables - (idlwave-start-of-substatement t) - (idlwave-statement-type))) - (what (save-excursion ; To catch keywords - (skip-chars-backward "= \t") - (nth 2 (idlwave-where))))) - (cond ((or (memq what '(function-keyword procedure-keyword)) - (memq (caar st) '(for pdef))) - (cond - ((null idlwave-pad-keyword) - (idlwave-surround 0 0) - ) ; remove space - (t))) ; leave any spaces alone - (t (idlwave-surround before after len)))))))) - - -(defun idlwave-indent-and-action (&optional arg) - "Call `idlwave-indent-line' and do expand actions. -With prefix ARG non-nil, indent the entire sub-statement." - (interactive "p") - (save-excursion - (if (and idlwave-expand-generic-end - (re-search-backward "\\<\\(end\\)\\s-*\\=" - (max 0 (- (point) 10)) t) - (looking-at "\\(end\\)\\([ \n\t]\\|\\'\\)")) - (progn (goto-char (match-end 1)) - ;;Expand the END abbreviation, just as RET or Space would have. - (if abbrev-mode (expand-abbrev) - (idlwave-show-begin))))) - (when (and (not arg) current-prefix-arg) - (setq arg current-prefix-arg) - (setq current-prefix-arg nil)) - (if arg - (idlwave-indent-statement) - (idlwave-indent-line t))) - -(defun idlwave-indent-line (&optional expand) - "Indent current IDL line as code or as a comment. -The actions in `idlwave-indent-action-table' are performed. -If the optional argument EXPAND is non-nil then the actions in -`idlwave-indent-expand-table' are performed." - (interactive) - ;; Move point out of left margin. - (if (save-excursion - (skip-chars-backward " \t") - (bolp)) - (skip-chars-forward " \t")) - (let ((mloc (point-marker))) - (save-excursion - (beginning-of-line) - (if (looking-at idlwave-comment-line-start-skip) - ;; Indentation for a line comment - (progn - (skip-chars-forward " \t") - (idlwave-indent-left-margin (idlwave-comment-hook))) - ;; - ;; Code Line - ;; - ;; Before indenting, run action routines. - ;; - (if (and expand idlwave-do-actions) - (mapc #'idlwave-do-action idlwave-indent-expand-table)) - ;; - (if idlwave-do-actions - (mapc #'idlwave-do-action idlwave-indent-action-table)) - ;; - ;; No longer expand abbrevs on the line. The user can do this - ;; manually using expand-region-abbrevs. - ;; - ;; Indent for code line - ;; - (beginning-of-line) - (if (or - ;; a label line - (looking-at (concat "^" idlwave-label "[ \t]*$")) - ;; a batch command - (looking-at "^[ \t]*@")) - ;; leave flush left - nil - ;; indent the line - (idlwave-indent-left-margin (idlwave-calculate-indent))) - ;; Adjust parallel comment - (end-of-line) - (if (idlwave-in-comment) - (let ((fill-column (1- (frame-width)))) - (indent-for-comment))))) - (goto-char mloc) - ;; Get rid of marker - (set-marker mloc nil))) - -(defun idlwave-do-action (action) - "Perform an action repeatedly on a line. -ACTION is a list (REG . FUNC). REG is a regular expression. FUNC is -either a function which will be called with one argument `is-action' or -a list to be evaluated with `eval'. -The action performed by FUNC should leave point after the match for REG -- otherwise an infinite loop may be entered. -FUNC is always passed a final argument of `is-action', so it -can discriminate between being run as an action, or a key binding." - (let ((action-key (car action)) - (action-routine (cdr action))) - (beginning-of-line) - (while (idlwave-look-at action-key) - (if (functionp action-routine) - (funcall action-routine 'is-action) - (eval (append action-routine '('is-action)) t))))) - -(defun idlwave-indent-to (col &optional min) - "Indent from point with spaces until column COL. -Inserts space before markers at point." - (if (not min) (setq min 0)) - (insert-before-markers - (make-string (max min (- col (current-column))) ?\ ))) - -(defun idlwave-indent-left-margin (col) - "Indent the current line to column COL. -Indents such that first non-whitespace character is at column COL -Inserts spaces before markers at point." - (save-excursion - (beginning-of-line) - (delete-horizontal-space) - (idlwave-indent-to col))) - -(defun idlwave-indent-subprogram () - "Indent program unit which contains point." - (interactive) - (save-excursion - (idlwave-end-of-statement) - (idlwave-beginning-of-subprogram) - (let ((beg (point))) - (idlwave-forward-block) - (message "Indenting subprogram...") - (indent-region beg (point) nil)) - (message "Indenting subprogram...done."))) - -(defun idlwave-indent-statement () - "Indent current statement, including all continuation lines." - (interactive) - (save-excursion - (idlwave-beginning-of-statement) - (let ((beg (point))) - (idlwave-end-of-statement) - (indent-region beg (point) nil)))) - -(defun idlwave-calculate-indent () - "Return appropriate indentation for current line as IDL code." - (save-excursion - (beginning-of-line) - (cond - ;; Check for beginning of unit - main (beginning of buffer), pro, or - ;; function - ((idlwave-look-at idlwave-begin-unit-reg) - 0) - ;; Check for continuation line - ((save-excursion - (and (= (forward-line -1) 0) - (idlwave-is-continuation-line))) - (idlwave-calculate-cont-indent)) - ;; calculate indent based on previous and current statements - (t (let* (beg-prev-pos - (the-indent - ;; calculate indent based on previous statement - (save-excursion - (cond - ;; Beginning of file - ((prog1 - (idlwave-previous-statement) - (setq beg-prev-pos (point))) - 0) - ;; Main block - ((idlwave-look-at idlwave-begin-unit-reg t) - (+ (idlwave-current-statement-indent) - idlwave-main-block-indent)) - ;; Begin block - ((idlwave-look-at idlwave-begin-block-reg t) - (+ (idlwave-min-current-statement-indent) - idlwave-block-indent)) - ;; End Block - ((idlwave-look-at idlwave-end-block-reg t) - (progn - ;; Match to the *beginning* of the block opener - (goto-char beg-prev-pos) - (idlwave-block-jump-out -1 'nomark) ; go to begin block - (idlwave-min-current-statement-indent))) - ;; idlwave-end-offset - ;; idlwave-block-indent)) - - ;; Default to current indent - ((idlwave-current-statement-indent)))))) - ;; adjust the indentation based on the current statement - (cond - ;; End block - ((idlwave-look-at idlwave-end-block-reg) - (+ the-indent idlwave-end-offset)) - (the-indent))))))) - -;; -;; Parentheses indent -;; - -(defun idlwave-calculate-paren-indent (beg-reg end-reg close-exp) - "Calculate the continuation indent inside a paren group. -Returns a cons-cell with (open . indent), where open is the -location of the open paren." - (let ((open (nth 1 (parse-partial-sexp beg-reg end-reg)))) - ;; Found an innermost open paren. - (when open - (goto-char open) - ;; Line up with next word unless this is a closing paren. - (cons open - (cond - ;; Plain Kernighan-style nested indent - (idlwave-indent-parens-nested - (+ idlwave-continuation-indent (idlwave-current-indent))) - - ;; This is a closed paren - line up under open paren. - (close-exp - (current-column)) - - ;; Empty (or just comment) follows -- revert to basic indent - ((progn - ;; Skip paren - (forward-char 1) - (looking-at "[ \t$]*\\(;.*\\)?$")) - nil) - - ;; Line up with first word after any blank space - ((progn - (skip-chars-forward " \t") - (current-column)))))))) - -(defun idlwave-calculate-cont-indent () - "Calculates the IDL continuation indent column from the previous statement. -Note that here previous statement usually means the beginning of the -current statement if this statement is a continuation of the previous -line. Various special types of continuations, including assignments, -routine definitions, and parenthetical groupings, are treated separately." - (save-excursion - (let* ((case-fold-search t) - (end-reg (progn (beginning-of-line) (point))) - (beg-last-statement (save-excursion (idlwave-previous-statement) - (point))) - (beg-reg (progn (idlwave-start-of-substatement 'pre) - (if (eq (line-beginning-position) end-reg) - (goto-char beg-last-statement) - (point)))) - (basic-indent (+ (idlwave-min-current-statement-indent end-reg) - idlwave-continuation-indent)) - fancy-nonparen-indent fancy-paren-indent) - (cond - ;; Align then with its matching if, etc. - ((let ((matchers '(("\\" . "[ \t]*then") - ("\\<\\(if\\|end\\(if\\)?\\)\\>" . "[ \t]*else") - ("\\<\\(for\\|while\\)\\>" . "[ \t]*do") - ("\\<\\(repeat\\|end\\(rep\\)?\\)\\>" . - "[ \t]*until") - ("\\" . "[ \t]*of"))) - match cont-re) - (goto-char end-reg) - (and - (setq cont-re - (catch 'exit - (while (setq match (car matchers)) - (if (looking-at (cdr match)) - (throw 'exit (car match))) - (setq matchers (cdr matchers))))) - (idlwave-find-key cont-re -1 'nomark beg-last-statement))) - (if (looking-at "end") ;; that one's special - (- (idlwave-current-indent) - (+ idlwave-block-indent idlwave-end-offset)) - (idlwave-current-indent))) - - ;; Indent in from the previous line for continuing statements - ((let ((matchers '("\\" - "\\" - "\\" - "\\")) - match) - (catch 'exit - (goto-char end-reg) - (if (/= (forward-line -1) 0) - (throw 'exit nil)) - (while (setq match (car matchers)) - (if (looking-at (concat ".*" match "[ \t]*\\$[ \t]*" - "\\(;.*\\)?$")) - (throw 'exit t)) - (setq matchers (cdr matchers))))) - (+ idlwave-continuation-indent (idlwave-current-indent))) - - ;; Parenthetical indent, either traditional or Kernighan style - ((setq fancy-paren-indent - (let* ((end-reg end-reg) - (close-exp (progn - (goto-char end-reg) - (skip-chars-forward " \t") - (looking-at "\\s)"))) - indent-cons) - (catch 'loop - (while (setq indent-cons (idlwave-calculate-paren-indent - beg-reg end-reg close-exp)) - ;; First permitted containing paren - (if (or - idlwave-indent-to-open-paren - idlwave-indent-parens-nested - (null (cdr indent-cons)) - (< (- (cdr indent-cons) basic-indent) - idlwave-max-extra-continuation-indent)) - (throw 'loop (cdr indent-cons))) - (setq end-reg (car indent-cons)))))) - fancy-paren-indent) - - ;; A continued assignment, or procedure call/definition - ((and - (> idlwave-max-extra-continuation-indent 0) - (setq fancy-nonparen-indent - (progn - (goto-char beg-reg) - (while (idlwave-look-at "&")) ; skip continued statements - (cond - ;; A continued Procedure call or definition - ((progn - (idlwave-look-at "^[ \t]*\\(pro\\|function\\)") ;skip over - (looking-at "[ \t]*\\([a-zA-Z0-9.$_]+[ \t]*->[ \t]*\\)?[a-zA-Z][:a-zA-Z0-9$_]*[ \t]*\\(,\\)[ \t]*")) - (goto-char (match-end 0)) - ;; Comment only, or blank line with "$"? Basic indent. - (if (save-match-data (looking-at "[ \t$]*\\(;.*\\)?$")) - nil - (current-column))) - - ;; Continued assignment (with =): - ((catch 'assign ; - (while (looking-at "[^=\n\r]*\\(=\\)[ \t]*") - (goto-char (match-end 0)) - (if (null (idlwave-what-function beg-reg)) - (throw 'assign t)))) - (unless (or - (idlwave-in-quote) - (looking-at "[ \t$]*\\(;.*\\)?$") ; use basic - (save-excursion - (goto-char beg-last-statement) - (eq (caar (idlwave-statement-type)) 'for))) - (current-column)))))) - (< (- fancy-nonparen-indent basic-indent) - idlwave-max-extra-continuation-indent)) - (if fancy-paren-indent ;calculated but disallowed paren indent - (+ fancy-nonparen-indent idlwave-continuation-indent) - fancy-nonparen-indent)) - - ;; Basic indent, by default - (t basic-indent))))) - - - -(defun idlwave-find-key (key-re &optional dir nomark limit) - "Move to next match of the regular expression KEY-RE. -Matches inside comments or string constants will be ignored. -If DIR is negative, the search will be backwards. -At a successful match, the mark is pushed unless NOMARK is non-nil. -Searches are limited to LIMIT. -Searches are case-insensitive and use a special syntax table which -treats `$' and `_' as word characters. -Return value is the beginning of the match or (in case of failure) nil." - (setq dir (or dir 0)) - (let ((case-fold-search t) - (search-func (if (> dir 0) 're-search-forward 're-search-backward)) - found) - (with-syntax-table idlwave-find-symbol-syntax-table - (save-excursion - (catch 'exit - (while (funcall search-func key-re limit t) - (if (not (idlwave-quoted)) - (throw 'exit (setq found (match-beginning 0))) - (if (or (and (> dir 0) (eobp)) - (and (< dir 0) (bobp))) - (throw 'exit nil))))))) - (if found - (progn - (if (not nomark) (push-mark)) - (goto-char found) - found) - nil))) - -(defun idlwave-block-jump-out (&optional dir nomark) - "When optional argument DIR is non-negative, move forward to end of -current block using the `idlwave-begin-block-reg' and `idlwave-end-block-reg' -regular expressions. When DIR is negative, move backwards to block beginning. -Recursively calls itself to skip over nested blocks. DIR defaults to -forward. Calls `push-mark' unless the optional argument NOMARK is -non-nil. Movement is limited by the start of program units because of -possibility of unbalanced blocks." - (interactive "P") - (or dir (setq dir 0)) - (let* ((here (point)) - (case-fold-search t) - (limit (if (>= dir 0) (point-max) (point-min))) - (block-limit (if (>= dir 0) - idlwave-begin-block-reg - idlwave-end-block-reg)) - found - (block-reg (concat idlwave-begin-block-reg "\\|" - idlwave-end-block-reg)) - (unit-limit (or (save-excursion - (if (< dir 0) - (idlwave-find-key - idlwave-begin-unit-reg dir t limit) - (end-of-line) - (idlwave-find-key - idlwave-end-unit-reg dir t limit))) - limit))) - (if (>= dir 0) (end-of-line)) ;Make sure we are in current block - (if (setq found (idlwave-find-key block-reg dir t unit-limit)) - (while (and found (looking-at block-limit)) - (if (>= dir 0) (forward-word-strictly 1)) - (idlwave-block-jump-out dir t) - (setq found (idlwave-find-key block-reg dir t unit-limit)))) - (if (not nomark) (push-mark here)) - (if (not found) (goto-char unit-limit) - (if (>= dir 0) (forward-word-strictly 1))))) - -(defun idlwave-min-current-statement-indent (&optional end-reg) - "The minimum indent in the current statement." - (idlwave-beginning-of-statement) - (if (not (idlwave-is-continuation-line)) - (idlwave-current-indent) - (let ((min (idlwave-current-indent)) comm-or-empty) - (while (and (= (forward-line 1) 0) - (or (setq comm-or-empty (idlwave-is-comment-or-empty-line)) - (idlwave-is-continuation-line)) - (or (null end-reg) (< (point) end-reg))) - (unless comm-or-empty (setq min (min min (idlwave-current-indent))))) - (if (or comm-or-empty (and end-reg (>= (point) end-reg))) - min - (min min (idlwave-current-indent)))))) - -(defun idlwave-current-statement-indent (&optional last-line) - "Return indentation of the current statement. -If in a statement, moves to beginning of statement before finding indent." - (if last-line - (idlwave-end-of-statement) - (idlwave-beginning-of-statement)) - (idlwave-current-indent)) - -(defun idlwave-current-indent () - "Return the column of the indentation of the current line. -Skips any whitespace. Returns 0 if the end-of-line follows the whitespace." - (save-excursion - (beginning-of-line) - (skip-chars-forward " \t") - ;; if we are at the end of blank line return 0 - (cond ((eolp) 0) - ((current-column))))) - -(defun idlwave-is-continuation-line () - "Test if current line is continuation line. -Blank or comment-only lines following regular continuation lines (with -`$') count as continuations too." - (let (p) - (save-excursion - (or - (idlwave-look-at "\\<\\$") - (catch 'loop - (while (and (looking-at "^[ \t]*\\(;.*\\)?$") - (eq (forward-line -1) 0)) - (if (setq p (idlwave-look-at "\\<\\$")) (throw 'loop p)))))))) - -(defun idlwave-is-comment-line () - "Test if the current line is a comment line." - (save-excursion - (beginning-of-line 1) - (looking-at "[ \t]*;"))) - -(defun idlwave-is-comment-or-empty-line () - "Test if the current line is a comment line." - (save-excursion - (beginning-of-line 1) - (looking-at "[ \t]*[;\n]"))) - -(defun idlwave-look-at (regexp &optional cont beg) - "Search current line from current point for REGEXP. -If optional argument CONT is non-nil, searches to the end of -the current statement. -If optional arg BEG is non-nil, search starts from the beginning of the -current statement. -Ignores matches that end in a comment or inside a string expression. -Returns point if successful, nil otherwise. -This function produces unexpected results if REGEXP contains quotes or -a comment delimiter. The search is case insensitive. -If successful leaves point after the match, otherwise, does not move point." - (let ((here (point)) - (case-fold-search t) - (eos (save-excursion - (if cont (idlwave-end-of-statement) (end-of-line)) - (point))) - found) - (with-syntax-table idlwave-find-symbol-syntax-table - (if beg (idlwave-beginning-of-statement)) - (while (and (setq found (re-search-forward regexp eos t)) - (idlwave-quoted)))) - (if (not found) (goto-char here)) - found)) - -(defun idlwave-fill-paragraph (&optional nohang) - "Fill paragraphs in comments. -A paragraph is made up of all contiguous lines having the same comment -leader (the leading whitespace before the comment delimiter and the -comment delimiter). In addition, paragraphs are separated by blank -line comments. The indentation is given by the hanging indent of the -first line, otherwise by the minimum indentation of the lines after -the first line. The indentation of the first line does not change. -Does not effect code lines. Does not fill comments on the same line -with code. The hanging indent is given by the end of the first match -matching `idlwave-hang-indent-regexp' on the paragraph's first line. -If the optional argument NOHANG is non-nil then the hanging indent is -ignored." - (interactive "P") - ;; check if this is a line comment - (if (save-excursion - (beginning-of-line) - (skip-chars-forward " \t") - (looking-at comment-start)) - (let - ((indent 999) - pre here diff fill-prefix-reg bcl first-indent - hang start end) - ;; Change tabs to spaces in the surrounding paragraph. - ;; The surrounding paragraph will be the largest containing block of - ;; contiguous line comments. Thus, we may be changing tabs in - ;; a much larger area than is needed, but this is the easiest - ;; brute force way to do it. - ;; - ;; This has the undesirable side effect of replacing the tabs - ;; permanently without the user's request or knowledge. - (save-excursion - (backward-paragraph) - (setq start (point))) - (save-excursion - (forward-paragraph) - (setq end (point))) - (untabify start end) - ;; - (setq here (point)) - (beginning-of-line) - (setq bcl (point)) - (re-search-forward (concat "^[ \t]*" comment-start "+") - (line-end-position) t) - ;; Get the comment leader on the line and its length - (setq pre (current-column)) - ;; the comment leader is the indentation plus exactly the - ;; number of consecutive ";". - (setq fill-prefix-reg - (concat - (setq fill-prefix - (regexp-quote (buffer-substring (line-beginning-position) - (point)))) - "[^;]")) - - ;; Mark the beginning and end of the paragraph - (goto-char bcl) - (while (and (looking-at fill-prefix-reg) - (not (looking-at paragraph-separate)) - (not (bobp))) - (forward-line -1)) - ;; Move to first line of paragraph - (if (/= (point) bcl) - (forward-line 1)) - (setq start (point)) - (goto-char bcl) - (while (and (looking-at fill-prefix-reg) - (not (looking-at paragraph-separate)) - (not (eobp))) - (forward-line 1)) - (beginning-of-line) - (if (or (not (looking-at fill-prefix-reg)) - (looking-at paragraph-separate)) - (forward-line -1)) - (end-of-line) - ;; if at end of buffer add a newline (need this because - ;; fill-region needs END to be at the beginning of line after - ;; the paragraph or it will add a line). - (if (eobp) - (progn (insert ?\n) (backward-char 1))) - ;; Set END to the beginning of line after the paragraph - ;; END is calculated as distance from end of buffer - (setq end (- (point-max) (point) 1)) - ;; - ;; Calculate the indentation for the paragraph. - ;; - ;; In the following while statements, after one iteration - ;; point will be at the beginning of a line in which case - ;; the while will not be executed for the - ;; first paragraph line and thus will not affect the - ;; indentation. - ;; - ;; First check to see if indentation is based on hanging indent. - (if (and (not nohang) idlwave-hanging-indent - (setq hang - (save-excursion - (goto-char start) - (idlwave-calc-hanging-indent)))) - ;; Adjust lines of paragraph by inserting spaces so that - ;; each line's indent is at least as great as the hanging - ;; indent. This is needed for fill-paragraph to work with - ;; a fill-prefix. - (progn - (setq indent hang) - (beginning-of-line) - (while (> (point) start) - (re-search-forward comment-start-skip (line-end-position) t) - (if (> (setq diff (- indent (current-column))) 0) - (progn - (if (>= here (point)) - ;; adjust the original location for the - ;; inserted text. - (setq here (+ here diff))) - (insert (make-string diff ?\ )))) - (forward-line -1)) - ) - - ;; No hang. Instead find minimum indentation of paragraph - ;; after first line. - ;; For the following while statement, since START is at the - ;; beginning of line and END is at the end of line - ;; point is greater than START at least once (which would - ;; be the case for a single line paragraph). - (while (> (point) start) - (beginning-of-line) - (setq indent - (min indent - (progn - (re-search-forward comment-start-skip (line-end-position) t) - (current-column)))) - (forward-line -1))) - (setq fill-prefix (concat fill-prefix - (make-string (- indent pre) - ?\ ))) - ;; first-line indent - (setq first-indent - (max - (progn - (re-search-forward comment-start-skip (line-end-position) t) - (current-column)) - indent)) - - ;; try to keep point at its original place - (goto-char here) - - ;; In place of the more modern fill-region-as-paragraph, a hack - ;; to keep whitespace untouched on the first line within the - ;; indent length and to preserve any indent on the first line - ;; (first indent). - (save-excursion - (setq diff - (buffer-substring start (+ start first-indent -1))) - (subst-char-in-region start (+ start first-indent -1) ?\ ?~ nil) - (fill-region-as-paragraph - start - (- (point-max) end) - (current-justification) - nil) - (delete-region start (+ start first-indent -1)) - (goto-char start) - (insert diff)) - ;; When we want the point at the beginning of the comment - ;; body fill-region will put it at the beginning of the line. - (if (bolp) (skip-chars-forward (concat " \t" comment-start))) - (setq fill-prefix nil)))) - -(defun idlwave-calc-hanging-indent () - "Calculate the position of the hanging indent for the comment paragraph. -The hanging indent position is given by the first match with the -`idlwave-hang-indent-regexp'. If `idlwave-use-last-hang-indent' is -non-nil then use last occurrence matching `idlwave-hang-indent-regexp' -on the line. -If not found returns nil." - (if idlwave-use-last-hang-indent - (save-excursion - (end-of-line) - (if (re-search-backward idlwave-hang-indent-regexp (line-beginning-position) t) - (+ (current-column) (length idlwave-hang-indent-regexp)))) - (save-excursion - (beginning-of-line) - (if (re-search-forward idlwave-hang-indent-regexp (line-end-position) t) - (current-column))))) - -(defun idlwave-auto-fill () - "Called to break lines in auto fill mode. -Only fills non-comment lines if `idlwave-fill-comment-line-only' is -non-nil. Places a continuation character at the end of the line if -not in a comment. Splits strings with IDL concatenation operator `+' -if `idlwave-auto-fill-split-string' is non-nil." - (if (<= (current-column) fill-column) - nil ; do not to fill - (if (or (not idlwave-fill-comment-line-only) - (save-excursion - ;; Check for comment line - (beginning-of-line) - (looking-at idlwave-comment-line-start-skip))) - (let (beg) - (idlwave-indent-line) - ;; Prevent actions do-auto-fill which calls indent-line-function. - (let (idlwave-do-actions - (paragraph-separate ".") - (fill-nobreak-predicate - (if (and (idlwave-in-quote) - idlwave-auto-fill-split-string) - (lambda () ;; We'll need 5 spaces for " ' + $" - (<= (- fill-column (current-column)) 5) - )))) - (do-auto-fill)) - (save-excursion - (end-of-line 0) - ;; Indent the split line - (idlwave-indent-line)) - (if (save-excursion - (beginning-of-line) - (looking-at idlwave-comment-line-start-skip)) - ;; A continued line comment - ;; We treat continued line comments as part of a comment - ;; paragraph. So we check for a hanging indent. - (if idlwave-hanging-indent - (let ((here (- (point-max) (point))) - (indent - (save-excursion - (forward-line -1) - (idlwave-calc-hanging-indent)))) - (when indent - ;; Remove whitespace between comment delimiter and - ;; text, insert spaces for appropriate indentation. - (beginning-of-line) - (re-search-forward comment-start-skip (line-end-position) t) - (delete-horizontal-space) - (idlwave-indent-to indent) - (goto-char (- (point-max) here))))) - ;; Split code or comment? - (if (save-excursion - (end-of-line 0) - (idlwave-in-comment)) - ;; Splitting a non-full-line comment. - ;; Insert the comment delimiter from split line - (progn - (save-excursion - (beginning-of-line) - (skip-chars-forward " \t") - ;; Insert blank to keep off beginning of line - (insert " " - (save-excursion - (forward-line -1) - (buffer-substring (idlwave-goto-comment) - (progn - (skip-chars-forward "; ") - (point)))))) - (idlwave-indent-line)) - ;; Split code line - add continuation character - (save-excursion - (end-of-line 0) - ;; Check to see if we split a string - (if (and (setq beg (idlwave-in-quote)) - idlwave-auto-fill-split-string) - ;; Split the string and concatenate. - ;; The first extra space is for the space - ;; the line was split. That space was removed. - (insert " " (char-after beg) " +")) - (insert " $")) - (if beg - (if idlwave-auto-fill-split-string - ;; Make the second part of continued string - (save-excursion - (beginning-of-line) - (skip-chars-forward " \t") - (insert (char-after beg))) - ;; Warning - (beep) - (message "Warning: continuation inside a string."))) - ;; Although do-auto-fill (via indent-new-comment-line) calls - ;; idlwave-indent-line for the new line, re-indent again - ;; because of the addition of the continuation character. - (idlwave-indent-line)) - ))))) - -(define-obsolete-function-alias 'idlwave-auto-fill-mode #'auto-fill-mode "28.1") - -(defun idlwave-doc-header (&optional nomark) - "Insert a documentation header at the beginning of the unit. -Inserts the value of the variable `idlwave-file-header'. Sets mark -before moving to do insertion unless the optional prefix argument -NOMARK is non-nil." - (interactive "P") - (or nomark (push-mark)) - ;; make sure we catch the current line if it begins the unit - (if idlwave-header-to-beginning-of-file - (goto-char (point-min)) - (end-of-line) - (idlwave-beginning-of-subprogram) - (beginning-of-line) - ;; skip function or procedure line - (if (idlwave-look-at "\\<\\(pro\\|function\\)\\>") - (progn - (idlwave-end-of-statement) - (if (> (forward-line 1) 0) (insert "\n"))))) - (let ((pos (point))) - (if idlwave-file-header - (cond ((car idlwave-file-header) - (insert-file-contents (car idlwave-file-header))) - ((stringp (car (cdr idlwave-file-header))) - (insert (car (cdr idlwave-file-header)))))) - (goto-char pos))) - -(defun idlwave-default-insert-timestamp () - "Default timestamp insertion function." - (insert (current-time-string)) - (insert ", " (user-full-name)) - (if (boundp 'user-mail-address) - (insert " <" user-mail-address ">") - (insert " <" (user-login-name) "@" (system-name) ">")) - ;; Remove extra spaces from line - (idlwave-fill-paragraph) - ;; Insert a blank line comment to separate from the date entry - - ;; will keep the entry from flowing onto date line if re-filled. - (insert "\n;\n;\t\t")) - -(defun idlwave-doc-modification () - "Insert a brief modification log at the beginning of the current program. -Looks for an occurrence of the value of user variable -`idlwave-doc-modifications-keyword' if non-nil. Inserts time and user -name and places the point for the user to add a log. Before moving, saves -location on mark ring so that the user can return to previous point." - (interactive) - (push-mark) - (let* (beg end) - (if (and (or (re-search-backward idlwave-doclib-start nil t) - (progn - (goto-char (point-min)) - (re-search-forward idlwave-doclib-start nil t))) - (setq beg (match-beginning 0)) - (re-search-forward idlwave-doclib-end nil t) - (setq end (match-end 0))) - (progn - (goto-char beg) - (if (re-search-forward - (concat idlwave-doc-modifications-keyword ":") - end t) - (end-of-line) - (goto-char end) - (end-of-line -1) - (insert "\n" comment-start "\n") - (insert comment-start " " idlwave-doc-modifications-keyword ":")) - (insert "\n;\n;\t") - (run-hooks 'idlwave-timestamp-hook)) - (error "No valid DOCLIB header")))) - - -;; CJC 3/16/93 -;; Interface to expand-region-abbrevs which did not work when the -;; abbrev hook associated with an abbrev moves point backwards -;; after abbrev expansion, e.g., as with the abbrev '.n'. -;; The original would enter an infinite loop in attempting to expand -;; .n (it would continually expand and unexpand the abbrev without expanding -;; because the point would keep going back to the beginning of the -;; abbrev instead of to the end of the abbrev). We now keep the -;; abbrev hook from moving backwards. -;;; -(defun idlwave-expand-region-abbrevs (start end) - "Expand each abbrev occurrence in the region. -Calling from a program, arguments are START END." - (interactive "r") - (save-excursion - (goto-char (min start end)) - (let ((idlwave-show-block nil) ;Do not blink - (idlwave-abbrev-move nil)) ;Do not move - (expand-region-abbrevs start end 'noquery)))) - -(defun idlwave-quoted () - "Return t if point is in a comment or quoted string. -Returns nil otherwise." - ;; FIXME: Use (nth 8 (synx-ppss))! - (and (or (idlwave-in-comment) (idlwave-in-quote)) t)) - -(defun idlwave-in-quote () - "Return location of the opening quote -if point is in a IDL string constant, nil otherwise. -Ignores comment delimiters on the current line. -Properly handles nested quotation marks and octal -constants - a double quote followed by an octal digit." -;; Treat an octal inside an apostrophe to be a normal string. Treat a -;; double quote followed by an octal digit to be an octal constant -;; rather than a string. Therefore, there is no terminating double -;; quote. - (save-excursion - ;; Because single and double quotes can quote each other we must - ;; search for the string start from the beginning of line. - (let* ((start (point)) - (eol (line-end-position)) - (bq (progn (beginning-of-line) (point))) - (endq (point)) - (data (match-data)) - delim - found) - (while (< endq start) - ;; Find string start - ;; Don't find an octal constant beginning with a double quote - (if (re-search-forward "[\"']" eol 'lim) - ;; Find the string end. - ;; In IDL, two consecutive delimiters after the start of a - ;; string act as an - ;; escape for the delimiter in the string. - ;; Two consecutive delimiters alone (i.e., not after the - ;; start of a string) is the null string. - (progn - ;; Move to position after quote - (goto-char (1+ (match-beginning 0))) - (setq bq (1- (point))) - ;; Get the string delimiter - (setq delim (char-to-string (preceding-char))) - ;; Check for null string - (if (looking-at delim) - (progn (setq endq (point)) (forward-char 1)) - ;; Look for next unpaired delimiter - (setq found (search-forward delim eol 'lim)) - (while (looking-at delim) - (forward-char 1) - (setq found (search-forward delim eol 'lim))) - (setq endq (if found (1- (point)) (point))) - )) - (progn (setq bq (point)) (setq endq (point))))) - (store-match-data data) - ;; return string beginning position or nil - (if (> start bq) bq)))) - -(defun idlwave-is-pointer-dereference (&optional limit) - "Determine if the character after point is a pointer dereference *." - (and - (eq (char-after) ?\*) - (not (idlwave-in-quote)) - (save-excursion - (forward-char) - (re-search-backward (concat "\\(" idlwave-idl-keywords - "\\|[-[(*+/=,^><]\\)\\s-*\\*") limit t)))) - - -;; Statement templates - -;; Replace these with a general template function, something like -;; expand.el (I think there was also something with a name similar to -;; dmacro.el) - -(defun idlwave-template (s1 s2 &optional prompt noindent) - "Build a template with optional prompt expression. - -Opens a line if point is not followed by a newline modulo intervening -whitespace. S1 and S2 are strings. S1 is inserted at point followed -by S2. Point is inserted between S1 and S2. The case of S1 and S2 is -adjusted according to `idlwave-abbrev-change-case'. If optional -argument PROMPT is a string then it is displayed as a message in the -minibuffer. The PROMPT serves as a reminder to the user of an -expression to enter. - -The lines containing S1 and S2 are reindented using `indent-region' -unless the optional second argument NOINDENT is non-nil." - (if (derived-mode-p 'idlwave-shell-mode) - ;; This is a gross hack to avoid template abbrev expansion - ;; in the shell. FIXME: This is a dirty hack. - (if (and (eq this-command 'self-insert-command) - (equal last-abbrev-location (point))) - (insert last-abbrev-text) - (error "No templates in idlwave-shell")) - (cond ((eq idlwave-abbrev-change-case 'down) - (setq s1 (downcase s1) s2 (downcase s2))) - (idlwave-abbrev-change-case - (setq s1 (upcase s1) s2 (upcase s2)))) - (let ((beg (line-beginning-position)) - end) - (if (not (looking-at "\\s-*\n")) - (open-line 1)) - (insert s1) - (save-excursion - (insert s2) - (setq end (point))) - (if (not noindent) - (indent-region beg end nil)) - (if (stringp prompt) - (message "%s" prompt))))) - -(defun idlwave-rw-case (string) - "Make STRING have the case required by `idlwave-reserved-word-upcase'." - (if idlwave-reserved-word-upcase - (upcase string) - string)) - -(defun idlwave-elif () - "Build skeleton IDL if-else block." - (interactive) - (idlwave-template - (idlwave-rw-case "if") - (idlwave-rw-case " then begin\n\nendif else begin\n\nendelse") - "Condition expression")) - -(defun idlwave-case () - "Build skeleton IDL case statement." - (interactive) - (idlwave-template - (idlwave-rw-case "case") - (idlwave-rw-case " of\n\nendcase") - "Selector expression")) - -(defun idlwave-switch () - "Build skeleton IDL switch statement." - (interactive) - (idlwave-template - (idlwave-rw-case "switch") - (idlwave-rw-case " of\n\nendswitch") - "Selector expression")) - -(defun idlwave-for () - "Build skeleton IDL loop statement." - (interactive) - (idlwave-template - (idlwave-rw-case "for") - (idlwave-rw-case " do begin\n\nendfor") - "Loop expression")) - -(defun idlwave-if () - "Build skeleton IDL if statement." - (interactive) - (idlwave-template - (idlwave-rw-case "if") - (idlwave-rw-case " then begin\n\nendif") - "Scalar logical expression")) - -(defun idlwave-procedure () - (interactive) - (idlwave-template - (idlwave-rw-case "pro") - (idlwave-rw-case "\n\nreturn\nend") - "Procedure name")) - -(defun idlwave-function () - (interactive) - (idlwave-template - (idlwave-rw-case "function") - (idlwave-rw-case "\n\nreturn\nend") - "Function name")) - -(defun idlwave-repeat () - (interactive) - (idlwave-template - (idlwave-rw-case "repeat begin\n\nendrep until") - (idlwave-rw-case "") - "Exit condition")) - -(defun idlwave-while () - (interactive) - (idlwave-template - (idlwave-rw-case "while") - (idlwave-rw-case " do begin\n\nendwhile") - "Entry condition")) - -(defun idlwave-split-string (string &optional pattern) - "Return a list of substrings of STRING which are separated by PATTERN. -If PATTERN is omitted, it defaults to \"[ \\f\\t\\n\\r\\v]+\"." - (or pattern - (setq pattern "[ \f\t\n\r\v]+")) - (let (parts (start 0)) - (while (string-match pattern string start) - (setq parts (cons (substring string start (match-beginning 0)) parts) - start (match-end 0))) - (nreverse (cons (substring string start) parts)))) - -(defun idlwave-replace-string (string replace_string replace_with) - (let* ((start 0) - (last (length string)) - (ret_string "") - end) - (while (setq end (string-match replace_string string start)) - (setq ret_string - (concat ret_string (substring string start end) replace_with)) - (setq start (match-end 0))) - (setq ret_string (concat ret_string (substring string start last))))) - -(define-obsolete-function-alias 'idlwave-get-buffer-visiting - #'find-buffer-visiting "28.1") - -(defvar idlwave-outlawed-buffers nil - "List of buffers pulled up by IDLWAVE for special reasons. -Buffers in this list may be killed by `idlwave-kill-autoloaded-buffers'.") - -(defun idlwave-find-file-noselect (file &optional why) - ;; Return a buffer visiting file. - (or (find-buffer-visiting file) - (let ((buf (find-file-noselect file))) - (if why (add-to-list 'idlwave-outlawed-buffers (cons buf why))) - buf))) - -(defun idlwave-kill-autoloaded-buffers () - "Kill buffers created automatically by IDLWAVE. -Function prompts for a letter to identify the buffers to kill. -Possible letters are: - -f Buffers created by the command \\[idlwave-find-module] or mouse - clicks in the routine info window. -s Buffers created by the IDLWAVE Shell to display where execution - stopped or an error was found. -a Both of the above. - -Buffers containing unsaved changes require confirmation before they are killed." - (interactive) - (if (null idlwave-outlawed-buffers) - (error "No IDLWAVE-created buffers available") - (princ (format "Kill IDLWAVE-created buffers: [f]ind source(%d), [s]hell display(%d), [a]ll ? " - (idlwave-count-outlawed-buffers 'find) - (idlwave-count-outlawed-buffers 'shell))) - (let ((c (read-char))) - (cond - ((member c '(?f ?\C-f)) - (idlwave-do-kill-autoloaded-buffers 'find)) - ((member c '(?s ?\C-s)) - (idlwave-do-kill-autoloaded-buffers 'shell)) - ((member c '(?a ?\C-a)) - (idlwave-do-kill-autoloaded-buffers t)) - (t (error "Abort")))))) - -(defun idlwave-count-outlawed-buffers (tag) - "How many outlawed buffers have tag TAG?" - (length (delq nil - (mapcar - (lambda (x) (eq (cdr x) tag)) - idlwave-outlawed-buffers)))) - -(defun idlwave-do-kill-autoloaded-buffers (&rest reasons) - "Kill all buffers pulled up by IDLWAVE matching REASONS." - (let* ((list (copy-sequence idlwave-outlawed-buffers)) - (cnt 0) - entry) - (while (setq entry (pop list)) - (if (buffer-live-p (car entry)) - (and (or (memq t reasons) - (memq (cdr entry) reasons)) - (kill-buffer (car entry)) - (cl-incf cnt) - (setq idlwave-outlawed-buffers - (delq entry idlwave-outlawed-buffers))) - (setq idlwave-outlawed-buffers - (delq entry idlwave-outlawed-buffers)))) - (message "%d buffer%s killed" cnt (if (= cnt 1) "" "s")))) - -(defun idlwave-revoke-license-to-kill () - "Remove BUFFER from the buffers which may be killed. -Killing would be done by `idlwave-do-kill-autoloaded-buffers'. -Intended for `after-save-hook'." - (let* ((buf (current-buffer)) - (entry (assq buf idlwave-outlawed-buffers))) - ;; Revoke license - (if entry - (setq idlwave-outlawed-buffers - (delq entry idlwave-outlawed-buffers))) - ;; Remove this function from the hook. - (remove-hook 'after-save-hook #'idlwave-revoke-license-to-kill 'local))) - -(defvar idlwave-path-alist) -(defun idlwave-locate-lib-file (file) - ;; Find FILE on the scanned lib path and return a buffer visiting it - (let* ((dirs idlwave-path-alist) - dir efile) - (catch 'exit - (while (setq dir (car (pop dirs))) - (if (file-regular-p - (setq efile (expand-file-name file dir))) - (throw 'exit efile)))))) - -(defun idlwave-expand-lib-file-name (file) - ;; Find FILE on the scanned lib path and return a buffer visiting it - ;; This is for, e.g., finding source with no user catalog - (cond - ((null file) nil) - ((file-name-absolute-p file) file) - (t (idlwave-locate-lib-file file)))) - -(defun idlwave-make-tags () - "Create the IDL tags file IDLTAGS in the current directory from -the list of directories specified in the minibuffer. Directories may be -for example: . /usr/local/rsi/idl/lib. All the subdirectories of the -specified top directories are searched if the directory name is prefixed -by @. Specify @ directories with care, it may take a long, long time if -you specify /." - (interactive) - (let (directory directories cmd append status numdirs dir getsubdirs - buffer save_buffer files numfiles item errbuf) - - ;; - ;; Read list of directories - (setq directory (read-string "Tag Directories: " ".")) - (setq directories (idlwave-split-string directory "[ \t]+")) - ;; - ;; Set etags command, vars - (setq cmd "etags --output=IDLTAGS --language=none --regex='/[ -\\t]*[pP][Rr][Oo][ \\t]+\\([^ \\t,]+\\)/' --regex='/[ -\\t]*[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn][ \\t]+\\([^ \\t,]+\\)/' ") - (setq append " ") - (setq status 0) - ;; - ;; For each directory - (setq numdirs 0) - (setq dir (nth numdirs directories)) - (while (and dir) - ;; - ;; Find the subdirectories - (if (string-match "^[@]\\(.+\\)$" dir) - (setq getsubdirs t) (setq getsubdirs nil)) - (if (and getsubdirs) (setq dir (substring dir 1 (length dir)))) - (setq dir (expand-file-name dir)) - (if (file-directory-p dir) - (progn - (if (and getsubdirs) - (progn - (setq buffer (get-buffer-create "*idltags*")) - (call-process "sh" nil buffer nil "-c" - (concat "find " dir " -type d -print")) - (setq save_buffer (current-buffer)) - (set-buffer buffer) - (setq files (idlwave-split-string - (idlwave-replace-string - (buffer-substring 1 (point-max)) - "\n" "/*.pro ") - "[ \t]+")) - (set-buffer save_buffer) - (kill-buffer buffer)) - (setq files (list (concat dir "/*.pro")))) - ;; - ;; For each subdirectory - (setq numfiles 0) - (setq item (nth numfiles files)) - (while (and item) - ;; - ;; Call etags - (if (not (string-match "^[ \t]*$" item)) - (progn - (message "%s" (concat "Tagging " item "...")) - (setq errbuf (get-buffer-create "*idltags-error*")) - (setq status (+ status - (if (eq 0 (call-process - "sh" nil errbuf nil "-c" - (concat cmd append item))) - 0 - 1))) - ;; - ;; Append additional tags - (setq append " --append ") - (setq numfiles (1+ numfiles)) - (setq item (nth numfiles files))) - (progn - (setq numfiles (1+ numfiles)) - (setq item (nth numfiles files)) - ))) - - (setq numdirs (1+ numdirs)) - (setq dir (nth numdirs directories))) - (progn - (setq numdirs (1+ numdirs)) - (setq dir (nth numdirs directories))))) - - (setq errbuf (get-buffer-create "*idltags-error*")) - (if (= status 0) - (kill-buffer errbuf)) - (message "") - )) - -(defun idlwave-toggle-comment-region (beg end &optional n) - "Comment the lines in the region if the first non-blank line is -commented, and conversely, uncomment region. If optional prefix arg -N is non-nil, then for N positive, add N comment delimiters or for N -negative, remove N comment delimiters. -Uses `comment-region' which does not place comment delimiters on -blank lines." - (interactive "r\nP") - (if n - (comment-region beg end (prefix-numeric-value n)) - (save-excursion - (goto-char beg) - (beginning-of-line) - ;; skip blank lines - (skip-chars-forward " \t\n") - (if (looking-at (concat "[ \t]*\\(" comment-start "+\\)")) - (uncomment-region beg end) - (comment-region beg end))))) - - -;; ---------------------------------------------------------------------------- -;; ---------------------------------------------------------------------------- -;; ---------------------------------------------------------------------------- -;; ---------------------------------------------------------------------------- -;; -;; Completion and Routine Info -;; - -;; String "intern" functions - -;; For the completion and routine info function, we want to normalize -;; the case of procedure names etc. We do this by "interning" these -;; string is a hand-crafted way. Hashes are used to map the downcase -;; version of the strings to the cased versions. Most *-sint-* -;; variables consist of *two* hashes, a buffer+shell, followed by a -;; system hash. The former is re-scanned, and the latter takes case -;; precedence. -;; -;; Since these cased versions are really lisp objects, we can use `eq' -;; to search, which is a large performance boost. All new strings -;; need to be "sinterned". We do this as early as possible after -;; getting these strings from completion or buffer substrings. So -;; most of the code can simply assume to deal with "sinterned" -;; strings. The only exception is that the functions which scan whole -;; buffers for routine information do not intern the grabbed strings. -;; This is only done afterwards. Therefore in these functions it is -;; *not* safe to assume the strings can be compared with `eq' and be -;; fed into the routine assq functions. - -;; Here we define the hashing functions. - -;; The variables which hold the hashes. -(defvar idlwave-sint-routines '(nil)) -(defvar idlwave-sint-keywords '(nil)) -(defvar idlwave-sint-methods '(nil)) -(defvar idlwave-sint-classes '(nil)) -(defvar idlwave-sint-dirs '(nil)) -(defvar idlwave-sint-libnames '(nil)) - -(defun idlwave-reset-sintern (&optional what) - "Reset all sintern hashes." - ;; Make sure the hash functions are accessible. - (let ((entries '((idlwave-sint-routines 1000 10) - (idlwave-sint-keywords 1000 10) - (idlwave-sint-methods 100 10) - (idlwave-sint-classes 10 10)))) - - ;; Make sure these are lists - (cl-loop for entry in entries - for var = (car entry) - do (if (not (consp (symbol-value var))) (set var (list nil)))) - - ;; Reset the system & library hash - (when (or (eq what t) (eq what 'syslib) - (null (cdr idlwave-sint-routines))) - (cl-loop for entry in entries - for var = (car entry) for size = (nth 1 entry) - do (setcdr (symbol-value var) - (make-hash-table ':size size ':test 'equal))) - (setq idlwave-sint-dirs nil - idlwave-sint-libnames nil)) - - ;; Reset the buffer & shell hash - (when (or (eq what t) (eq what 'bufsh) - (null (car idlwave-sint-routines))) - (cl-loop for entry in entries - for var = (car entry) for size = (nth 1 entry) - do (setcar (symbol-value var) - (make-hash-table ':size size ':test 'equal)))))) - -(defun idlwave-sintern-routine-or-method (name &optional class set) - (if class - (idlwave-sintern-method name set) - (idlwave-sintern-routine name set))) - -(defun idlwave-sintern (stype &rest args) - (apply (intern (concat "idlwave-sintern-" (symbol-name stype))) args)) - -;;(defmacro idlwave-sintern (type var) -;; `(cond ((not (stringp name)) name) -;; ((gethash (downcase name) (cdr ,var))) -;; ((gethash (downcase name) (car ,var))) -;; (set (idlwave-sintern-set name ,type ,var set)) -;; (name))) - -(defun idlwave-sintern-routine (name &optional set) - (cond ((not (stringp name)) name) - ((gethash (downcase name) (cdr idlwave-sint-routines))) - ((gethash (downcase name) (car idlwave-sint-routines))) - (set (idlwave-sintern-set name 'routine idlwave-sint-routines set)) - (name))) -(defun idlwave-sintern-keyword (name &optional set) - (cond ((not (stringp name)) name) - ((gethash (downcase name) (cdr idlwave-sint-keywords))) - ((gethash (downcase name) (car idlwave-sint-keywords))) - (set (idlwave-sintern-set name 'keyword idlwave-sint-keywords set)) - (name))) -(defun idlwave-sintern-method (name &optional set) - (cond ((not (stringp name)) name) - ((gethash (downcase name) (cdr idlwave-sint-methods))) - ((gethash (downcase name) (car idlwave-sint-methods))) - (set (idlwave-sintern-set name 'method idlwave-sint-methods set)) - (name))) -(defun idlwave-sintern-class (name &optional set) - (cond ((not (stringp name)) name) - ((gethash (downcase name) (cdr idlwave-sint-classes))) - ((gethash (downcase name) (car idlwave-sint-classes))) - (set (idlwave-sintern-set name 'class idlwave-sint-classes set)) - (name))) - -(defun idlwave-sintern-dir (dir &optional _set) - (car (or (member dir idlwave-sint-dirs) - (setq idlwave-sint-dirs (cons dir idlwave-sint-dirs))))) -(defun idlwave-sintern-libname (name &optional _set) - (car (or (member name idlwave-sint-libnames) - (setq idlwave-sint-libnames (cons name idlwave-sint-libnames))))) - -(defun idlwave-sintern-set (name type tables set) - (let* ((func (or (cdr (assq type idlwave-completion-case)) - 'identity)) - (iname (funcall (if (eq func 'preserve) 'identity func) name)) - (table (if (eq set 'sys) (cdr tables) (car tables)))) - (puthash (downcase name) iname table) - iname)) - -(defun idlwave-sintern-keyword-list (kwd-list &optional set) - "Sintern a set of keywords (file (key . link) (key2 . link2) ...)." - (mapc (lambda(x) - (setcar x (idlwave-sintern-keyword (car x) set))) - (cdr kwd-list)) - kwd-list) - -(defun idlwave-sintern-rinfo-list (list &optional set default-dir) - "Sintern all strings in the rinfo LIST. -With optional parameter SET: also set new patterns. Probably this -will always have to be t. If DEFAULT-DIR is passed, it is used as -the base of the directory." - (let (entry name type class kwds res source call new) - (while list - (setq entry (car list) - list (cdr list) - name (car entry) - type (nth 1 entry) - class (nth 2 entry) - source (nth 3 entry) - call (nth 4 entry) - kwds (nthcdr 5 entry)) - - ;; The class and name - (if class - (progn - (if (symbolp class) (setq class (symbol-name class))) - (setq class (idlwave-sintern-class class set)) - (setq name (idlwave-sintern-method name set))) - (setq name (idlwave-sintern-routine name set))) - - ;; The source - (let ((source-type (car source)) - (source-file (nth 1 source)) - (source-dir (if default-dir - (file-name-as-directory default-dir) - (nth 2 source))) - (source-lib (nth 3 source))) - (if (stringp source-dir) - (setq source-dir (idlwave-sintern-dir source-dir set))) - (if (stringp source-lib) - (setq source-lib (idlwave-sintern-libname source-lib set))) - (setq source (list source-type source-file source-dir source-lib))) - - ;; The keywords - (setq kwds (mapcar (lambda (x) - (idlwave-sintern-keyword-list x set)) - kwds)) - - ;; Build a canonicalized list - (setq new (nconc (list name type class source call) kwds) - res (cons new res))) - (nreverse res))) - -;; Creating new sintern tables - -(defmacro idlwave-new-sintern-type (tag) - "Define a variable and a function to sintern the new type TAG. -This defines the function `idlwave-sintern-TAG' and the variable -`idlwave-sint-TAGs'." - (let* ((name (symbol-name tag)) - (names (concat name "s")) - (var (intern (concat "idlwave-sint-" names))) - (func (intern (concat "idlwave-sintern-" name)))) - `(progn - (defvar ,var nil) ; initial value of the association list - (defun ,func (name &optional set) - (cond ((not (stringp name)) name) - ((cdr (assoc (downcase name) ,var))) - (set - (push (cons (downcase name) name) ,var) - name) - (name)))))) - -(defun idlwave-reset-sintern-type (tag) - "Reset the sintern variable associated with TAG." - (set (intern (concat "idlwave-sint-" (symbol-name tag) "s")) nil)) - -;;--------------------------------------------------------------------------- - - -;; The variables which hold the information -(defvar idlwave-system-routines nil - "Holds the routine-info obtained by scanning buffers.") -(defvar idlwave-buffer-routines nil - "Holds the routine-info obtained by scanning buffers.") -(defvar idlwave-compiled-routines nil - "Holds the routine-info obtained by asking the shell.") -(defvar idlwave-unresolved-routines nil - "Holds the unresolved routine-info obtained by asking the shell.") -(defvar idlwave-user-catalog-routines nil - "Holds the procedure routine-info from the user scan.") -(defvar idlwave-library-catalog-routines nil - "Holds the procedure routine-info from the .idlwave_catalog library files.") -(defvar idlwave-library-catalog-libname nil - "Name of library catalog loaded from .idlwave_catalog files.") -(defvar idlwave-path-alist nil - "Alist with !PATH directories and zero or more flags if the dir has -been scanned in a user catalog ('user) or discovered in a library -catalog \('lib).") -(defvar idlwave-true-path-alist nil - "Like `idlwave-path-alist', but with true filenames.") -(defvar idlwave-routines nil - "Holds the combined procedure/function/method routine-info.") -(defvar idlwave-class-alist nil - "Holds the class names known to IDLWAVE.") -(defvar idlwave-class-history nil - "The history of classes selected with the minibuffer.") -(defvar idlwave-force-class-query nil) -(defvar idlwave-before-completion-wconf nil - "The window configuration just before the completion buffer was displayed.") -(defvar idlwave-last-system-routine-info-cons-cell nil - "The last cons cell in the system routine info.") - -;; -;; The code to get routine info from different sources. - -(defvar idlwave-system-routines) -(defvar idlwave-catalog-process nil - "The background process currently updating the catalog.") - -(defun idlwave-routines () - "Provide a list of IDL routines. -This routine loads the builtin routines on the first call. -Later it only returns the value of the variable." - (if (and idlwave-catalog-process - (processp idlwave-catalog-process)) - (progn - (cond - ((equal (process-status idlwave-catalog-process) 'exit) - (message "updating........") - (setq idlwave-catalog-process nil) - (idlwave-update-routine-info '(4))) - ((equal (process-status idlwave-catalog-process) 'run) - ;; Keep it running... - ) - (t - ;; Something is wrong, get rid of the process - (message "Problem with catalog process") (beep) - (condition-case nil - (kill-process idlwave-catalog-process) - (error nil)) - (setq idlwave-catalog-process nil))))) - (or idlwave-routines - (progn - (idlwave-update-routine-info) - ;; return the current value - idlwave-routines))) - -(defvar idlwave-update-rinfo-hook nil - "List of functions which should run after a global rinfo update. -Does not run after automatic updates of buffer or the shell.") - -(defun idlwave-rescan-catalog-directories () - "Rescan the previously selected directories. For batch processing." - (idlwave-update-routine-info '(16))) - -(defun idlwave-rescan-asynchronously () - "Dispatch another Emacs instance to update the idlwave catalog. -After the process finishes normally, the first access to routine info -will re-read the catalog." - (interactive) - (if (processp idlwave-catalog-process) - (if (eq (process-status idlwave-catalog-process) 'run) - (if (yes-or-no-p "A catalog-updating process is running. Kill it? ") - (progn - (condition-case nil - (kill-process idlwave-catalog-process) - (error nil)) - (error "Process killed, no new process started")) - (error "Quit")) - (condition-case nil - (kill-process idlwave-catalog-process) - (error nil)))) - (if (or (not idlwave-user-catalog-file) - (not (stringp idlwave-user-catalog-file)) - (not (file-regular-p idlwave-user-catalog-file))) - (error "No catalog has been produced yet")) - (let* ((emacs (concat invocation-directory invocation-name)) - (args (list "-batch" - "-l" (expand-file-name "~/.emacs") - "-l" "idlwave" - "-f" "idlwave-rescan-catalog-directories")) - (process (apply #'start-process "idlcat" - nil emacs args))) - (setq idlwave-catalog-process process) - (set-process-sentinel - process - (lambda (_pro why) - (when (string-match "finished" why) - (setq idlwave-routines nil - idlwave-system-routines nil - idlwave-catalog-process nil) - (or (idlwave-start-load-rinfo-timer) - (idlwave-update-routine-info '(4)))))) - (message "Background job started to update catalog file"))) - - -;; Format for all routine info user catalog, library catalogs, etc.: -;; -;; ("ROUTINE" type class -;; (system) | (lib pro_file dir "LIBNAME") | (user pro_file dir "USERLIB") | -;; (buffer pro_file dir) | (compiled pro_file dir) -;; "calling_string" ("HELPFILE" (("KWD1" . link1) ...)) -;; ("HELPFILE2" (("KWD2" . link) ...)) ...) -;; -;; DIR will be supplied dynamically while loading library catalogs, -;; and is sinterned to save space, as is LIBNAME. PRO_FILE can be a -;; complete filepath, in which case DIR is unnecessary. HELPFILE can -;; be nil, as can LINK1, etc., if no HTML help is available. - - -(defvar idlwave-load-rinfo-idle-timer) -(defvar idlwave-shell-path-query) - -(defun idlwave-update-routine-info (&optional arg no-concatenate) - "Update the internal routine-info lists. -These lists are used by `idlwave-routine-info' (\\[idlwave-routine-info]) -and by `idlwave-complete' (\\[idlwave-complete]) to provide information -about individual routines. - -The information can come from 4 sources: -1. IDL programs in the current editing session -2. Compiled modules in an IDL shell running as Emacs subprocess -3. A list which covers the IDL system routines. -4. A list which covers the prescanned library files. - -Scans all IDLWAVE-mode buffers of the current editing session (see -`idlwave-scan-all-buffers-for-routine-info'). -When an IDL shell is running, this command also queries the IDL program -for currently compiled routines. - -With prefix ARG, also reload the system and library lists. -With two prefix ARG's, also rescans the chosen user catalog tree. -With three prefix args, dispatch asynchronous process to do the update. - -If NO-CONCATENATE is non-nil, don't pre-concatenate the routine info -lists, but instead wait for the shell query to complete and -asynchronously finish updating routine info. This is set -automatically when called interactively. When you need routine -information updated immediately, leave NO-CONCATENATE nil." - (interactive "P\np") - ;; Stop any idle processing - (if (timerp idlwave-load-rinfo-idle-timer) - (cancel-timer idlwave-load-rinfo-idle-timer)) - (cond - ((equal arg '(64)) - ;; Start a background process which updates the catalog. - (idlwave-rescan-asynchronously)) - ((equal arg '(16)) - ;; Update the user catalog now, and wait for them. - (idlwave-create-user-catalog-file t)) - (t - (let* ((load (or arg - idlwave-buffer-case-takes-precedence - (null idlwave-routines))) - ;; The override-idle means, even if the idle timer has done some - ;; preparing work, load and renormalize everything anyway. - (override-idle (or arg idlwave-buffer-case-takes-precedence))) - - (setq idlwave-buffer-routines nil - idlwave-compiled-routines nil - idlwave-unresolved-routines nil) - ;; Reset the appropriate hashes - (if (get 'idlwave-reset-sintern 'done-by-idle) - ;; reset was already done in idle time, so skip this step now once - (put 'idlwave-reset-sintern 'done-by-idle nil) - (idlwave-reset-sintern (cond (load t) - ((null idlwave-system-routines) t) - (t 'bufsh)))) - - (if idlwave-buffer-case-takes-precedence - ;; We can safely scan the buffer stuff first - (progn - (idlwave-update-buffer-routine-info) - (and load (idlwave-load-all-rinfo override-idle))) - ;; We first do the system info, and then the buffers - (and load (idlwave-load-all-rinfo override-idle)) - (idlwave-update-buffer-routine-info)) - - ;; Let's see if there is a shell - (let* ((shell-is-running (and (fboundp 'idlwave-shell-is-running) - (idlwave-shell-is-running))) - (ask-shell (and shell-is-running - idlwave-query-shell-for-routine-info))) - - ;; Load the library catalogs again, first re-scanning the path - (when arg - (if shell-is-running - (idlwave-shell-send-command idlwave-shell-path-query - '(progn - (idlwave-shell-get-path-info) - (idlwave-scan-library-catalogs)) - 'hide) - (idlwave-scan-library-catalogs))) - - (if (or (not ask-shell) - (not no-concatenate)) - ;; 1. If we are not going to ask the shell, we need to do the - ;; concatenation now. - ;; 2. When this function is called non-interactively, it - ;; means that someone needs routine info *now*. The - ;; shell update causes the concatenation to be - ;; *delayed*, so not in time for the current command. - ;; Therefore, we do a concatenation now, even though - ;; the shell might do it again. - (idlwave-concatenate-rinfo-lists nil 'run-hooks)) - - (when ask-shell - ;; Ask the shell about the routines it knows of. - (message "Querying the shell") - (idlwave-shell-update-routine-info nil t))))))) - - -(defvar idlwave-load-rinfo-steps-done (make-vector 6 nil)) -(defvar idlwave-load-rinfo-idle-timer nil) -(defun idlwave-start-load-rinfo-timer () - (if (timerp idlwave-load-rinfo-idle-timer) - (cancel-timer idlwave-load-rinfo-idle-timer)) - (setq idlwave-load-rinfo-steps-done (make-vector 6 nil)) - (setq idlwave-load-rinfo-idle-timer nil) - (if (and idlwave-init-rinfo-when-idle-after - (numberp idlwave-init-rinfo-when-idle-after) - (not (equal 0 idlwave-init-rinfo-when-idle-after)) - (not idlwave-routines)) - (condition-case nil - (progn - (setq idlwave-load-rinfo-idle-timer - (run-with-idle-timer - idlwave-init-rinfo-when-idle-after - nil #'idlwave-load-rinfo-next-step))) - (error nil)))) - -;;------ XML Help routine info system -(defun idlwave-load-system-routine-info () - ;; Load the system routine info from the cached routine info file, - ;; which, if necessary, will be re-created from the XML file on - ;; disk. As a last fallback, load the (likely outdated) idlw-rinfo - ;; file distributed with older IDLWAVE versions (<6.0) - (unless (and (load idlwave-xml-system-rinfo-converted-file - 'noerror 'nomessage) - (idlwave-xml-system-routine-info-up-to-date)) - ;; See if we can create it from XML source - (condition-case nil - (idlwave-convert-xml-system-routine-info) - (error - (unless (load idlwave-xml-system-rinfo-converted-file - 'noerror 'nomessage) - (if idlwave-system-routines - (message - "Failed to load converted routine info, using old conversion.") - (message - "Failed to convert XML routine info, falling back on idlw-rinfo.") - (if (not (load "idlw-rinfo" 'noerror 'nomessage)) - (message - "Could not locate any system routine information.")))))))) - -(defun idlwave-xml-system-routine-info-up-to-date() - (let* ((dir (file-name-as-directory - (expand-file-name "help/online_help" (idlwave-sys-dir)))) - (catalog-file (expand-file-name "idl_catalog.xml" dir))) - (file-newer-than-file-p ;converted file is newer than catalog - idlwave-xml-system-rinfo-converted-file - catalog-file))) - -(defvar idlwave-system-class-info nil) ; Gathered from idlw-rinfo -(defvar idlwave-system-variables-alist nil - "Alist of system variables and the associated structure tags. -Gets set in cached XML rinfo, or `idlw-rinfo.el'.") -(defvar idlwave-executive-commands-alist nil - "Alist of system variables and their help files.") -(defvar idlwave-help-special-topic-words nil) - - -(defun idlwave-shorten-syntax (syntax name &optional class) - ;; From a list of syntax statements, shorten with %s and group with "or" - (let ((case-fold-search t)) - (mapconcat - (lambda (x) - (while (string-match name x) - (setq x (replace-match "%s" t t x))) - (if class - (while (string-match class x) - (setq x (replace-match "%s" t t x)))) - x) - (nreverse syntax) - " or "))) - -(defun idlwave-xml-create-class-method-lists (xml-entry) - ;; Create a class list entry from the xml parsed list., returning a - ;; cons of form (class-entry method-entries). - (let* ((nameblock (nth 1 xml-entry)) - (class (cdr (assq 'name nameblock))) - (link (cdr (assq 'link nameblock))) - (params (cddr xml-entry)) - (case-fold-search t) - class-entry - method methods-entry extra-kwds - props get-props set-props init-props inherits - pelem ptype) - (while params - (setq pelem (car params)) - (when (listp pelem) - (setq ptype (car pelem) - props (car (cdr pelem))) - (cond - ((eq ptype 'SUPERCLASS) - (let ((pname (cdr (assq 'name props))) - (plink (cdr (assq 'link props)))) - (unless (and (string= pname "None") - (string= plink "None")) - (push pname inherits)))) - - ((eq ptype 'PROPERTY) - (let ((pname (cdr (assq 'name props))) - (plink (cdr (assq 'link props))) - (get (string= (cdr (assq 'get props)) "Yes")) - (set (string= (cdr (assq 'set props)) "Yes")) - (init (string= (cdr (assq 'init props)) "Yes"))) - (if get (push (list pname plink) get-props)) - (if set (push (list pname plink) set-props)) - (if init (push (list pname plink) init-props)))) - - ((eq ptype 'METHOD) - (setq method (cdr (assq 'name props))) - (setq extra-kwds ;;Assume all property keywords are gathered already - (cond - ((string-match (concat class "::Init") method) - (put 'init-props 'matched t) - init-props) - ((string-match (concat class "::GetProperty") method) - (put 'get-props 'matched t) - get-props) - ((string-match (concat class "::SetProperty") method) - (put 'set-props 'matched t) - set-props) - (t nil))) - (setq methods-entry - (nconc (idlwave-xml-create-rinfo-list pelem class extra-kwds) - methods-entry))) - (t))) - (setq params (cdr params))) - ;;(unless (get 'init-props 'matched) - ;; (message "Failed to match Init in class %s" class)) - ;;(unless (get 'get-props 'matched) - ;; (message "Failed to match GetProperty in class %s" class)) - ;;(unless (get 'set-props 'matched) - ;; (message "Failed to match SetProperty in class %s" class)) - (setq class-entry - (if inherits - (list class (append '(inherits) inherits) (list 'link link)) - (list class (list 'link link)))) - (cons class-entry methods-entry))) - -(defun idlwave-xml-create-rinfo-list (xml-entry &optional class extra-kws) - ;; Create correctly structured list elements from ROUTINE or METHOD - ;; XML list structures. Return a list of list elements, with more - ;; than one sub-list possible if a routine can serve as both - ;; procedure and function (e.g. call_method). - (let* ((nameblock (nth 1 xml-entry)) - (name (cdr (assq 'name nameblock))) - (link (cdr (assq 'link nameblock))) - (params (cddr xml-entry)) - (syntax-vec (make-vector 3 nil)) ; procedure, function, exec command - (case-fold-search t) - syntax kwd klink pref-list kwds pelem ptype props result type) - (if class ;; strip out class name from class method name string - (if (string-match (concat class "::") name) - (setq name (substring name (match-end 0))))) - (while params - (setq pelem (car params)) - (when (listp pelem) - (setq ptype (car pelem) - props (car (cdr pelem))) - (cond - ((eq ptype 'SYNTAX) - (setq syntax (cdr (assq 'name props))) - (if (string-match "->" syntax) - (setq syntax (replace-match "->" t nil syntax))) - (setq type (cdr (assq 'type props))) - (push syntax - (aref syntax-vec (cond - ((string-match "^pro" type) 0) - ((string-match "^fun" type) 1) - ((string-match "^exec" type) 2))))) - ((eq ptype 'KEYWORD) - (setq kwd (cdr (assq 'name props)) - klink (cdr (assq 'link props))) - (if (string-match "^\\[XY\\(Z?\\)\\]" kwd) - (progn - (setq pref-list - (if (match-string 1 kwd) '("X" "Y" "Z") '("X" "Y")) - kwd (substring kwd (match-end 0))) - (cl-loop for x in pref-list do - (push (list (concat x kwd) klink) kwds))) - (push (list kwd klink) kwds))) - - (t))); Do nothing for the others - (setq params (cdr params))) - - ;; Debug - ;; (if (and (null (aref syntax-vec 0)) - ;; (null (aref syntax-vec 1)) - ;; (null (aref syntax-vec 2))) - ;; (with-current-buffer (get-buffer-create "IDL_XML_catalog_complaints") - ;; (if class - ;; (insert (format "Missing SYNTAX entry for %s::%s\n" class name)) - ;; (insert (message "Missing SYNTAX entry for %s\n" name))))) - - ;; Executive commands are treated specially - (if (aref syntax-vec 2) - (cons (substring name 1) link) - (if extra-kws (setq kwds (nconc kwds extra-kws))) - (setq kwds (idlwave-rinfo-group-keywords kwds link)) - (cl-loop for idx from 0 to 1 do - (if (aref syntax-vec idx) - (push (append (list name (if (eq idx 0) 'pro 'fun) - class '(system) - (idlwave-shorten-syntax - (aref syntax-vec idx) name class)) - kwds) result))) - result))) - - -(defun idlwave-rinfo-group-keywords (kwds master-link) - ;; Group keywords by link file, as a list with elements - ;; (linkfile ( ("KWD1" . link1) ("KWD2" . link2)) - (let (kwd link anchor linkfiles block master-elt) - (while kwds - (setq kwd (car kwds) - link (idlwave-split-link-target (nth 1 kwd)) - anchor (cdr link) - link (car link) - kwd (car kwd)) - (if (setq block (assoc link linkfiles)) - (push (cons kwd anchor) (cdr block)) - (push (list link (cons kwd anchor)) linkfiles)) - (setq kwds (cdr kwds))) - ;; Ensure the master link is there - (if (setq master-elt (assoc master-link linkfiles)) - (if (eq (car linkfiles) master-elt) - linkfiles - (cons master-elt (delq master-elt linkfiles))) - (push (list master-link) linkfiles)))) - -(defun idlwave-convert-xml-clean-statement-aliases (aliases) - ;; Clean up the syntax of routines which are actually aliases by - ;; removing the "OR" from the statements - (let (syntax entry) - (cl-loop for x in aliases do - (setq entry (assoc x idlwave-system-routines)) - (when entry - (while (string-match " +or +" (setq syntax (nth 4 entry))) - (setf (nth 4 entry) (replace-match ", " t t syntax))))))) - -(defun idlwave-convert-xml-clean-routine-aliases (aliases) - ;; Duplicate and trim original routine aliases from rinfo list - ;; This if for, e.g. OPENR/OPENW/OPENU - (let (alias remove-list new parts all-parts) - (cl-loop for x in aliases do - (when (setq parts (split-string (cdr x) "/")) - (setq new (assoc (cdr x) all-parts)) - (unless new - (setq new (cons (cdr x) parts)) - (push new all-parts)) - (setcdr new (delete (car x) (cdr new))))) - - ;; Add any missing aliases (separate by slashes) - (cl-loop for x in all-parts do - (if (cdr x) - (push (cons (nth 1 x) (car x)) aliases))) - - (cl-loop for x in aliases do - (when (setq alias (assoc (cdr x) idlwave-system-routines)) - (unless (memq alias remove-list) (push alias remove-list)) - (setq alias (copy-sequence alias)) - (setcar alias (car x)) - (push alias idlwave-system-routines))) - (cl-loop for x in remove-list do - (setq idlwave-system-routines (delq x idlwave-system-routines))))) - -(defun idlwave-convert-xml-clean-sysvar-aliases (aliases) - ;; Duplicate and trim original routine aliases from rinfo list - ;; This if for, e.g. !X, !Y, !Z. - (let (alias remove-list) - (cl-loop for x in aliases do - (when (setq alias (assoc (cdr x) idlwave-system-variables-alist)) - (unless (memq alias remove-list) (push alias remove-list)) - (setq alias (copy-sequence alias)) - (setcar alias (car x)) - (push alias idlwave-system-variables-alist))) - (cl-loop for x in remove-list do - (setq idlwave-system-variables-alist - (delq x idlwave-system-variables-alist))))) - - -(defun idlwave-xml-create-sysvar-alist (xml-entry) - ;; Create a sysvar list entry from the xml parsed list. - (let* ((nameblock (nth 1 xml-entry)) - (name (cdr (assq 'name nameblock))) - (sysvar (substring name (progn (string-match "^ *!" name) - (match-end 0)))) - (link (cdr (assq 'link nameblock))) - (params (cddr xml-entry)) - (case-fold-search t) - pelem ptype props tags) - (while params - (setq pelem (car params)) - (when (listp pelem) - (setq ptype (car pelem) - props (car (cdr pelem))) - (cond - ((eq ptype 'FIELD) - (push (cons (cdr (assq 'name props)) - (cdr - (idlwave-split-link-target (cdr (assq 'link props))))) - tags)))) - (setq params (cdr params))) - (delq nil - (list sysvar (if tags (cons 'tags tags)) (list 'link link))))) - - -(defvar idlwave-xml-routine-info-file nil) - -(defun idlwave-save-routine-info () - (if idlwave-xml-routine-info-file - (with-temp-file idlwave-xml-system-rinfo-converted-file - (insert - (concat ";; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* -;; IDLWAVE Routine Information File (IDLWAVE version " idlwave-mode-version ") -;; Automatically generated from source file: -;; " idlwave-xml-routine-info-file " -;; on " (current-time-string) " -;; Do not edit.")) - (insert (format "\n(setq idlwave-xml-routine-info-file \n \"%s\")" - idlwave-xml-routine-info-file)) - (insert "\n(setq idlwave-system-routines\n '") - (prin1 idlwave-system-routines (current-buffer)) - (insert ")") - (insert "\n(setq idlwave-system-variables-alist\n '") - (prin1 idlwave-system-variables-alist (current-buffer)) - (insert ")") - (insert "\n(setq idlwave-system-class-info\n '") - (prin1 idlwave-system-class-info (current-buffer)) - (insert ")") - (insert "\n(setq idlwave-executive-commands-alist\n '") - (prin1 idlwave-executive-commands-alist (current-buffer)) - (insert ")") - (insert "\n(setq idlwave-help-special-topic-words\n '") - (prin1 idlwave-help-special-topic-words (current-buffer)) - (insert ")")))) - -(defun idlwave-convert-xml-system-routine-info () - "Convert XML supplied IDL routine info into internal form. -Cache to disk for quick recovery." - (interactive) - (let* ((dir (file-name-as-directory - (expand-file-name "help/online_help" (idlwave-sys-dir)))) - (catalog-file (expand-file-name "idl_catalog.xml" dir)) - (elem-cnt 0) - props rinfo msg-cnt elem type nelem class-result alias - routines routine-aliases statement-aliases sysvar-aliases) - (if (not (file-exists-p catalog-file)) - (error "No such XML routine info file: %s" catalog-file) - (if (not (file-readable-p catalog-file)) - (error "Cannot read XML routine info file: %s" catalog-file))) - (message "Reading XML routine info...") - (setq rinfo (xml-parse-file catalog-file)) - (message "Reading XML routine info...done") - (setq rinfo (assq 'CATALOG rinfo)) - (unless rinfo (error "Failed to parse XML routine info")) - ;;(setq rinfo (car rinfo)) ; Skip the catalog stuff. - - (setq rinfo (cddr rinfo)) - - (setq nelem (length rinfo) - msg-cnt (/ nelem 20)) - - (setq idlwave-xml-routine-info-file nil) - (message "Converting XML routine info...") - (setq idlwave-system-routines nil - idlwave-system-variables-alist nil - idlwave-system-class-info nil - idlwave-executive-commands-alist nil - idlwave-help-special-topic-words nil) - - (while rinfo - (setq elem (car rinfo) - rinfo (cdr rinfo)) - (cl-incf elem-cnt) - (when (listp elem) - (setq type (car elem) - props (car (cdr elem))) - (if (= (mod elem-cnt msg-cnt) 0) - (message "Converting XML routine info...%2d%%" - (floor (* elem-cnt 100.0) nelem))) - (cond - ((eq type 'ROUTINE) - (if (setq alias (assq 'alias_to props)) - (push (cons (cdr (assq 'name props)) (cdr alias)) - routine-aliases) - (setq routines (idlwave-xml-create-rinfo-list elem)) - (if (listp (cdr routines)) - (setq idlwave-system-routines - (nconc idlwave-system-routines routines)) - ;; a cons cell is an executive commands - (push routines idlwave-executive-commands-alist)))) - - ((eq type 'CLASS) - (setq class-result (idlwave-xml-create-class-method-lists elem)) - (push (car class-result) idlwave-system-class-info) - (setq idlwave-system-routines - (nconc idlwave-system-routines (cdr class-result)))) - - ((eq type 'STATEMENT) - (push (cons (cdr (assq 'name props)) - (cdr (assq 'link props))) - idlwave-help-special-topic-words) - ;; Save the links to those which are statement aliases (not routines) - (if (setq alias (assq 'alias_to props)) - (unless (member (cdr alias) statement-aliases) - (push (cdr alias) statement-aliases)))) - - ((eq type 'SYSVAR) - (if (setq alias (cdr (assq 'alias_to props))) - (push (cons (substring (cdr (assq 'name props)) 1) - (substring alias 1)) - sysvar-aliases) - (push (idlwave-xml-create-sysvar-alist elem) - idlwave-system-variables-alist))) - (t)))) - (idlwave-convert-xml-clean-routine-aliases routine-aliases) - (idlwave-convert-xml-clean-statement-aliases statement-aliases) - (idlwave-convert-xml-clean-sysvar-aliases sysvar-aliases) - - (setq idlwave-xml-routine-info-file catalog-file) - (idlwave-save-routine-info) - (message "Converting XML routine info...done"))) - - -;; ("ROUTINE" type class -;; (system) | (lib pro_file dir "LIBNAME") | (user pro_file dir "USERLIB") | -;; (buffer pro_file dir) | (compiled pro_file dir) -;; "calling_string" ("HELPFILE" (("KWD1" . link1) ...)) -;; ("HELPFILE2" (("KWD2" . link) ...)) ...) - - -(defun idlwave-load-rinfo-next-step () - (let ((inhibit-quit t) - (arr idlwave-load-rinfo-steps-done)) - (if (catch 'exit - (when (not (aref arr 0)) - (message "Loading system routine info in idle time...") - (idlwave-load-system-routine-info) - ;;(load "idlw-rinfo" 'noerror 'nomessage) - (message "Loading system routine info in idle time...done") - (aset arr 0 t) - (throw 'exit t)) - - (when (not (aref arr 1)) - (message "Normalizing idlwave-system-routines in idle time...") - (idlwave-reset-sintern t) - (put 'idlwave-reset-sintern 'done-by-idle t) - (setq idlwave-system-routines - (idlwave-sintern-rinfo-list idlwave-system-routines 'sys)) - (message "Normalizing idlwave-system-routines in idle time...done") - (aset arr 1 t) - (throw 'exit t)) - - (when (not (aref arr 2)) - (when (and (stringp idlwave-user-catalog-file) - (file-regular-p idlwave-user-catalog-file)) - (message "Loading user catalog in idle time...") - (condition-case nil - (load-file idlwave-user-catalog-file) - (error (throw 'exit nil))) - ;; Check for the old style catalog and warn - (if (and - (boundp 'idlwave-library-routines) - idlwave-library-routines) - (progn - (setq idlwave-library-routines nil) - (ding) - (message "Outdated user catalog: %s... recreate" - idlwave-user-catalog-file)) - (message "Loading user catalog in idle time...done"))) - (aset arr 2 t) - (throw 'exit t)) - - (when (not (aref arr 3)) - (when idlwave-user-catalog-routines - (message "Normalizing user catalog routines in idle time...") - (setq idlwave-user-catalog-routines - (idlwave-sintern-rinfo-list - idlwave-user-catalog-routines 'sys)) - (message - "Normalizing user catalog routines in idle time...done")) - (aset arr 3 t) - (throw 'exit t)) - - (when (not (aref arr 4)) - (idlwave-scan-library-catalogs - "Loading and normalizing library catalogs in idle time...") - (aset arr 4 t) - (throw 'exit t)) - (when (not (aref arr 5)) - (message "Finishing initialization in idle time...") - (idlwave-routines) - (message "Finishing initialization in idle time...done") - (aset arr 5 t) - (throw 'exit nil))) - ;; restart the timer - (if (sit-for 1) - (idlwave-load-rinfo-next-step) - (setq idlwave-load-rinfo-idle-timer - (run-with-idle-timer - idlwave-init-rinfo-when-idle-after - nil #'idlwave-load-rinfo-next-step)))))) - -(defvar idlwave-after-load-rinfo-hook nil) - -(defun idlwave-load-all-rinfo (&optional force) - ;; Load and case-treat the system, user catalog, and library routine - ;; info files. - - ;; System - (when (or force (not (aref idlwave-load-rinfo-steps-done 0))) - ;;(load "idlw-rinfo" 'noerror 'nomessage)) - (idlwave-load-system-routine-info)) - (when (or force (not (aref idlwave-load-rinfo-steps-done 1))) - (message "Normalizing idlwave-system-routines...") - (setq idlwave-system-routines - (idlwave-sintern-rinfo-list idlwave-system-routines 'sys)) - (message "Normalizing idlwave-system-routines...done")) - (when idlwave-system-routines - (setq idlwave-routines (copy-sequence idlwave-system-routines)) - (setq idlwave-last-system-routine-info-cons-cell - (nthcdr (1- (length idlwave-routines)) idlwave-routines))) - - ;; User catalog - (when (and (stringp idlwave-user-catalog-file) - (file-regular-p idlwave-user-catalog-file)) - (condition-case nil - (when (or force (not (aref idlwave-load-rinfo-steps-done 2))) - (load-file idlwave-user-catalog-file)) - (error nil)) - (when (and - (boundp 'idlwave-library-routines) - idlwave-library-routines) - (setq idlwave-library-routines nil) - (error "Outdated user catalog: %s... recreate" - idlwave-user-catalog-file)) - (setq idlwave-true-path-alist nil) - (when (or force (not (aref idlwave-load-rinfo-steps-done 3))) - (message "Normalizing user catalog routines...") - (setq idlwave-user-catalog-routines - (idlwave-sintern-rinfo-list - idlwave-user-catalog-routines 'sys)) - (message "Normalizing user catalog routines...done"))) - - ;; Library catalog - (when (or force (not (aref idlwave-load-rinfo-steps-done 4))) - (idlwave-scan-library-catalogs - "Loading and normalizing library catalogs...")) - (run-hooks 'idlwave-after-load-rinfo-hook)) - - -(defun idlwave-update-buffer-routine-info () - (let (res) - (cond - ((eq idlwave-scan-all-buffers-for-routine-info t) - ;; Scan all buffers, current buffer last - (message "Scanning all buffers...") - (setq res (idlwave-get-routine-info-from-buffers - (reverse (buffer-list))))) - ((null idlwave-scan-all-buffers-for-routine-info) - ;; Don't scan any buffers - (setq res nil)) - (t - ;; Just scan this buffer - (if (derived-mode-p 'idlwave-mode) - (progn - (message "Scanning current buffer...") - (setq res (idlwave-get-routine-info-from-buffers - (list (current-buffer)))))))) - ;; Put the result into the correct variable - (setq idlwave-buffer-routines - (idlwave-sintern-rinfo-list res 'set)))) - -(defun idlwave-concatenate-rinfo-lists (&optional quiet run-hook) - "Put the different sources for routine information together." - ;; The sequence here is important because earlier definitions shadow - ;; later ones. We assume that if things in the buffers are newer - ;; then in the shell of the system, they are meant to be different. - (let ((temp (append idlwave-buffer-routines - idlwave-compiled-routines - idlwave-library-catalog-routines - idlwave-user-catalog-routines))) - ;; Not actually used for anything? - (if idlwave-last-system-routine-info-cons-cell - (setcdr idlwave-last-system-routine-info-cons-cell temp) - (setq idlwave-last-system-routine-info-cons-cell (cons temp nil)))) - (setq idlwave-class-alist nil) - - ;; Give a message with information about the number of routines we have. - (unless quiet - (message - "Routines Found: buffer(%d) compiled(%d) library(%d) user(%d) system(%d)" - (length idlwave-buffer-routines) - (length idlwave-compiled-routines) - (length idlwave-library-catalog-routines) - (length idlwave-user-catalog-routines) - (length idlwave-system-routines))) - (if run-hook - (run-hooks 'idlwave-update-rinfo-hook))) - -(defun idlwave-class-alist () - "Return the class alist - make it if necessary." - (or idlwave-class-alist - (let (class) - (cl-loop for x in idlwave-routines do - (when (and (setq class (nth 2 x)) - (not (assq class idlwave-class-alist))) - (push (list class) idlwave-class-alist))) - idlwave-class-alist))) - -;; Three functions for the hooks -(defun idlwave-save-buffer-update () - (idlwave-update-current-buffer-info 'save-buffer)) -(defun idlwave-kill-buffer-update () - (idlwave-update-current-buffer-info 'kill-buffer)) -(defun idlwave-new-buffer-update () - (idlwave-update-current-buffer-info 'find-file)) - -(defun idlwave-update-current-buffer-info (why) - "Update `idlwave-routines' for current buffer. -Can run from `after-save-hook'." - (when (and (derived-mode-p 'idlwave-mode) - (or (eq t idlwave-auto-routine-info-updates) - (memq why idlwave-auto-routine-info-updates)) - idlwave-scan-all-buffers-for-routine-info - idlwave-routines) - (condition-case nil - (let (routines) - (idlwave-replace-buffer-routine-info - (buffer-file-name) - (if (eq why 'kill-buffer) - nil - (setq routines - (idlwave-sintern-rinfo-list - (idlwave-get-routine-info-from-buffers - (list (current-buffer))) 'set)))) - (idlwave-concatenate-rinfo-lists 'quiet) - routines) - (error nil)))) - -(defun idlwave-replace-buffer-routine-info (file new) - "Cut the part from FILE out of `idlwave-buffer-routines' and add NEW." - (let ((list idlwave-buffer-routines) - found) - (while list - ;; The following test uses eq to make sure it works correctly - ;; when two buffers visit the same file. Then the file names - ;; will be equal, but not eq. - (if (eq (idlwave-routine-source-file (nth 3 (car list))) file) - (progn - (setcar list nil) - (setq found t)) - (if found - ;; End of that section reached. Jump. - (setq list nil))) - (setq list (cdr list))) - (setq idlwave-buffer-routines - (append new (delq nil idlwave-buffer-routines))))) - -;;----- Scanning buffers ------------------- - -(defun idlwave-get-routine-info-from-buffers (buffers) - "Call `idlwave-get-buffer-routine-info' on `idlwave-mode' buffers in BUFFERS." - (let (buf routine-lists res) - (save-excursion - (while (setq buf (pop buffers)) - (set-buffer buf) - (if (and (derived-mode-p 'idlwave-mode) - buffer-file-name) - ;; yes, this buffer has the right mode. - (progn (setq res (condition-case nil - (idlwave-get-buffer-routine-info) - (error nil))) - (push res routine-lists))))) - ;; Concatenate the individual lists and return the result - (apply #'nconc routine-lists))) - -(defun idlwave-get-buffer-routine-info () - "Scan the current buffer for routine info. Return (PRO-LIST FUNC-LIST)." - (let* ((case-fold-search t) - routine-list string entry) - (save-excursion - (save-restriction - (widen) - (goto-char (point-min)) - (while (re-search-forward - "^[ \t]*\\(pro\\|function\\)[ \t]" nil t) - (setq string (buffer-substring-no-properties - (match-beginning 0) - (progn - (idlwave-end-of-statement) - (point)))) - (setq entry (idlwave-parse-definition string)) - (push entry routine-list)))) - routine-list)) - -(defvar idlwave-scanning-lib-dir) -(defvar idlwave-scanning-lib) -(defun idlwave-parse-definition (string) - "Parse a module definition." - (let ((case-fold-search t) - start name args type keywords class) - ;; Remove comments - (while (string-match ";.*" string) - (setq string (replace-match "" t t string))) - ;; Remove the continuation line stuff - (while (string-match "\\([^a-zA-Z0-9$_]\\)\\$[ \t]*\n" string) - (setq string (replace-match "\\1 " t nil string))) - (while (string-match "\n" string) - (setq string (replace-match " " t nil string))) - ;; Match the name and type. - (when (string-match - "\\<\\(pro\\|function\\)\\>\\s-+\\(\\([a-zA-Z0-9$_]+\\)::\\)?\\([a-zA-Z0-9$_]+\\)" string) - (setq start (match-end 0)) - (setq type (downcase (match-string 1 string))) - (if (match-beginning 3) - (setq class (match-string 3 string))) - (setq name (match-string 4 string))) - ;; Match normal args and keyword args - (while (string-match - ",\\s-*\\([a-zA-Z][a-zA-Z0-9$_]*\\|\\(_ref\\)?_extra\\)\\s-*\\(=\\)?" - string start) - (setq start (match-end 0)) - (if (match-beginning 3) - (push (match-string 1 string) keywords) - (push (match-string 1 string) args))) - ;; Normalize and sort. - (setq args (nreverse args)) - (setq keywords (sort keywords (lambda (a b) - (string< (downcase a) (downcase b))))) - ;; Make and return the entry - ;; We don't know which argument are optional, so this information - ;; will not be contained in the calling sequence. - (list name - (if (equal type "pro") 'pro 'fun) - class - (cond ((not (boundp 'idlwave-scanning-lib)) - (list 'buffer (buffer-file-name))) -; ((string= (downcase (file-name-base (buffer-file-name)) -; (downcase name)) -; (list 'lib)) -; (t (cons 'lib (file-name-nondirectory (buffer-file-name)))) - (t (list 'user (file-name-nondirectory (buffer-file-name)) - idlwave-scanning-lib-dir "UserLib"))) - (concat - (if (string= type "function") "Result = " "") - (if class "Obj ->[%s::]" "") - "%s" - (if args - (concat - (if (string= type "function") "(" ", ") - (mapconcat #'identity args ", ") - (if (string= type "function") ")" "")))) - (if keywords - (cons nil (mapcar #'list keywords)) ;No help file - nil)))) - - -;;----- Scanning the user catalog ------------------- - -(defun idlwave-sys-dir () - "Return the syslib directory, or a dummy that never matches." - (cond - ((and idlwave-system-directory - (not (string= idlwave-system-directory ""))) - idlwave-system-directory) - ((getenv "IDL_DIR")) - (t "@@@@@@@@"))) - - -(defun idlwave-create-user-catalog-file (&optional arg) - "Scan all files on selected dirs of IDL search path for routine information. - -A widget checklist will allow you to choose the directories. Write -the result as a file `idlwave-user-catalog-file'. When this file -exists, it will be automatically loaded to give routine information -about library routines. With ARG, just rescan the same directories -as last time - so no widget will pop up." - (interactive "P") - ;; Make sure the file is loaded if it exists. - (if (and (stringp idlwave-user-catalog-file) - (file-regular-p idlwave-user-catalog-file)) - (condition-case nil - (load-file idlwave-user-catalog-file) - (error nil))) - ;; Make sure the file name makes sense - (unless (and (stringp idlwave-user-catalog-file) - (> (length idlwave-user-catalog-file) 0) - (file-accessible-directory-p - (file-name-directory idlwave-user-catalog-file)) - (not (string= "" (file-name-nondirectory - idlwave-user-catalog-file)))) - (error "`idlwave-user-catalog-file' does not point to a file in an accessible directory")) - - (cond - ;; Rescan the known directories - ((and arg idlwave-path-alist - (consp (car idlwave-path-alist))) - (idlwave-scan-user-lib-files idlwave-path-alist)) - - ;; Expand the directories from library-path and run the widget - (idlwave-library-path - (idlwave-display-user-catalog-widget - (if idlwave-true-path-alist - ;; Propagate any flags on the existing path-alist - (mapcar (lambda (x) - (let ((path-entry (assoc (file-truename x) - idlwave-true-path-alist))) - (if path-entry - (cons x (cdr path-entry)) - (list x)))) - (idlwave-expand-path idlwave-library-path)) - (mapcar #'list (idlwave-expand-path idlwave-library-path))))) - - ;; Ask the shell for the path and then run the widget - (t - (message "Asking the shell for IDL path...") - (require 'idlw-shell) - (idlwave-shell-send-command idlwave-shell-path-query - '(idlwave-user-catalog-command-hook nil) - 'hide)))) - - -;; Parse shell path information and select among it. -(defun idlwave-user-catalog-command-hook (&optional arg) - ;; Command hook used by `idlwave-create-user-catalog-file'. - (if arg - ;; Scan immediately - (idlwave-scan-user-lib-files idlwave-path-alist) - ;; Set the path and display the widget - (idlwave-shell-get-path-info 'no-write) ; set to something path-alist - (idlwave-scan-library-catalogs "Locating library catalogs..." 'no-load) - (idlwave-display-user-catalog-widget idlwave-path-alist))) - -(defconst idlwave-user-catalog-widget-help-string - "This is the front-end to the creation of the IDLWAVE user catalog. -Please select the directories on IDL's search path from which you -would like to extract routine information, to be stored in the file: - - %s - -If this is not the correct file, first set variable -`idlwave-user-catalog-file', and call this command again. - -N.B. Many libraries include pre-scanned catalog files -\(\".idlwave_catalog\"). These are marked with \"[LIB]\", and need -not be scanned. You can scan your own libraries off-line using the -perl script `idlwave_catalog'. - -After selecting the directories, choose [Scan & Save] to scan the library -directories and save the routine info. -\n") - -(defvar idlwave-widget) -(defvar widget-keymap) -(defun idlwave-display-user-catalog-widget (dirs-list) - "Create the widget to select IDL search path directories for scanning." - (interactive) - (require 'widget) - (require 'wid-edit) - (unless dirs-list - (error "Don't know IDL's search path")) - - (kill-buffer (get-buffer-create "*IDLWAVE Widget*")) - (switch-to-buffer (get-buffer-create "*IDLWAVE Widget*")) - (kill-all-local-variables) - (make-local-variable 'idlwave-widget) - (widget-insert (format idlwave-user-catalog-widget-help-string - idlwave-user-catalog-file)) - - (widget-create 'push-button - :notify 'idlwave-widget-scan-user-lib-files - "Scan & Save") - (widget-insert " ") - (widget-create 'push-button - :notify 'idlwave-delete-user-catalog-file - "Delete File") - (widget-insert " ") - (widget-create 'push-button - :notify - (lambda (&rest _ignore) - (let ((path-list (widget-get idlwave-widget :path-dirs))) - (dolist (x path-list) - (unless (memq 'lib (cdr x)) - (idlwave-path-alist-add-flag x 'user))) - (idlwave-display-user-catalog-widget path-list))) - "Select All Non-Lib") - (widget-insert " ") - (widget-create 'push-button - :notify - (lambda (&rest _ignore) - (let ((path-list (widget-get idlwave-widget :path-dirs))) - (dolist (x path-list) - (idlwave-path-alist-remove-flag x 'user)) - (idlwave-display-user-catalog-widget path-list))) - "Deselect All") - (widget-insert " ") - (widget-create 'push-button - :notify (lambda (&rest _ignore) - (kill-buffer (current-buffer))) - "Quit") - (widget-insert "\n\n") - - (widget-insert "Select Directories: \n") - - (setq idlwave-widget - (apply #'widget-create - 'checklist - :value (delq nil (mapcar (lambda (x) - (if (memq 'user (cdr x)) - (car x))) - dirs-list)) - :greedy t - :tag "List of directories" - (mapcar (lambda (x) - (list 'item - (if (memq 'lib (cdr x)) - (concat "[LIB] " (car x) ) - (car x)))) - dirs-list))) - (widget-put idlwave-widget :path-dirs dirs-list) - (widget-insert "\n") - (use-local-map widget-keymap) - (widget-setup) - (goto-char (point-min)) - (delete-other-windows)) - -(defun idlwave-delete-user-catalog-file (&rest _ignore) - (if (yes-or-no-p - (format "Delete file %s?" idlwave-user-catalog-file)) - (progn - (delete-file idlwave-user-catalog-file) - (message "%s has been deleted" idlwave-user-catalog-file)))) - -(defun idlwave-widget-scan-user-lib-files (&rest _ignore) - ;; Call `idlwave-scan-user-lib-files' with data taken from the widget. - (let* ((widget idlwave-widget) - (selected-dirs (widget-value widget)) - (path-alist (widget-get widget :path-dirs)) - (this-path-alist path-alist) - dir-entry) - (while (setq dir-entry (pop this-path-alist)) - (if (member - (if (memq 'lib (cdr dir-entry)) - (concat "[LIB] " (car dir-entry)) - (car dir-entry)) - selected-dirs) - (idlwave-path-alist-add-flag dir-entry 'user) - (idlwave-path-alist-remove-flag dir-entry 'user))) - (idlwave-scan-user-lib-files path-alist))) - -(defun idlwave-scan-user-lib-files (path-alist) - ;; Scan the PRO files in PATH-ALIST and store the info in the user catalog - (let* ((idlwave-scanning-lib t) - (idlwave-scanning-lib-dir "") - (idlwave-completion-case nil) - dirs-alist dir files file) - (setq idlwave-user-catalog-routines nil - idlwave-path-alist path-alist ; for library-path instead - idlwave-true-path-alist nil) - (if idlwave-auto-write-paths (idlwave-write-paths)) - (with-current-buffer (get-buffer-create "*idlwave-scan.pro*") - (idlwave-mode) - (setq dirs-alist (reverse path-alist)) - (while (setq dir (pop dirs-alist)) - (when (memq 'user (cdr dir)) ; Has it marked for scan? - (setq dir (car dir)) - (setq idlwave-scanning-lib-dir dir) - (when (file-directory-p dir) - (setq files (directory-files dir 'full "\\.[pP][rR][oO]\\'")) - (while (setq file (pop files)) - (when (file-regular-p file) - (if (not (file-readable-p file)) - (message "Skipping %s (no read permission)" file) - (message "Scanning %s..." file) - (erase-buffer) - (insert-file-contents file 'visit) - (setq idlwave-user-catalog-routines - (append (idlwave-get-routine-info-from-buffers - (list (current-buffer))) - idlwave-user-catalog-routines))))))))) - (message "Creating user catalog file...") - (kill-buffer "*idlwave-scan.pro*") - (kill-buffer (get-buffer-create "*IDLWAVE Widget*")) - (with-temp-buffer - (insert ";; IDLWAVE user catalog file\n") - (insert (format ";; Created %s\n\n" (current-time-string))) - - ;; Define the routine info list - (insert "\n(setq idlwave-user-catalog-routines\n '(") - (let ((standard-output (current-buffer))) - (mapc (lambda (x) - (insert "\n ") - (prin1 x) - (goto-char (point-max))) - idlwave-user-catalog-routines)) - (insert (format "))\n\n;;; %s ends here\n" - (file-name-nondirectory idlwave-user-catalog-file))) - (write-region nil nil idlwave-user-catalog-file))) - (message "Creating user catalog file...done") - (message "Info for %d routines saved in %s" - (length idlwave-user-catalog-routines) - idlwave-user-catalog-file) - (sit-for 2) - (idlwave-update-routine-info t)) - -(defun idlwave-read-paths () - (if (and (stringp idlwave-path-file) - (file-regular-p idlwave-path-file)) - (condition-case nil - (load idlwave-path-file t t t) - (error nil)))) - -(defun idlwave-write-paths () - (interactive) - (when (and idlwave-path-alist idlwave-system-directory) - (with-temp-buffer - (insert ";; IDLWAVE paths\n") - (insert (format ";; Created %s\n\n" (current-time-string))) - ;; Define the variable which knows the value of "!DIR" - (insert (format "\n(setq idlwave-system-directory \"%s\")\n" - idlwave-system-directory)) - - ;; Define the variable which contains a list of all scanned directories - (insert "\n(setq idlwave-path-alist\n '(") - (let ((standard-output (current-buffer))) - (mapc (lambda (x) - (insert "\n ") - (prin1 x) - (goto-char (point-max))) - idlwave-path-alist)) - (insert "))\n") - (write-region nil nil idlwave-path-file)))) - -(defun idlwave-expand-path (path &optional default-dir) - ;; Expand parts of path starting with '+' recursively into directory list. - ;; Relative recursive path elements are expanded relative to DEFAULT-DIR. - (message "Expanding path...") - (let (path1 dir recursive) - (while (setq dir (pop path)) - (if (setq recursive (string= (substring dir 0 1) "+")) - (setq dir (substring dir 1))) - (if (and recursive - (not (file-name-absolute-p dir))) - (setq dir (expand-file-name dir default-dir))) - (if recursive - ;; Expand recursively - (setq path1 (append (idlwave-recursive-directory-list dir) path1)) - ;; Keep unchanged - (push dir path1))) - (message "Expanding path...done") - (nreverse path1))) - -(defun idlwave-recursive-directory-list (dir) - ;; Return a list of all directories below DIR, including DIR itself - (let ((path (list dir)) path1 file files) - (while (setq dir (pop path)) - (when (file-directory-p dir) - (setq files (nreverse (directory-files dir t "[^.]"))) - (while (setq file (pop files)) - (if (file-directory-p file) - (push (file-name-as-directory file) path))) - (push dir path1))) - path1)) - - -;;----- Scanning the library catalogs ------------------ - - - - -(defun idlwave-scan-library-catalogs (&optional message-base no-load) - "Scan for library catalog files (.idlwave_catalog) and ingest. - -All directories on `idlwave-path-alist' (or `idlwave-library-path' -instead, if present) are searched. Print MESSAGE-BASE along with the -libraries being loaded, if passed, and skip loading/normalizing if -NO-LOAD is non-nil. The variable `idlwave-use-library-catalogs' can -be set to nil to disable library catalog scanning." - (when idlwave-use-library-catalogs - (let ((dirs - (if idlwave-library-path - (idlwave-expand-path idlwave-library-path) - (mapcar #'car idlwave-path-alist))) - (old-libname "") - dir-entry dir catalog all-routines) - (if message-base (message "%s" message-base)) - (while (setq dir (pop dirs)) - (catch 'continue - (when (file-readable-p - (setq catalog (expand-file-name ".idlwave_catalog" dir))) - (unless no-load - (setq idlwave-library-catalog-routines nil) - ;; Load the catalog file - (condition-case nil - (load catalog t t t) - (error (throw 'continue t))) - (when (and - message-base - (not (string= idlwave-library-catalog-libname - old-libname))) - (message "%s%s" message-base idlwave-library-catalog-libname) - (setq old-libname idlwave-library-catalog-libname)) - (when idlwave-library-catalog-routines - (setq all-routines - (append - (idlwave-sintern-rinfo-list - idlwave-library-catalog-routines 'sys dir) - all-routines)))) - - ;; Add a 'lib flag if on path-alist - (when (and idlwave-path-alist - (setq dir-entry (assoc dir idlwave-path-alist))) - (idlwave-path-alist-add-flag dir-entry 'lib))))) - (unless no-load (setq idlwave-library-catalog-routines all-routines)) - (if message-base (message "%sdone" message-base))))) - -;;----- Communicating with the Shell ------------------- - -;; First, here is the idl program which can be used to query IDL for -;; defined routines. -(defconst idlwave-routine-info.pro - " -;; START OF IDLWAVE SUPPORT ROUTINES -pro idlwave_print_safe,item,limit - catch,err - if err ne 0 then begin - print,'Could not print item.' - return - endif - if n_elements(item) gt limit then $ - print,item[0:limit-1],'<... truncated at ',strtrim(limit,2),' elements>' $ - else print,item -end - -pro idlwave_print_info_entry,name,func=func,separator=sep - ;; See if it's an object method - if name eq '' then return - func = keyword_set(func) - methsep = strpos(name,'::') - meth = methsep ne -1 - - ;; Get routine info - pars = routine_info(name,/parameters,functions=func) - source = routine_info(name,/source,functions=func) - nargs = pars.num_args - nkw = pars.num_kw_args - if nargs gt 0 then args = pars.args - if nkw gt 0 then kwargs = pars.kw_args - - ;; Trim the class, and make the name - if meth then begin - class = strmid(name,0,methsep) - name = strmid(name,methsep+2,strlen(name)-1) - if nargs gt 0 then begin - ;; remove the self argument - wh = where(args ne 'SELF',nargs) - if nargs gt 0 then args = args[wh] - endif - endif else begin - ;; No class, just a normal routine. - class = \"\" - endelse - - ;; Calling sequence - cs = \"\" - if func then cs = 'Result = ' - if meth then cs = cs + 'Obj -> [' + '%s' + '::]' - cs = cs + '%s' - if func then cs = cs + '(' else if nargs gt 0 then cs = cs + ', ' - if nargs gt 0 then begin - for j=0,nargs-1 do begin - cs = cs + args[j] - if j lt nargs-1 then cs = cs + ', ' - endfor - end - if func then cs = cs + ')' - ;; Keyword arguments - kwstring = '' - if nkw gt 0 then begin - for j=0,nkw-1 do begin - kwstring = kwstring + ' ' + kwargs[j] - endfor - endif - - ret=(['IDLWAVE-PRO','IDLWAVE-FUN'])[func] - - print,ret + ': ' + name + sep + class + sep + source[0].path $ - + sep + cs + sep + kwstring -end - -pro idlwave_routine_info,file - on_error,1 - sep = '<@>' - print,'>>>BEGIN OF IDLWAVE ROUTINE INFO (\"' + sep + '\" IS THE SEPARATOR)' - all = routine_info() - fileQ=n_elements(file) ne 0 - if fileQ then file=strtrim(file,2) - for i=0L,n_elements(all)-1L do begin - if fileQ then begin - if (routine_info(all[i],/SOURCE)).path eq file then $ - idlwave_print_info_entry,all[i],separator=sep - endif else idlwave_print_info_entry,all[i],separator=sep - endfor - all = routine_info(/functions) - for i=0L,n_elements(all)-1L do begin - if fileQ then begin - if (routine_info(all[i],/FUNCTIONS,/SOURCE)).path eq file then $ - idlwave_print_info_entry,all[i],separator=sep,/FUNC - endif else idlwave_print_info_entry,all[i],separator=sep,/FUNC - endfor - print,'>>>END OF IDLWAVE ROUTINE INFO' -end - -pro idlwave_get_sysvars - on_error,1 - catch,error_status - if error_status ne 0 then begin - print, 'Cannot get info about system variables' - endif else begin - help,/brief,output=s,/system_variables ; ? unsafe use of OUTPUT= - s = strtrim(strjoin(s,' ',/single),2) ; make one line - v = strsplit(s,' +',/regex,/extract) ; get variables - for i=0L,n_elements(v)-1 do begin - t = [''] ; get tag list - a=execute('if n_tags('+v[i]+') gt 0 then t=tag_names('+v[i]+')') - print, 'IDLWAVE-SYSVAR: '+v[i]+' '+strjoin(t,' ',/single) - endfor - endelse -end - -pro idlwave_get_class_tags, class - res = execute('tags=tag_names({'+class+'})') - if res then print,'IDLWAVE-CLASS-TAGS: '+class+' '+strjoin(tags,' ',/single) -end -;; END OF IDLWAVE SUPPORT ROUTINES -" - "The IDL programs to get info from the shell.") - -(defvar idlwave-idlwave_routine_info-compiled nil - "Remember if the routine info procedure is already compiled.") - -(defvar idlwave-shell-temp-pro-file) -(defvar idlwave-shell-temp-rinfo-save-file) - -(defun idlwave-shell-compile-helper-routines (&optional wait) - (unless (and idlwave-idlwave_routine_info-compiled - (file-readable-p (idlwave-shell-temp-file 'rinfo))) - (with-current-buffer (idlwave-find-file-noselect - (idlwave-shell-temp-file 'pro)) - (erase-buffer) - (insert idlwave-routine-info.pro) - (save-buffer 0)) - (idlwave-shell-send-command - (concat ".run \"" idlwave-shell-temp-pro-file "\"") - nil 'hide wait) - (idlwave-shell-send-command - (format "save,'idlwave_print_safe','idlwave_routine_info','idlwave_print_info_entry','idlwave_get_class_tags','idlwave_get_sysvars',FILE='%s',/ROUTINES" - (idlwave-shell-temp-file 'rinfo)) - nil 'hide) - (setq idlwave-idlwave_routine_info-compiled t)) - - ;; Restore if necessary. Must use execute to hide lame routine_info - ;; errors on undefined routine - (idlwave-shell-send-command - (format "if execute(\"_v=routine_info('idlwave_routine_info',/SOURCE)\") eq 0 then restore,'%s' else if _v.path eq '' then restore,'%s'" - idlwave-shell-temp-rinfo-save-file - idlwave-shell-temp-rinfo-save-file) - nil 'hide)) - - -(defun idlwave-shell-update-routine-info (&optional quiet run-hooks wait file) - "Query the shell for routine_info of compiled modules and update the lists." - ;; Save and compile the procedure. The compiled procedure is then - ;; saved into an IDL SAVE file, to allow for fast RESTORE. We may - ;; need to test for and possibly RESTORE the procedure each time we - ;; use it, since the user may have killed or redefined it. In - ;; particular, .RESET_SESSION will kill all user procedures. If - ;; FILE is set, only update routine info for routines in that file. - - (idlwave-shell-compile-helper-routines wait) - ; execute the routine_info procedure, and analyze the output - (idlwave-shell-send-command - (format "idlwave_routine_info%s" (if file (concat ",'" file "'") "")) - `(progn - (idlwave-shell-routine-info-filter) - (idlwave-concatenate-rinfo-lists ,quiet ,run-hooks)) - 'hide wait)) - -;; --------------------------------------------------------------------------- -;; -;; Completion and displaying routine calling sequences - -(defvar idlwave-completion-help-info nil) -(defvar idlwave-completion-help-links nil) -(defvar idlwave-current-obj_new-class nil) -(defvar idlwave--method-selector) -(defvar idlwave--class-selector) -(defvar idlwave--type-selector) -(defvar idlwave--super-classes) - -(defun idlwave-complete (&optional arg module class) - "Complete a function, procedure or keyword name at point. -This function is smart and figures out what can be completed -at this point. -- At the beginning of a statement it completes procedure names. -- In the middle of a statement it completes function names. -- After a `(' or `,' in the argument list of a function or procedure, - it completes a keyword of the relevant function or procedure. -- In the first arg of `OBJ_NEW', it completes a class name. - -When several completions are possible, a list will be displayed in -the *Completions* buffer. If this list is too long to fit into the -window, scrolling can be achieved by repeatedly pressing -\\[idlwave-complete]. - -The function also knows about object methods. When it needs a class -name, the action depends upon `idlwave-query-class', which see. You -can force IDLWAVE to ask you for a class name with a -\\[universal-argument] prefix argument to this command. - -See also the variables `idlwave-keyword-completion-adds-equal' and -`idlwave-function-completion-adds-paren'. - -The optional ARG can be used to specify the completion type in order -to override IDLWAVE's idea of what should be completed at point. -Possible values are: - -0 <=> query for the completion type -1 <=> `procedure' -2 <=> `procedure-keyword' -3 <=> `function' -4 <=> `function-keyword' -5 <=> `procedure-method' -6 <=> `procedure-method-keyword' -7 <=> `function-method' -8 <=> `function-method-keyword' -9 <=> `class' - -As a special case, the universal argument \\[universal-argument] forces completion of -function names in places where the default would be a keyword. - -For Lisp programmers only: -When we force a keyword, optional argument MODULE can contain the module name. -When we force a method or a method keyword, CLASS can specify the class." - (interactive "P") - (idlwave-routines) - (let* ((where-list - (if (and arg - (or (and (integerp arg) (not (equal arg '(16)))) - (symbolp arg))) - (idlwave-make-force-complete-where-list arg module class) - (idlwave-where))) - (what (nth 2 where-list)) - (idlwave-force-class-query (equal arg '(4)))) - - (if (and module (string-match "::" module)) - (setq class (substring module 0 (match-beginning 0)) - module (substring module (match-end 0)))) - - (cond - - ((and (null arg) - (eq (car-safe last-command) 'idlwave-display-completion-list) - (get-buffer-window "*Completions*")) - (setq this-command last-command) - (idlwave-scroll-completions)) - - ;; Complete a filename in quotes - ((and (idlwave-in-quote) - (not (eq what 'class))) - (idlwave-complete-filename)) - - ;; Check for any special completion functions - ((run-hook-with-args-until-success 'idlwave-complete-functions)) - - ((null what) - (error "Nothing to complete here")) - - ;; Complete a class - ((eq what 'class) - (setq idlwave-completion-help-info '(class)) - (idlwave-complete-class)) - - ((eq what 'procedure) - ;; Complete a procedure name - (let* ((cw-list (nth 3 where-list)) - (idlwave--class-selector (idlwave-determine-class cw-list 'pro)) - (idlwave--super-classes - (unless (idlwave-explicit-class-listed cw-list) - (idlwave-all-class-inherits idlwave--class-selector))) - (isa (concat "procedure" - (if idlwave--class-selector "-method" ""))) - (idlwave--type-selector 'pro)) - (setq idlwave-completion-help-info - (list 'routine nil - idlwave--type-selector idlwave--class-selector - nil idlwave--super-classes)) - (idlwave-complete-in-buffer - 'procedure (if idlwave--class-selector 'method 'routine) - (idlwave-routines) 'idlwave-selector - (format "Select a %s name%s" - isa - (if idlwave--class-selector - (format " (class is %s)" - (if (eq idlwave--class-selector t) - "unknown" idlwave--class-selector)) - "")) - isa - 'idlwave-attach-method-classes 'idlwave-add-file-link-selector))) - - ((eq what 'function) - ;; Complete a function name - (let* ((cw-list (nth 3 where-list)) - (idlwave--class-selector (idlwave-determine-class cw-list 'fun)) - (idlwave--super-classes - (unless (idlwave-explicit-class-listed cw-list) - (idlwave-all-class-inherits idlwave--class-selector))) - (isa (concat "function" (if idlwave--class-selector "-method" ""))) - (idlwave--type-selector 'fun)) - (setq idlwave-completion-help-info - (list 'routine nil - idlwave--type-selector idlwave--class-selector - nil idlwave--super-classes)) - (idlwave-complete-in-buffer - 'function (if idlwave--class-selector 'method 'routine) - (idlwave-routines) 'idlwave-selector - (format "Select a %s name%s" - isa - (if idlwave--class-selector - (format " (class is %s)" - (if (eq idlwave--class-selector t) - "unknown" idlwave--class-selector)) - "")) - isa - 'idlwave-attach-method-classes 'idlwave-add-file-link-selector))) - - ((and (memq what '(procedure-keyword function-keyword)) ; Special Case - (equal arg '(4))) - (idlwave-complete 3)) - - ((eq what 'procedure-keyword) - ;; Complete a procedure keyword - (let* ((where (nth 3 where-list)) - (name (car where)) - (idlwave--method-selector name) - (idlwave--type-selector 'pro) - (class (idlwave-determine-class where 'pro)) - (idlwave--class-selector class) - (idlwave--super-classes (idlwave-all-class-inherits - idlwave--class-selector)) - (isa (format "procedure%s-keyword" (if class "-method" ""))) - (entry (idlwave-best-rinfo-assq - name 'pro class (idlwave-routines))) - (system (if entry (eq (car (nth 3 entry)) 'system))) - (list (idlwave-entry-keywords entry 'do-link))) - (unless (or entry (eq class t)) - (error "Nothing known about procedure %s" - (idlwave-make-full-name class name))) - (setq list (idlwave-fix-keywords name 'pro class list - idlwave--super-classes system)) - (unless list (error "No keywords available for procedure %s" - (idlwave-make-full-name class name))) - (setq idlwave-completion-help-info - (list 'keyword name - idlwave--type-selector idlwave--class-selector - entry idlwave--super-classes)) - (idlwave-complete-in-buffer - 'keyword 'keyword list nil - (format "Select keyword for procedure %s%s" - (idlwave-make-full-name class name) - (if (or (member '("_EXTRA") list) - (member '("_REF_EXTRA") list)) - " (note _EXTRA)" "")) - isa - 'idlwave-attach-keyword-classes))) - - ((eq what 'function-keyword) - ;; Complete a function keyword - (let* ((where (nth 3 where-list)) - (name (car where)) - (idlwave--method-selector name) - (idlwave--type-selector 'fun) - (class (idlwave-determine-class where 'fun)) - (idlwave--class-selector class) - (idlwave--super-classes (idlwave-all-class-inherits - idlwave--class-selector)) - (isa (format "function%s-keyword" (if class "-method" ""))) - (entry (idlwave-best-rinfo-assq - name 'fun class (idlwave-routines))) - (system (if entry (eq (car (nth 3 entry)) 'system))) - (list (idlwave-entry-keywords entry 'do-link)) - msg-name) - (unless (or entry (eq class t)) - (error "Nothing known about function %s" - (idlwave-make-full-name class name))) - (setq list (idlwave-fix-keywords name 'fun class list - idlwave--super-classes system)) - ;; OBJ_NEW: Messages mention the proper Init method - (setq msg-name (if (and (null class) - (string= (upcase name) "OBJ_NEW")) - (concat idlwave-current-obj_new-class - "::Init (via OBJ_NEW)") - (idlwave-make-full-name class name))) - (unless list (error "No keywords available for function %s" - msg-name)) - (setq idlwave-completion-help-info - (list 'keyword name - idlwave--type-selector idlwave--class-selector - nil idlwave--super-classes)) - (idlwave-complete-in-buffer - 'keyword 'keyword list nil - (format "Select keyword for function %s%s" msg-name - (if (or (member '("_EXTRA") list) - (member '("_REF_EXTRA") list)) - " (note _EXTRA)" "")) - isa - 'idlwave-attach-keyword-classes))) - - (t (error "This should not happen (idlwave-complete)"))))) - -(define-obsolete-variable-alias 'idlwave-complete-special - 'idlwave-complete-functions "28.1") -(defvar idlwave-complete-functions nil - "List of special completion functions. -These functions are called for each completion. Each function must -check if its own special completion context is present. If yes, it -should use `idlwave-complete-in-buffer' to do some completion and -return t. If such a function returns t, *no further* attempts to -complete other contexts will be done. If the function returns nil, -other completions will be tried.") - -(defun idlwave-call-special (functions &rest args) - (declare (obsolete run-hook-with-args-until-success "28.1")) - (let ((funcs functions) - fun ret) - (catch 'exit - (while (setq fun (pop funcs)) - (if (setq ret (apply fun args)) - (throw 'exit ret))) - nil))) - -(defun idlwave-make-force-complete-where-list (what &optional module class) - ;; Return an artificial WHERE specification to force the completion - ;; routine to complete a specific item independent of context. - ;; WHAT is the prefix arg of `idlwave-complete', see there for details. - ;; MODULE and CLASS can be used to specify the routine name and class. - ;; The class name will also be found in MODULE if that is like "class::mod". - (let* ((what-list '(("procedure") ("procedure-keyword") - ("function") ("function-keyword") - ("procedure-method") ("procedure-method-keyword") - ("function-method") ("function-method-keyword") - ("class"))) - (module (idlwave-sintern-routine-or-method module class)) - (class (idlwave-sintern-class class)) - (what (cond - ((equal what 0) - (setq what - (intern (completing-read - "Complete what? " what-list nil t)))) - ((integerp what) - (setq what (intern (car (nth (1- what) what-list))))) - ((and what - (symbolp what) - (assoc (symbol-name what) what-list)) - what) - (t (error "Invalid WHAT")))) - (nil-list '(nil nil nil nil)) - (class-list (list nil nil (or class t) nil))) - - (cond - - ((eq what 'procedure) - (list nil-list nil-list 'procedure nil-list nil)) - - ((eq what 'procedure-keyword) - (let* ((idlwave--class-selector nil) - (idlwave--super-classes nil) - (idlwave--type-selector 'pro) - (pro (or module - (idlwave-completing-read - "Procedure: " (idlwave-routines) 'idlwave-selector)))) - (setq pro (idlwave-sintern-routine pro)) - (list nil-list nil-list 'procedure-keyword - (list pro nil nil nil) nil))) - - ((eq what 'function) - (list nil-list nil-list 'function nil-list nil)) - - ((eq what 'function-keyword) - (let* ((idlwave--class-selector nil) - (idlwave--super-classes nil) - (idlwave--type-selector 'fun) - (func (or module - (idlwave-completing-read - "Function: " (idlwave-routines) 'idlwave-selector)))) - (setq func (idlwave-sintern-routine func)) - (list nil-list nil-list 'function-keyword - (list func nil nil nil) nil))) - - ((eq what 'procedure-method) - (list nil-list nil-list 'procedure class-list nil)) - - ((eq what 'procedure-method-keyword) - (let* ((class (idlwave-determine-class class-list 'pro)) - (idlwave--class-selector class) - (idlwave--super-classes (idlwave-all-class-inherits - idlwave--class-selector)) - (idlwave--type-selector 'pro) - (pro (or module - (idlwave-completing-read - (format "Procedure in %s class: " - idlwave--class-selector) - (idlwave-routines) 'idlwave-selector)))) - (setq pro (idlwave-sintern-method pro)) - (list nil-list nil-list 'procedure-keyword - (list pro nil class nil) nil))) - - ((eq what 'function-method) - (list nil-list nil-list 'function class-list nil)) - - ((eq what 'function-method-keyword) - (let* ((class (idlwave-determine-class class-list 'fun)) - (idlwave--class-selector class) - (idlwave--super-classes (idlwave-all-class-inherits - idlwave--class-selector)) - (idlwave--type-selector 'fun) - (func (or module - (idlwave-completing-read - (format "Function in %s class: " - idlwave--class-selector) - (idlwave-routines) 'idlwave-selector)))) - (setq func (idlwave-sintern-method func)) - (list nil-list nil-list 'function-keyword - (list func nil class nil) nil))) - - ((eq what 'class) - (list nil-list nil-list 'class nil-list nil)) - - (t (error "Invalid value for WHAT"))))) - -(defun idlwave-completing-read (&rest args) - ;; Completing read, case insensitive - (let ((old-value (default-value 'completion-ignore-case))) - (unwind-protect - (progn - (setq-default completion-ignore-case t) - (apply #'completing-read args)) - (setq-default completion-ignore-case old-value)))) - -(defvar idlwave-shell-default-directory) -(defun idlwave-complete-filename () - "Use the comint stuff to complete a file name." - (require 'comint) - (dlet ((comint-file-name-chars "~/A-Za-z0-9+@:_.$#%={}\\-") - (comint-completion-addsuffix nil) - (default-directory - (if (and (boundp 'idlwave-shell-default-directory) - (stringp idlwave-shell-default-directory) - (file-directory-p idlwave-shell-default-directory)) - idlwave-shell-default-directory - default-directory))) - (comint-dynamic-complete-filename))) - -(defun idlwave-make-full-name (class name) - ;; Make a fully qualified module name including the class name - (concat (if class (format "%s::" class) "") name)) - -(defun idlwave-rinfo-assoc (name type class list) - "Like `idlwave-rinfo-assq', but sintern strings first." - (idlwave-rinfo-assq - (idlwave-sintern-routine-or-method name class) - type (idlwave-sintern-class class) list)) - -(defun idlwave-rinfo-assq (name type class list) - ;; Works like assq, but also checks type and class - (catch 'exit - (let (match) - (while (setq match (assq name list)) - (and (or (eq type t) - (eq (nth 1 match) type)) - (eq (nth 2 match) class) - (throw 'exit match)) - (setq list (cdr (memq match list))))))) - -(defun idlwave-rinfo-assq-any-class (name type class list) - ;; Return the first matching method on the inheritance list - (let* ((classes (cons class (idlwave-all-class-inherits class))) - rtn) ;; class - (while classes - (if (setq rtn (idlwave-rinfo-assq name type (pop classes) list)) - (setq classes nil))) - rtn)) - -(defun idlwave-best-rinfo-assq (name type class list &optional with-file - keep-system) - "Like `idlwave-rinfo-assq', but get all twins and sort, then return first. -If WITH-FILE is passed, find the best rinfo entry with a file -included. If KEEP-SYSTEM is set, don't prune system for compiled -syslib files." - (let ((twins (idlwave-routine-twins - (idlwave-rinfo-assq-any-class name type class list) - list)) - syslibp) - (when (> (length twins) 1) - (setq twins (sort twins #'idlwave-routine-entry-compare-twins)) - (if (and (null keep-system) - (eq 'system (car (nth 3 (car twins)))) - (setq syslibp (idlwave-any-syslib (cdr twins))) - (not (equal 1 syslibp))) - ;; Its a compiled syslib, so we need to remove the system entry - (setq twins (cdr twins))) - (if with-file - (setq twins (delq nil - (mapcar (lambda (x) - (if (nth 1 (nth 3 x)) x)) - twins))))) - (car twins))) - -(defun idlwave-best-rinfo-assoc (name type class list &optional with-file - keep-system) - "Like `idlwave-best-rinfo-assq', but sintern strings first." - (idlwave-best-rinfo-assq - (idlwave-sintern-routine-or-method name class) - type (idlwave-sintern-class class) list with-file keep-system)) - -(defun idlwave-any-syslib (entries) - "Does the entry list ENTRIES contain a syslib entry? -If yes, return the index (>=1)." - (let (file (cnt 0)) - (catch 'exit - (while entries - (cl-incf cnt) - (setq file (idlwave-routine-source-file (nth 3 (car entries)))) - (if (and file (idlwave-syslib-p file)) - (throw 'exit cnt) - (setq entries (cdr entries)))) - nil))) - -(defun idlwave-all-assq (key list) - "Return a list of all associations of Key in LIST." - (let (rtn elt) - (while (setq elt (assq key list)) - (push elt rtn) - (setq list (cdr (memq elt list)))) - (nreverse rtn))) - -(defun idlwave-all-method-classes (method &optional type) - "Return all classes which have a method METHOD. -TYPE is `fun' or `pro'. -When TYPE is not specified, both procedures and functions will be considered." - (if (null method) - (mapcar #'car (idlwave-class-alist)) - (let (rtn) - (mapc (lambda (x) - (and (nth 2 x) - (or (not type) - (eq type (nth 1 x))) - (push (nth 2 x) rtn))) - (idlwave-all-assq method (idlwave-routines))) - (idlwave-uniquify rtn)))) - -(defun idlwave-all-method-keyword-classes (method keyword &optional type) - "Return all classes which have a method METHOD with keyword KEYWORD. -TYPE is `fun' or `pro'. -When TYPE is not specified, both procedures and functions will be considered." - (if (or (null method) - (null keyword)) - nil - (let (rtn) - (mapc (lambda (x) - (and (nth 2 x) ; non-nil class - (or (not type) ; correct or unspecified type - (eq type (nth 1 x))) - (assoc keyword (idlwave-entry-keywords x)) - (push (nth 2 x) rtn))) - (idlwave-all-assq method (idlwave-routines))) - (idlwave-uniquify rtn)))) - -(defun idlwave-members-only (list club) - "Return list of all elements in LIST which are also in CLUB." - (let (rtn) - (while list - (if (member (car list) club) - (setq rtn (cons (car list) rtn))) - (setq list (cdr list))) - (nreverse rtn))) - -(defun idlwave-nonmembers-only (list club) - "Return list of all elements in LIST which are not in CLUB." - (let (rtn) - (while list - (if (member (car list) club) - nil - (setq rtn (cons (car list) rtn))) - (setq list (cdr list))) - (nreverse rtn))) - -(defun idlwave-explicit-class-listed (info) - "Return whether or not the class is listed explicitly, ala a->b::c. -INFO is as returned by `idlwave-what-function' or `-procedure'." - (let ((apos (nth 3 info))) - (if apos - (save-excursion (goto-char apos) - (looking-at "->[a-zA-Z][a-zA-Z0-9$_]*::"))))) - -(define-obsolete-variable-alias 'idlwave-determine-class-special - 'idlwave-determine-class-functions "28.1") -(defvar idlwave-determine-class-functions nil - "Special hook to determine a class. -The functions should accept one argument, APOS.") - -(defun idlwave-determine-class (info type) - ;; Determine the class of a routine call. - ;; INFO is the `cw-list' structure as returned by idlwave-where. - ;; The second element in this structure is the class. When nil, we - ;; return nil. When t, try to get the class from text properties at - ;; the arrow. When the object is "self", we use the class of the - ;; current routine. otherwise prompt the user for a class name. - ;; Also stores the selected class as a text property at the arrow. - ;; TYPE is 'fun or 'pro. - (let* ((class (nth 2 info)) - (apos (nth 3 info)) - (nassoc (assoc (if (stringp (car info)) - (upcase (car info)) - (car info)) - idlwave-query-class)) - (dassoc (assq (if (car info) 'keyword-default 'method-default) - idlwave-query-class)) - (query (cond (nassoc (cdr nassoc)) - (dassoc (cdr dassoc)) - (t t))) - (arrow (and apos (string= (buffer-substring apos (+ 2 apos)) "->"))) - (is-self - (and arrow - (save-excursion (goto-char apos) - (forward-word-strictly -1) - (let ((case-fold-search t)) - (looking-at "self\\>"))))) - (force-query idlwave-force-class-query) - store special-class class-alist) - (cond - ((null class) nil) - ((eq t class) - ;; There is an object which would like to know its class - (if (and arrow (get-text-property apos 'idlwave-class) - idlwave-store-inquired-class - (not force-query)) - (setq class (get-text-property apos 'idlwave-class) - class (idlwave-sintern-class class))) - (if (and (eq t class) is-self) - (setq class (or (nth 2 (idlwave-current-routine)) class))) - - ;; Before prompting, try any special class determination routines - (when (and (eq t class) - (not force-query)) - (setq special-class - (run-hook-with-args-until-success - 'idlwave-determine-class-functions apos)) - (if special-class - (setq class (idlwave-sintern-class special-class) - store idlwave-store-inquired-class))) - - ;; Prompt for a class, if we need to - (when (and (eq class t) - (or force-query query)) - (setq class-alist - (mapcar #'list (idlwave-all-method-classes (car info) type))) - (setq class - (idlwave-sintern-class - (cond - ((and (= (length class-alist) 0) (not force-query)) - (error "No classes available with method %s" (car info))) - ((and (= (length class-alist) 1) (not force-query)) - (car (car class-alist))) - (t - (setq store idlwave-store-inquired-class) - (idlwave-completing-read - (format "Class%s: " (if (stringp (car info)) - (format " for %s method %s" - type (car info)) - "")) - class-alist nil nil nil 'idlwave-class-history)))))) - - ;; Store it, if requested - (when (and class (not (eq t class))) - ;; We have a real class here - (when (and store arrow) - (condition-case () - (add-text-properties - apos (+ apos 2) - `(idlwave-class ,class face ,idlwave-class-arrow-face - rear-nonsticky t)) - (error nil))) - (setf (nth 2 info) class)) - ;; Return the class - class) - ;; Default as fallback - (t class)))) - -(defun idlwave-selector (a) - (and (eq (nth 1 a) idlwave--type-selector) - (or (and (nth 2 a) (eq idlwave--class-selector t)) - (eq (nth 2 a) idlwave--class-selector) - (memq (nth 2 a) idlwave--super-classes)))) - -(defun idlwave-add-file-link-selector (a) - ;; Record a file link, if any, for the tested names during selection. - (let ((sel (idlwave-selector a)) file) - (if (and sel (setq file (idlwave-entry-has-help a))) - (push (cons (car a) file) idlwave-completion-help-links)) - sel)) - - -(defun idlwave-where () - "Find out where we are. -The return value is a list with the following stuff: -\(PRO-LIST FUNC-LIST COMPLETE-WHAT CW-LIST LAST-CHAR) - -PRO-LIST (PRO POINT CLASS ARROW) -FUNC-LIST (FUNC POINT CLASS ARROW) -COMPLETE-WHAT a symbol indicating what kind of completion makes sense here -CW-LIST (PRO-OR-FUNC POINT CLASS ARROW) Like PRO-LIST, for what can - be completed here. -LAST-CHAR last relevant character before point (non-white non-comment, - not part of current identifier or leading slash). - -In the lists, we have these meanings: -PRO: Procedure name -FUNC: Function name -POINT: Where is this -CLASS: What class has the routine (nil=no, t=is method, but class unknown) -ARROW: Location of the arrow" - (idlwave-routines) - (let* (;(bos (save-excursion (idlwave-beginning-of-statement) (point))) - (bos (save-excursion (idlwave-start-of-substatement 'pre) (point))) - (func-entry (idlwave-what-function bos)) - (func (car func-entry)) - (func-class (nth 1 func-entry)) - (func-arrow (nth 2 func-entry)) - (func-point (or (nth 3 func-entry) 0)) - (func-level (or (nth 4 func-entry) 0)) - (pro-entry (idlwave-what-procedure bos)) - (pro (car pro-entry)) - (pro-class (nth 1 pro-entry)) - (pro-arrow (nth 2 pro-entry)) - (pro-point (or (nth 3 pro-entry) 0)) - (last-char (idlwave-last-valid-char)) - (case-fold-search t) - (match-string (buffer-substring bos (point))) - cw cw-mod cw-arrow cw-class cw-point) - (if (< func-point pro-point) (setq func nil)) - (cond - ((string-match "\\`[ \t]*\\(pro\\|function\\)[ \t]+[a-zA-Z0-9_]*\\'" - match-string) - (setq cw 'class)) - ((string-match - "\\`[ \t]*\\([a-zA-Z][a-zA-Z0-9$_]*\\)?\\'" - (if (> pro-point 0) - (buffer-substring pro-point (point)) - match-string)) - (setq cw 'procedure cw-class pro-class cw-point pro-point - cw-arrow pro-arrow)) - ((string-match "\\`[ \t]*\\(pro\\|function\\)\\>" - match-string) - nil) - ((string-match "OBJ_NEW([ \t]*['\"][a-zA-Z0-9$_]*\\'" - match-string) - (setq cw 'class)) - ((string-match "\\ func-point pro-point) - (= func-level 1) - (memq last-char '(?\( ?,))) - (setq cw 'function-keyword cw-mod func cw-point func-point - cw-class func-class cw-arrow func-arrow)) - ((and pro (eq last-char ?,)) - (setq cw 'procedure-keyword cw-mod pro cw-point pro-point - cw-class pro-class cw-arrow pro-arrow)) -; ((member last-char '(?\' ?\) ?\] ?!)) -; ;; after these chars, a function makes no sense -; ;; FIXME: I am sure there can be more in this list -; ;; FIXME: Do we want to do this at all? -; nil) - ;; Everywhere else we try a function. - (t - (setq cw 'function) - (save-excursion - (if (re-search-backward "->[ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\s-*\\)?\\(\\([$a-zA-Z0-9_]+\\)::\\)?[$a-zA-Z0-9_]*\\=" bos t) - (setq cw-arrow (copy-marker (match-beginning 0)) - cw-class (if (match-end 4) - (idlwave-sintern-class (match-string 4)) - t)))))) - (list (list pro pro-point pro-class pro-arrow) - (list func func-point func-class func-arrow) - cw - (list cw-mod cw-point cw-class cw-arrow) - last-char))) - -(defun idlwave-this-word (&optional class) - ;; Grab the word around point. CLASS is for the `skip-chars=...' functions - (setq class (or class "a-zA-Z0-9$_.")) - (save-excursion - (buffer-substring - (progn (skip-chars-backward class) (point)) - (progn (skip-chars-forward class) (point))))) - -(defun idlwave-what-function (&optional bound) - ;; Find out if point is within the argument list of a function. - ;; The return value is ("function-name" class arrow-start (point) level). - ;; Level is 1 on the top level parentheses, higher further down. - - ;; If the optional BOUND is an integer, bound backwards directed - ;; searches to this point. - - (catch 'exit - (let (pos - func-point - (cnt 0) - func arrow-start class) - (with-syntax-table idlwave-find-symbol-syntax-table - (save-restriction - (save-excursion - (narrow-to-region (max 1 (or bound 0)) (point-max)) - ;; move back out of the current parenthesis - (while (condition-case nil - (progn (up-list -1) t) - (error nil)) - (setq pos (point)) - (cl-incf cnt) - (when (and (= (following-char) ?\() - (re-search-backward - "\\(::\\|\\<\\)\\([a-zA-Z][a-zA-Z0-9$_]*\\)[ \t]*\\=" - bound t)) - (setq func (match-string 2) - func-point (goto-char (match-beginning 2)) - pos func-point) - (if (re-search-backward - "->[ \t]*\\(\\([a-zA-Z][a-zA-Z0-9$_]*\\)::\\)?\\=" bound t) - (setq arrow-start (copy-marker (match-beginning 0)) - class (or (match-string 2) t))) - (throw - 'exit - (list - (idlwave-sintern-routine-or-method func class) - (idlwave-sintern-class class) - arrow-start func-point cnt))) - (goto-char pos)) - (throw 'exit nil))))))) - -(defun idlwave-what-procedure (&optional _bound) - ;; Find out if point is within the argument list of a procedure. - ;; The return value is ("procedure-name" class arrow-pos (point)). - - ;; If the optional BOUND is an integer, bound backwards directed - ;; searches to this point. - (let ((pos (point)) pro-point - pro class arrow-start string) - (save-excursion - ;;(idlwave-beginning-of-statement) - (idlwave-start-of-substatement 'pre) - (setq string (buffer-substring (point) pos)) - (if (string-match - "\\`[ \t]*\\([a-zA-Z][a-zA-Z0-9$_]*\\)[ \t]*\\(,\\|\\'\\)" string) - (setq pro (match-string 1 string) - pro-point (+ (point) (match-beginning 1))) - (if (and (idlwave-skip-object) - (setq string (buffer-substring (point) pos)) - (string-match - "\\`[ \t]*\\(->\\)[ \t]*\\(\\([a-zA-Z][a-zA-Z0-9$_]*\\)::\\)?\\([a-zA-Z][a-zA-Z0-9$_]*\\)?[ \t]*\\(,\\|\\(\\$\\s *\\(;.*\\)?\\)?$\\)" - string)) - (setq pro (if (match-beginning 4) - (match-string 4 string)) - pro-point (if (match-beginning 4) - (+ (point) (match-beginning 4)) - pos) - arrow-start (copy-marker (+ (point) (match-beginning 1))) - class (or (match-string 3 string) t))))) - (list (idlwave-sintern-routine-or-method pro class) - (idlwave-sintern-class class) - arrow-start - pro-point))) - -(defun idlwave-skip-object () - ;; If there is an object at point, move over it and return t. - (let ((pos (point))) - (if (catch 'exit - (save-excursion - (skip-chars-forward " ") ; white space - (skip-chars-forward "*") ; de-reference - (cond - ((looking-at idlwave-identifier) - (goto-char (match-end 0))) - ((eq (following-char) ?\() - nil) - (t (throw 'exit nil))) - (catch 'endwhile - (while t - (cond ((eq (following-char) ?.) - (forward-char 1) - (if (not (looking-at idlwave-identifier)) - (throw 'exit nil)) - (goto-char (match-end 0))) - ((memq (following-char) '(?\( ?\[)) - (condition-case nil - (forward-list 1) - (error (throw 'exit nil)))) - (t (throw 'endwhile t))))) - (if (looking-at "[ \t]*->") - (throw 'exit (setq pos (match-beginning 0))) - (throw 'exit nil)))) - (goto-char pos) - nil))) - -(defun idlwave-last-valid-char () - "Return the last character before point which is not white or a comment -and also not part of the current identifier. Since we do this in -order to identify places where keywords are, we consider the initial -`/' of a keyword as part of the identifier. -This function is not general, can only be used for completion stuff." - (catch 'exit - (save-excursion - ;; skip the current identifier - (skip-chars-backward "a-zA-Z0-9_$") - ;; also skip a leading slash which might be belong to the keyword - (if (eq (preceding-char) ?/) - (backward-char 1)) - ;; FIXME: does not check if this is a valid identifier - (while t - (skip-chars-backward " \t") - (cond - ((memq (preceding-char) '(?\; ?\$)) (throw 'exit nil)) - ((eq (preceding-char) ?\n) - (beginning-of-line 0) - (if (looking-at "\\([^\n]*\\)\\$[ \t]*\\(;[^\n]*\\)?\n") - ;; continuation line - (goto-char (match-end 1)) - (throw 'exit nil))) - (t (throw 'exit (preceding-char)))))))) - -(defvar idlwave--complete-after-success-function #'ignore - "A function to evaluate after successful completion.") -(defvar idlwave--complete-after-success-force-function #'ignore - "A function to evaluate after completion selection in *Completions* buffer.") -(defconst idlwave-completion-mark (make-marker) - "A mark pointing to the beginning of the completion string.") - -(defun idlwave-complete-in-buffer (type stype list selector prompt isa - &optional prepare-display-function - special-selector) - "Perform TYPE completion of word before point against LIST. -SELECTOR is the PREDICATE argument for the completion function. Show -PROMPT in echo area. TYPE is one of the intern types, e.g., `function', -`procedure', `class-tag', `keyword', `sysvar'. SPECIAL-SELECTOR is -used only once, for `all-completions', and can be used to, e.g., -accumulate information on matching completions." - (let* ((completion-ignore-case t) - beg (end (point)) slash part spart completion all-completions - dpart dcompletion) - - (unless list - (error (concat prompt ": No completions available"))) - - ;; What is already in the buffer? - (save-excursion - (skip-chars-backward "a-zA-Z0-9_$") - (setq slash (eq (preceding-char) ?/) - beg (point) - idlwave--complete-after-success-function - (lambda () (idlwave-after-successful-completion - type slash beg)) - idlwave--complete-after-success-force-function - (lambda () (idlwave-after-successful-completion - type slash 'force)))) - - ;; Try a completion - (setq part (buffer-substring beg end) - dpart (downcase part) - spart (idlwave-sintern stype part) - completion (try-completion part list selector) - dcompletion (if (stringp completion) (downcase completion)) - idlwave-completion-help-links nil) - (cond - ((null completion) - ;; nothing available. - (error (concat prompt ": no completion for \"%s\"") part)) - ((and (not (equal dpart dcompletion)) - (not (eq t completion))) - ;; We can add something - (delete-region beg end) - (insert (if (and (string= part dpart) - (or (not (string= part "")) - idlwave-complete-empty-string-as-lower-case) - (not idlwave-completion-force-default-case)) - dcompletion - completion)) - (if (eq t (try-completion completion list selector)) - ;; Now this is a unique match - (idlwave-after-successful-completion type slash beg)) - t) - ((or (eq completion t) - (and (= 1 (length (setq all-completions - (idlwave-uniquify - (all-completions part list - (or special-selector - selector)))))) - (equal dpart dcompletion))) - ;; This is already complete - (idlwave-after-successful-completion type slash beg) - (message "%s is already the complete %s" part isa) - nil) - (t - ;; We cannot add something - offer a list. - (message "Making completion list...") - - (unless idlwave-completion-help-links ; already set somewhere? - (mapc (lambda (x) ; Pass link prop through to highlight-linked - (let ((link (get-text-property 0 'link (car x)))) - (if link - (push (cons (car x) link) - idlwave-completion-help-links)))) - list)) - (let* ((list all-completions) - ;; "complete" means, this is already a valid completion - (complete (memq spart all-completions))) - (setq list (sort list (lambda (a b) - (string< (downcase a) (downcase b))))) - (if prepare-display-function - (setq list (funcall prepare-display-function list))) - (if (and (string= part dpart) - (or (not (string= part "")) - idlwave-complete-empty-string-as-lower-case) - (not idlwave-completion-force-default-case)) - (setq list (mapcar (lambda (x) - (if (listp x) - (setcar x (downcase (car x))) - (setq x (downcase x))) - x) - list))) - (idlwave-display-completion-list list prompt beg complete)) - t)))) - -(defun idlwave-complete-class () - "Complete a class at point." - (interactive) - ;; Call `idlwave-routines' to make sure the class list will be available - (idlwave-routines) - ;; Check for the special case of completing empty string after pro/function - (if (let ((case-fold-search t)) - (save-excursion - (and - (re-search-backward "\\<\\(pro\\|function\\)[ \t]+\\=" - (- (point) 15) t) - (goto-char (point-min)) - (re-search-forward - "^[ \t]*\\(pro\\|function\\)[ \t]+\\([a-zA-Z0-9_]+::\\)" nil t)))) - ;; Yank the full class specification - (insert (match-string 2)) - ;; Do the completion, using list gathered from `idlwave-routines' - (idlwave-complete-in-buffer - 'class 'class (idlwave-class-alist) nil - "Select a class" "class" - (lambda (list) ;; Push it to help-links if system help available - (mapcar (lambda (x) - (let* ((entry (idlwave-class-info x)) - (link (nth 1 (assq 'link entry)))) - (if link (push (cons x link) - idlwave-completion-help-links)) - x)) - list))))) - -(defun idlwave-attach-classes (list type show-classes) - ;; Attach the proper class list to a LIST of completion items. - ;; TYPE, when 'kwd, shows classes for method keywords, when - ;; 'class-tag, for class tags, and otherwise for methods. - ;; SHOW-CLASSES is the value of `idlwave-completion-show-classes'. - (if (or (null show-classes) ; don't want to see classes - (null idlwave--class-selector) ; not a method call - (and - (stringp idlwave--class-selector) ; the class is already known - (not idlwave--super-classes))) ; no possibilities for inheritance - ;; In these cases, we do not have to do anything - list - (let* ((do-prop (>= show-classes 0)) - (do-buf (not (= show-classes 0))) - ;; (do-dots t) - (inherit (if (and (not (eq type 'class-tag)) idlwave--super-classes) - (cons idlwave--class-selector idlwave--super-classes))) - (max (abs show-classes)) - (lmax ;; (if do-dots - (apply #'max (mapcar #'length list))) ;;) - classes nclasses class-info space) - (mapcar - (lambda (x) - ;; get the classes - (if (eq type 'class-tag) - ;; Just one class for tags - (setq classes - (list - (idlwave-class-or-superclass-with-tag - idlwave--class-selector x))) - ;; Multiple classes for method or method-keyword - (setq classes - (if (eq type 'kwd) - (idlwave-all-method-keyword-classes - idlwave--method-selector x idlwave--type-selector) - (idlwave-all-method-classes x idlwave--type-selector))) - (if inherit - (setq classes - (delq nil - (mapcar (lambda (x) (if (memq x inherit) x nil)) - classes))))) - (setq nclasses (length classes)) - ;; Make the separator between item and class-info - ;; (if do-dots - (setq space (concat " " (make-string (- lmax (length x)) ?.))) - ;; (setq space " ")) - (if do-buf - ;; We do want info in the buffer - (if (<= nclasses max) - (setq class-info (concat - space - "<" (mapconcat #'identity classes ",") ">")) - (setq class-info (format "%s<%d classes>" space nclasses))) - (setq class-info nil)) - (when do-prop - ;; We do want properties - (setq x (copy-sequence x)) - (put-text-property 0 (length x) - 'help-echo (mapconcat #'identity classes " ") - x)) - (if class-info - (list x class-info) - x)) - list)))) - -(defun idlwave-attach-method-classes (list) - ;; Call idlwave-attach-classes with method parameters - (idlwave-attach-classes list 'method idlwave-completion-show-classes)) -(defun idlwave-attach-keyword-classes (list) - ;; Call idlwave-attach-classes with keyword parameters - (idlwave-attach-classes list 'kwd idlwave-completion-show-classes)) -(defun idlwave-attach-class-tag-classes (list) - ;; Call idlwave-attach-classes with class structure tags - (idlwave-attach-classes list 'class-tag idlwave-completion-show-classes)) - - -;;---------------------------------------------------------------------- -;;---------------------------------------------------------------------- -;;---------------------------------------------------------------------- -;;---------------------------------------------------------------------- -;;---------------------------------------------------------------------- - -(defun idlwave-popup-select (ev list title &optional sort) - "Select an item in LIST with a popup menu. -TITLE is the title to put atop the popup. If SORT is non-nil, -sort the list before displaying." - (let ((maxpopup idlwave-max-popup-menu-items) - rtn menu) - (cond ((null list)) - ((= 1 (length list)) - (setq rtn (car list))) - (t - (if sort (setq list (sort list (lambda (a b) - (string< (upcase a) (upcase b)))))) - (setq menu (cons title - (list - (append (list "") - (mapcar (lambda(x) (cons x x)) list))))) - (setq menu (idlwave-split-menu menu maxpopup)) - (setq rtn (x-popup-menu ev menu)))) - rtn)) - -(define-obsolete-function-alias 'idlwave-split-menu-emacs - #'idlwave-split-menu "28.1") - -(defun idlwave-split-menu (menu N) - "Split the MENU into submenus of maximum length N." - (if (<= (length (nth 1 menu)) (1+ N)) - ;; No splitting needed - menu - (let* ((title (car menu)) - (entries (cdr (nth 1 menu))) - (menu nil) - (cnt 0) - (nextmenu nil)) - (while entries - (while (and entries (< cnt N)) - (setq cnt (1+ cnt) - nextmenu (cons (car entries) nextmenu) - entries (cdr entries))) - (setq nextmenu (nreverse nextmenu)) - (prin1 nextmenu) - (setq nextmenu (cons (format "%s...%s" - (car (car nextmenu)) - (car (nth (1- cnt) nextmenu))) - nextmenu)) - (setq menu (cons nextmenu menu) - nextmenu nil - cnt 0)) - (setq menu (nreverse menu)) - (setq menu (cons title menu)) - menu))) - -(defvar idlwave-completion-setup-hook nil) - -(defun idlwave-scroll-completions (&optional message) - "Scroll the completion window on this frame." - (let ((cwin (get-buffer-window "*Completions*" 'visible)) - (win (selected-window))) - (unwind-protect - (progn - (select-window cwin) - (condition-case nil - (scroll-up) - (error (if (and (listp last-command) - (nth 2 last-command)) - (progn - (select-window win) - (funcall idlwave--complete-after-success-function)) - (set-window-start cwin (point-min))))) - (and message (message "%s" message))) - (select-window win)))) - -(defun idlwave-display-completion-list (list &optional message beg complete) - "Display the completions in LIST in the completions buffer and echo MESSAGE." - (unless (and (get-buffer-window "*Completions*") - (idlwave-local-value 'idlwave-completion-p "*Completions*")) - (move-marker idlwave-completion-mark beg) - (setq idlwave-before-completion-wconf (current-window-configuration))) - - (idlwave-display-completion-list-1 list) - - ;; Store a special value in `this-command'. When `idlwave-complete' - ;; finds this in `last-command', it will scroll the *Completions* buffer. - (setq this-command (list 'idlwave-display-completion-list message complete)) - - ;; Mark the completions buffer as created by cib - (idlwave-set-local 'idlwave-completion-p t "*Completions*") - - ;; Fontify the classes - (if (and idlwave-completion-fontify-classes - (consp (car list))) - (idlwave-completion-fontify-classes)) - - ;; Run the hook - (run-hooks 'idlwave-completion-setup-hook) - - ;; Display the message - (message "%s" (or message "Making completion list...done"))) - -(defun idlwave-choose (function &rest args) - "Call FUNCTION as a completion chooser and pass ARGS to it." - (let ((completion-ignore-case t)) ; install correct value - (apply function args)) - (if (and (derived-mode-p 'idlwave-shell-mode) - (not font-lock-mode)) - ;; For the shell, remove the fontification of the word before point - (let ((beg (save-excursion - (skip-chars-backward "a-zA-Z0-9_") - (point)))) - (remove-text-properties beg (point) '(face nil)))) - (funcall idlwave--complete-after-success-force-function)) - -(defun idlwave-keyboard-quit () - (interactive) - (unwind-protect - (if (eq (car-safe last-command) 'idlwave-display-completion-list) - (idlwave-restore-wconf-after-completion)) - (keyboard-quit))) - -(defun idlwave-restore-wconf-after-completion () - "Restore the old (before completion) window configuration." - (and idlwave-completion-restore-window-configuration - idlwave-before-completion-wconf - (set-window-configuration idlwave-before-completion-wconf))) - -(defun idlwave-one-key-select (sym prompt delay) - "Make the user select an element from the alist in the variable SYM. -The keys of the alist are expected to be strings. The function returns the -car of the selected association. -To do this, PROMPT is displayed and the user must hit a letter key to -select an entry. If the user does not reply within DELAY seconds, a help -window with the options is displayed automatically. -The key which is associated with each option is generated automatically. -First, the strings are checked for preselected keys, like in \"[P]rint\". -If these don't exist, a letter in the string is automatically selected." - (let* ((alist (symbol-value sym)) - (temp-buffer-show-hook '(fit-window-to-buffer)) - keys-alist char) - ;; First check the cache - (if (and (eq (symbol-value sym) (get sym :one-key-alist-last))) - (setq keys-alist (get sym :one-key-alist-cache)) - ;; Need to make new list - (setq keys-alist (idlwave-make-one-key-alist alist)) - (put sym :one-key-alist-cache keys-alist) - (put sym :one-key-alist-last alist)) - ;; Display prompt and wait for quick reply - (message "%s[%s]" prompt - (mapconcat (lambda(x) (char-to-string (car x))) - keys-alist)) - (if (sit-for delay) - ;; No quick reply: Show help - (save-window-excursion - (with-output-to-temp-buffer "*Completions*" - (dolist (x keys-alist) - (princ (nth 1 x)) - (princ "\n"))) - (setq char (read-char))) - (setq char (read-char))) - (message nil) - ;; Return the selected result - (nth 2 (assoc char keys-alist)))) - -;; Used for, e.g., electric debug super-examine. -(defun idlwave-make-one-key-alist (alist) - "Make an alist for single key selection." - (let ((l alist) keys-alist name start char help - (cnt 0) - (case-fold-search nil)) - (while l - (setq name (car (car l)) - l (cdr l)) - (catch 'exit - ;; First check if the configuration predetermined a key - (if (string-match "\\[\\(.\\)\\]" name) - (progn - (setq char (string-to-char (downcase (match-string 1 name))) - help (format "%c: %s" char name) - keys-alist (cons (list char help name) keys-alist)) - (throw 'exit t))) - ;; Then check for capital letters - (setq start 0) - (while (string-match "[A-Z]" name start) - (setq start (match-end 0) - char (string-to-char (downcase (match-string 0 name)))) - (if (not (assoc char keys-alist)) - (progn - (setq help (format "%c: %s" char - (replace-match - (concat "[" (match-string 0 name) "]") - t t name)) - keys-alist (cons (list char help name) keys-alist)) - (throw 'exit t)))) - ;; Now check for lowercase letters - (setq start 0) - (while (string-match "[a-z]" name start) - (setq start (match-end 0) - char (string-to-char (match-string 0 name))) - (if (not (assoc char keys-alist)) - (progn - (setq help (format "%c: %s" char - (replace-match - (concat "[" (match-string 0 name) "]") - t t name)) - keys-alist (cons (list char help name) keys-alist)) - (throw 'exit t)))) - ;; Bummer, nothing found! Use a stupid number - (setq char (string-to-char (int-to-string (setq cnt (1+ cnt)))) - help (format "%c: %s" char name) - keys-alist (cons (list char help name) keys-alist)))) - (nreverse keys-alist))) - -(defun idlwave-set-local (var value &optional buffer) - "Set the buffer-local value of VAR in BUFFER to VALUE." - (with-current-buffer (or buffer (current-buffer)) - (set (make-local-variable var) value))) - -(defun idlwave-local-value (var &optional buffer) - "Return the value of VAR in BUFFER, but only if VAR is local to BUFFER." - (when (local-variable-p var buffer) - (buffer-local-value var (or buffer (current-buffer))))) - -(defvar idlwave-completion-map nil - "Keymap for `completion-list-mode' with `idlwave-complete'.") - -;; (defun idlwave-default-choose-completion (&rest args) -;; "Execute `default-choose-completion' and then restore the win-conf." -;; (apply #'idlwave-choose #'default-choose-completion args)) - -(define-obsolete-function-alias 'idlwave-display-completion-list-emacs - #'idlwave-display-completion-list-1 "28.1") - -(defun idlwave-display-completion-list-1 (list) - "Display completion list and install the choose wrappers." - (with-output-to-temp-buffer "*Completions*" - (display-completion-list list)) - (with-current-buffer "*Completions*" - (use-local-map - (or idlwave-completion-map - (setq idlwave-completion-map - (idlwave-make-modified-completion-map (current-local-map))))))) - -(define-obsolete-function-alias 'idlwave-make-modified-completion-map-emacs - #'idlwave-make-modified-completion-map "28.1") - -(defun idlwave-make-modified-completion-map (old-map) - "Replace `choose-completion' in OLD-MAP." - (let ((new-map (copy-keymap old-map))) - (substitute-key-definition - #'choose-completion #'idlwave-choose-completion new-map) - (define-key new-map [mouse-3] #'idlwave-mouse-completion-help) - new-map)) - -(defun idlwave-choose-completion (&rest args) - "Choose the completion that point is in or next to." - (interactive (list last-nonmenu-event)) - (apply #'idlwave-choose #'choose-completion args)) - -(define-obsolete-function-alias 'idlwave-mouse-choose-completion - #'idlwave-choose-completion "28.1") - -;;---------------------------------------------------------------------- -;;---------------------------------------------------------------------- - -;;; ------------------------------------------------------------------------ -;;; Structure parsing code, and code to manage class info - -;; -;; - Go again over the documentation how to write a completion -;; plugin. It is in self.el, but currently still very bad. -;; This could be in a separate file in the distribution, or -;; in an appendix for the manual. - -(defvar idlwave-struct-skip - "[ \t]*\\(\\$.*\n\\(^[ \t]*\\(\\$[ \t]*\\)?\\(;.*\\)?\n\\)*\\)?[ \t]*" - "Regexp for skipping continued blank or comment-only lines in structures.") - -(defvar idlwave-struct-tag-regexp - (concat "[{,]" ;leading comma/brace - idlwave-struct-skip ; 4 groups - "\\([a-zA-Z][a-zA-Z0-9_]*\\)" ;the tag itself, group 5 - "[ \t]*:") ; the final colon - "Regexp for structure tags.") - -(defun idlwave-struct-tags () - "Return a list of all tags in the structure defined at point. -Point is expected just before the opening `{' of the struct definition." - (save-excursion - (let* ((borders (idlwave-struct-borders)) - (beg (car borders)) - (end (cdr borders)) - tags) - (goto-char beg) - (save-restriction - (narrow-to-region beg end) - (while (re-search-forward idlwave-struct-tag-regexp end t) - ;; Check if we are still on the top level of the structure. - (if (and (condition-case nil (progn (up-list -1) t) (error nil)) - (= (point) beg)) - (push (match-string-no-properties 5) tags)) - (goto-char (match-end 0)))) - (nreverse tags)))) - -(defun idlwave-find-struct-tag (tag) - "Find a given TAG in the structure defined at point." - (let* ((borders (idlwave-struct-borders)) - (end (cdr borders)) - (case-fold-search t)) - (re-search-forward (concat "\\(^[ \t]*\\|[,{][ \t]*\\)" tag "[ \t]*:") - end t))) - -(defun idlwave-struct-inherits () - "Return a list of all `inherits' names in the struct at point. -Point is expected just before the opening `{' of the struct definition." - (save-excursion - (let* ((borders (idlwave-struct-borders)) - (beg (car borders)) - (end (cdr borders)) - (case-fold-search t) - names) - (goto-char beg) - (save-restriction - (narrow-to-region beg end) - (while (re-search-forward - (concat "[{,]" ;leading comma/brace - idlwave-struct-skip ; 4 groups - "inherits" ; The INHERITS tag - idlwave-struct-skip ; 4 more - "\\([a-zA-Z][a-zA-Z0-9_]*\\)") ; The super-group, #9 - end t) - ;; Check if we are still on the top level of the structure. - (if (and (condition-case nil (progn (up-list -1) t) (error nil)) - (= (point) beg)) - (push (match-string-no-properties 9) names)) - (goto-char (match-end 0)))) - (nreverse names)))) - -(defun idlwave-in-structure () - "Return t if point is inside an IDL structure definition." - (let ((beg (point))) - (save-excursion - (if (not (or (idlwave-in-comment) (idlwave-in-quote))) - (if (idlwave-find-structure-definition nil nil 'back) - (let ((borders (idlwave-struct-borders))) - (or (= (car borders) (cdr borders)) ;; struct not yet closed... - (and (> beg (car borders)) (< beg (cdr borders)))))))))) - -(defun idlwave-struct-borders () - "Return the borders of the {...} after point as a cons cell." - (let (beg) - (save-excursion - (skip-chars-forward "^{") - (setq beg (point)) - (condition-case nil (forward-list 1) - (error (goto-char beg))) - (cons beg (point))))) - -(defun idlwave-find-structure-definition (&optional var name bound) - "Search forward for a structure definition. -If VAR is non-nil, search for a structure assigned to variable VAR. -If NAME is non-nil, search for a named structure NAME, if a string, -or a generic named structure otherwise. If BOUND is an integer, limit -the search. If BOUND is the symbol `all', we search first back and -then forward through the entire file. If BOUND is the symbol `back' -we search only backward." - (let* ((ws "[ \t]*\\(\\$.*\n[ \t]*\\)*") - (case-fold-search t) - (lim (if (integerp bound) bound nil)) - (re (concat - (if var - (concat "\\<" (regexp-quote (downcase var)) "\\>" ws) - "\\(\\)") - "=" ws "\\({\\)" - (if name - (if (stringp name) - (concat ws "\\(\\<" (downcase name) "\\)[^a-zA-Z0-9_$]") - ;; Just a generic name - (concat ws "\\<\\([a-zA-Z_0-9$]+\\)" ws ",")) - "")))) - (if (or (and (or (eq bound 'all) (eq bound 'back)) - (re-search-backward re nil t)) - (and (not (eq bound 'back)) (re-search-forward re lim t))) - (progn - (goto-char (match-beginning 3)) - (match-string-no-properties 5))))) - -(defvar idlwave-class-info nil) -(defvar idlwave-class-reset nil) ; to reset buffer-local classes - -(add-hook 'idlwave-update-rinfo-hook - (lambda () (setq idlwave-class-reset t))) -(add-hook 'idlwave-after-load-rinfo-hook - (lambda () (setq idlwave-class-info nil))) - -(defun idlwave-class-info (class) - (let (list entry) - (if idlwave-class-info - (if idlwave-class-reset - (setq - idlwave-class-reset nil - idlwave-class-info ; Remove any visited in a buffer - (delq nil (mapcar - (lambda (x) - (let ((filebuf - (idlwave-class-file-or-buffer - (or (cdr (assq 'found-in x)) (car x))))) - (if (cdr filebuf) - nil - x))) - idlwave-class-info)))) - ;; Info is nil, put in the system stuff to start. - (setq idlwave-class-info idlwave-system-class-info) - (setq list idlwave-class-info) - (while (setq entry (pop list)) - (idlwave-sintern-class-info entry))) - (setq class (idlwave-sintern-class class)) - (or (assq class idlwave-class-info) - (progn (idlwave-scan-class-info class) - (assq class idlwave-class-info))))) - -(defun idlwave-sintern-class-info (entry) - "Sintern the class names in a class-info entry." - (let ((inherits (assq 'inherits entry))) - (setcar entry (idlwave-sintern-class (car entry) 'set)) - (if inherits - (setcdr inherits (mapcar (lambda (x) (idlwave-sintern-class x 'set)) - (cdr inherits)))))) - -(defun idlwave-find-class-definition (class &optional all-hook alt-class) - "Find class structure definition(s). -If ALL-HOOK is set, find all named structure definitions in a given -class__define routine, on which ALL-HOOK will be run. If ALT-CLASS is -set, look for the name__define pro, and inside of it, for the ALT-CLASS -class/struct definition." - (let ((case-fold-search t) end-lim name) - (when (re-search-forward - (concat "^[ \t]*pro[ \t]+" (downcase class) "__define" "\\>") nil t) - (if all-hook - (progn - ;; For everything there - (setq end-lim (save-excursion (idlwave-end-of-subprogram) (point))) - (while (setq name - (idlwave-find-structure-definition nil t end-lim)) - (funcall all-hook name))) - (idlwave-find-structure-definition nil (or alt-class class)))))) - - -(defun idlwave-class-file-or-buffer (class) - "Find buffer visiting CLASS definition." - (let* ((pro (concat (downcase class) "__define")) - (file (idlwave-routine-source-file - (nth 3 (idlwave-rinfo-assoc pro 'pro nil - (idlwave-routines)))))) - (cons file (if file (find-buffer-visiting file))))) - - -(defun idlwave-scan-class-info (class) - "Scan all class and named structure info in the class__define pro." - (let* ((idlwave-auto-routine-info-updates nil) - (filebuf (idlwave-class-file-or-buffer class)) - (file (car filebuf)) - (buf (cdr filebuf)) - (class (idlwave-sintern-class class))) - (if (or - (not file) - (and ;; neither a regular file nor a visited buffer - (not buf) - (not (file-regular-p file)))) - nil ; Cannot find the file/buffer to get any info - (save-excursion - (if buf (set-buffer buf) - ;; Read the file in temporarily - (set-buffer (get-buffer-create " *IDLWAVE-tmp*")) - (erase-buffer) - (unless (derived-mode-p 'idlwave-mode) - (idlwave-mode)) - (insert-file-contents file)) - (save-excursion - (goto-char 1) - (idlwave-find-class-definition class - ;; Scan all of the structures found there - (lambda (name) - (let* ((this-class (idlwave-sintern-class name)) - (entry - (list this-class - (cons 'tags (idlwave-struct-tags)) - (cons 'inherits (idlwave-struct-inherits))))) - (if (not (eq this-class class)) - (setq entry (nconc entry (list (cons 'found-in class))))) - (idlwave-sintern-class-info entry) - (push entry idlwave-class-info))))))))) - -(defun idlwave-class-found-in (class) - "Return the FOUND-IN property of the CLASS." - (cdr (assq 'found-in (idlwave-class-info class)))) -(defun idlwave-class-tags (class) - "Return the native tags in CLASS." - (cdr (assq 'tags (idlwave-class-info class)))) -(defun idlwave-class-inherits (class) - "Return the direct superclasses of CLASS." - (cdr (assq 'inherits (idlwave-class-info class)))) - - -(defun idlwave-all-class-tags (class) - "Return a list of native and inherited tags in CLASS." - (condition-case err - (apply #'append (mapcar #'idlwave-class-tags - (cons class (idlwave-all-class-inherits class)))) - (error - (idlwave-class-tag-reset) - (error "%s" (error-message-string err))))) - - -(defun idlwave-all-class-inherits (class) - "Return a list of all superclasses of CLASS (recursively expanded). -The list is cached in `idlwave-class-info' for faster access." - (cond - ((not idlwave-support-inheritance) nil) - ((eq class nil) nil) - ((eq class t) nil) - (t - (let ((info (idlwave-class-info class)) - entry) - (if (setq entry (assq 'all-inherits info)) - (cdr entry) - ;; Save the depth of inheritance scan to check for circular references - (let ((inherits (mapcar (lambda (x) (cons x 0)) - (idlwave-class-inherits class))) - rtn all-inherits cl) - (while inherits - (setq cl (pop inherits) - rtn (cons (car cl) rtn) - inherits (append (mapcar (lambda (x) - (cons x (1+ (cdr cl)))) - (idlwave-class-inherits (car cl))) - inherits)) - (if (> (cdr cl) 999) - (error - "Class scan: inheritance depth exceeded. Circular inheritance?"))) - (setq all-inherits (nreverse rtn)) - (nconc info (list (cons 'all-inherits all-inherits))) - all-inherits)))))) - -(defun idlwave-entry-keywords (entry &optional record-link) - "Return the flat entry keywords alist from routine-info entry. -If RECORD-LINK is non-nil, the keyword text is copied and a text -property indicating the link is added." - (let (kwds) - (mapc - (lambda (key-list) - (let ((file (car key-list))) - (mapcar (lambda (key-cons) - (let ((key (car key-cons)) - (link (cdr key-cons))) - (when (and record-link file) - (setq key (copy-sequence key)) - (put-text-property - 0 (length key) - 'link - (concat - file - (if link - (concat idlwave-html-link-sep - (number-to-string link)))) - key)) - (push (list key) kwds))) - (cdr key-list)))) - (nthcdr 5 entry)) - (nreverse kwds))) - -(defun idlwave-entry-find-keyword (entry keyword) - "Find keyword KEYWORD in entry ENTRY, and return (with link) if set." - (catch 'exit - (mapc - (lambda (key-list) - (let ((file (car key-list)) - (kwd (assoc keyword (cdr key-list)))) - (when kwd - (setq kwd (cons (car kwd) - (if (and file (cdr kwd)) - (concat file - idlwave-html-link-sep - (number-to-string (cdr kwd))) - (cdr kwd)))) - (throw 'exit kwd)))) - (nthcdr 5 entry)))) - -;;========================================================================== -;; -;; Completing class structure tags. This is a completion plugin. -;; The necessary taglist is constructed dynamically - -(defvar idlwave-current-tags-class nil) -(defvar idlwave-current-class-tags nil) -(defvar idlwave-current-native-class-tags nil) -(defvar idlwave-sint-class-tags nil) -(idlwave-new-sintern-type class-tag) -(add-hook 'idlwave-complete-functions #'idlwave-complete-class-structure-tag) -(add-hook 'idlwave-update-rinfo-hook #'idlwave-class-tag-reset) - -(defun idlwave-complete-class-structure-tag () - "Complete a structure tag on a `self' argument in an object method." - (interactive) - (let ((pos (point)) - (case-fold-search t)) - (if (save-excursion - ;; Check if the context is right - (skip-chars-backward "a-zA-Z0-9._$") - (and (< (point) (- pos 4)) - (looking-at "self\\."))) - (let* ((idlwave--class-selector (nth 2 (idlwave-current-routine))) - (idlwave--super-classes (idlwave-all-class-inherits - idlwave--class-selector))) - ;; Check if we are in a class routine - (unless idlwave--class-selector - (error "Not in a method procedure or function")) - ;; Check if we need to update the "current" class - (if (not (equal idlwave--class-selector idlwave-current-tags-class)) - (idlwave-prepare-class-tag-completion idlwave--class-selector)) - (setq idlwave-completion-help-info - (list 'idlwave-complete-class-structure-tag-help - (idlwave-sintern-routine - (concat idlwave--class-selector "__define")) - nil)) - ;; FIXME: idlwave-cpl-bold doesn't seem used anywhere. - (let ((_idlwave-cpl-bold idlwave-current-native-class-tags)) - (idlwave-complete-in-buffer - 'class-tag 'class-tag - idlwave-current-class-tags nil - (format "Select a tag of class %s" idlwave--class-selector) - "class tag" - 'idlwave-attach-class-tag-classes)) - t) ; return t to skip other completions - nil))) - -(defun idlwave-class-tag-reset () - (setq idlwave-current-tags-class nil)) - -(defun idlwave-prepare-class-tag-completion (class) - "Find and parse the necessary class definitions for class structure tags." - (setq idlwave-sint-class-tags nil) - (setq idlwave-current-tags-class class) - (setq idlwave-current-class-tags - (mapcar (lambda (x) - (list (idlwave-sintern-class-tag x 'set))) - (idlwave-all-class-tags class))) - (setq idlwave-current-native-class-tags - (mapcar #'downcase (idlwave-class-tags class)))) - -;=========================================================================== -;; -;; Completing system variables and their structure fields -;; This is also a plugin. - -(defvar idlwave-sint-sysvars nil) -(defvar idlwave-sint-sysvartags nil) -(idlwave-new-sintern-type sysvar) -(idlwave-new-sintern-type sysvartag) -(add-hook 'idlwave-complete-functions #'idlwave-complete-sysvar-or-tag) -(add-hook 'idlwave-update-rinfo-hook #'idlwave-sysvars-reset) -(add-hook 'idlwave-after-load-rinfo-hook #'idlwave-sintern-sysvar-alist) - - -(defun idlwave-complete-sysvar-or-tag () - "Complete a system variable." - (interactive) - (let ((pos (point)) - (case-fold-search t)) - (cond ((save-excursion - ;; Check if the context is right for system variable - (skip-chars-backward "a-zA-Z0-9_$") - (equal (char-before) ?!)) - (setq idlwave-completion-help-info '(idlwave-complete-sysvar-help)) - (idlwave-complete-in-buffer 'sysvar 'sysvar - idlwave-system-variables-alist nil - "Select a system variable" - "system variable") - t) ; return t to skip other completions - ((save-excursion - ;; Check if the context is right for sysvar tag - (skip-chars-backward "a-zA-Z0-9_$.") - (and (equal (char-before) ?!) - (looking-at "\\([a-zA-Z][a-zA-Z0-9_$]*\\)\\.") - (<= (match-end 0) pos))) - ;; Complete a system variable tag - (let* ((var (idlwave-sintern-sysvar (match-string 1))) - (entry (assq var idlwave-system-variables-alist)) - (tags (cdr (assq 'tags entry)))) - (or entry (error "!%s is not a known system variable" var)) - (or tags (error "System variable !%s is not a structure" var)) - (setq idlwave-completion-help-info - (list 'idlwave-complete-sysvar-tag-help var)) - (idlwave-complete-in-buffer 'sysvartag 'sysvartag - tags nil - "Select a system variable tag" - "system variable tag") - t)) ; return t to skip other completions - (t nil)))) - -(defvar idlw-help-link) ;dynamic variables set by help callback -(defun idlwave-complete-sysvar-help (mode word) - (let ((word (or (nth 1 idlwave-completion-help-info) word)) - (entry (assoc word idlwave-system-variables-alist))) - (cond - ((eq mode 'test) - (and (stringp word) entry (nth 1 (assq 'link entry)))) - ((eq mode 'set) - ;; Setting dynamic!!! - (if entry (setq idlw-help-link (nth 1 (assq 'link entry))))) - (t (error "This should not happen"))))) - -(defun idlwave-complete-sysvar-tag-help (mode word) - (let* ((var (nth 1 idlwave-completion-help-info)) - (entry (assoc var idlwave-system-variables-alist)) - (tags (cdr (assq 'tags entry))) - (main (nth 1 (assq 'link entry))) - target) - (cond - ((eq mode 'test) ; we can at least link the main - (and (stringp word) entry main)) - ((eq mode 'set) - (if entry - (setq idlw-help-link - (if (setq target (cdr (assoc-string word tags t))) - (idlwave-substitute-link-target main target) - main)))) ;; setting dynamic!!! - (t (error "This should not happen"))))) - -(defun idlwave-split-link-target (link) - "Split a given LINK into link file and anchor." - (if (string-match idlwave-html-link-sep link) - (cons (substring link 0 (match-beginning 0)) - (string-to-number (substring link (match-end 0)))))) - -(defun idlwave-substitute-link-target (link target) - "Substitute the TARGET anchor for the given LINK." - (let (main-base) - (setq main-base (if (string-match "#" link) - (substring link 0 (match-beginning 0)) - link)) - (if target - (concat main-base idlwave-html-link-sep (number-to-string target)) - link))) - -;; Fake help in the source buffer for class structure tags. -;; IDLW-HELP-LINK AND IDLW-HELP-NAME ARE GLOBAL-VARIABLES HERE. -;; (from idlwave-do-mouse-completion-help) -(defvar idlw-help-name) -(defvar idlw-help-link) -(defvar idlwave-help-do-class-struct-tag nil) -(defun idlwave-complete-class-structure-tag-help (mode word) - (cond - ((eq mode 'test) ; nothing gets fontified for class tags - nil) - ((eq mode 'set) - (let (class-with found-in) - (when (setq class-with - (idlwave-class-or-superclass-with-tag - idlwave-current-tags-class - word)) - (if (assq (idlwave-sintern-class class-with) - idlwave-system-class-info) - (error "No help available for system class tags")) - (if (setq found-in (idlwave-class-found-in class-with)) - (setq idlw-help-name (cons (concat found-in "__define") class-with)) - (setq idlw-help-name (concat class-with "__define"))))) - (setq idlw-help-link word - idlwave-help-do-class-struct-tag t)) - (t (error "This should not happen")))) - -(defun idlwave-class-or-superclass-with-tag (class tag) - "Find and return the CLASS or one of its superclass with the -associated TAG, if any." - (let ((sclasses (cons class (idlwave-all-class-inherits class))) - cl) - (catch 'exit - (while sclasses - (setq cl (pop sclasses)) - (let ((tags (idlwave-class-tags cl))) - (while tags - (if (string-equal-ignore-case tag (car tags)) - (throw 'exit cl)) - (setq tags (cdr tags)))))))) - - -(defun idlwave-sysvars-reset () - (if (and (fboundp 'idlwave-shell-is-running) - (idlwave-shell-is-running) - idlwave-idlwave_routine_info-compiled) - (idlwave-shell-send-command "idlwave_get_sysvars" - 'idlwave-process-sysvars 'hide))) - -(defun idlwave-process-sysvars () - (idlwave-shell-filter-sysvars) - (setq idlwave-sint-sysvars nil - idlwave-sint-sysvartags nil) - (idlwave-sintern-sysvar-alist)) - -(defun idlwave-sintern-sysvar-alist () - (let ((list idlwave-system-variables-alist) entry tags) - (while (setq entry (pop list)) - (setcar entry (idlwave-sintern-sysvar (car entry) 'set)) - (setq tags (assq 'tags entry)) - (if tags - (setcdr tags - (mapcar (lambda (x) - (cons (idlwave-sintern-sysvartag (car x) 'set) - (cdr x))) - (cdr tags))))))) - -(defvar idlwave-shell-command-output) -(defun idlwave-shell-filter-sysvars () - "Get any new system variables and tags." - (let ((text idlwave-shell-command-output) - (start 0) - (old idlwave-system-variables-alist) - var tags link old-entry) ;; type name class - (setq idlwave-system-variables-alist nil) - (while (string-match "^IDLWAVE-SYSVAR: !\\([a-zA-Z0-9_$]+\\)\\( \\(.*\\)\\)?" - text start) - (setq start (match-end 0) - var (match-string 1 text) - tags (if (match-end 3) - (idlwave-split-string (match-string 3 text)))) - ;; Maintain old links, if present - (setq old-entry (assq (idlwave-sintern-sysvar var) old)) - (setq link (assq 'link old-entry)) - (setq idlwave-system-variables-alist - (cons (list var - (cons - 'tags - (mapcar (lambda (x) - (cons x - (cdr (assq - (idlwave-sintern-sysvartag x) - (cdr (assq 'tags old-entry)))))) - tags)) - link) - idlwave-system-variables-alist))) - ;; Keep the old value if query was not successful - (setq idlwave-system-variables-alist - (or idlwave-system-variables-alist old)))) - -(defun idlwave-completion-fontify-classes () - "Goto the *Completions* buffer and fontify the class info." - (with-current-buffer "*Completions*" - (save-excursion - (goto-char (point-min)) - (let ((buffer-read-only nil)) - (while (re-search-forward "\\.*<[^>]+>" nil t) - (put-text-property (match-beginning 0) (match-end 0) - 'face 'font-lock-string-face)))))) - -(defun idlwave-after-successful-completion (type slash &optional verify) - "Add `=' or `(' after successful completion of keyword and function. -Restore the pre-completion window configuration if possible." - (cond - ((eq type 'procedure) - nil) - ((eq type 'function) - (cond - ((equal idlwave-function-completion-adds-paren nil) nil) - ((or (equal idlwave-function-completion-adds-paren t) - (equal idlwave-function-completion-adds-paren 1)) - (insert "(")) - ((equal idlwave-function-completion-adds-paren 2) - (insert "()") - (backward-char 1)) - (t nil))) - ((eq type 'keyword) - (if (and idlwave-keyword-completion-adds-equal - (not slash)) - (progn (insert "=") t) - nil))) - - ;; Restore the pre-completion window configuration if this is safe. - - (if (or (eq verify 'force) ; force - (and - (get-buffer-window "*Completions*") ; visible - (idlwave-local-value 'idlwave-completion-p - "*Completions*") ; cib-buffer - (eq (marker-buffer idlwave-completion-mark) - (current-buffer)) ; buffer OK - (equal (marker-position idlwave-completion-mark) - verify))) ; pos OK - (idlwave-restore-wconf-after-completion)) - (move-marker idlwave-completion-mark nil) - (setq idlwave-before-completion-wconf nil)) - -(defun idlwave-mouse-context-help (ev &optional arg) - "Call `idlwave-context-help' on the clicked location." - (interactive "eP") - (mouse-set-point ev) - (idlwave-context-help arg)) - -(defvar idlwave-last-context-help-pos nil) -(defun idlwave-context-help (&optional arg) - "Display IDL Online Help on context. -If point is on a keyword, help for that keyword will be shown. If -point is on a routine name or in the argument list of a routine, help -for that routine will be displayed. Works for system routines and -keywords, it pulls up text help. For other routines and keywords, -visits the source file, finding help in the header (if -`idlwave-help-source-try-header' is non-nil) or the routine definition -itself." - (interactive "P") - (idlwave-do-context-help arg)) - -(defun idlwave-mouse-completion-help (ev) - "Display online help about the completion at point." - (interactive "eP") - ;; Restore last-command for next command, to make - ;; scrolling/canceling of completions work. - (setq this-command last-command) - (idlwave-do-mouse-completion-help ev)) - -(defun idlwave-routine-info (&optional arg _external) - "Display a routines calling sequence and list of keywords. -When point is on the name a function or procedure, or in the argument -list of a function or procedure, this command displays a help buffer with -the information. When called with prefix arg, enforce class query. - -When point is on an object operator `->', display the class stored in -this arrow, if any (see `idlwave-store-inquired-class'). With a prefix -arg, the class property is cleared out." - - (interactive "P") - (idlwave-routines) - (if (string-search "->" (buffer-substring - (max (point-min) (1- (point))) - (min (+ 2 (point)) (point-max)))) - ;; Cursor is on an arrow - (if (get-text-property (point) 'idlwave-class) - ;; arrow has class property - (if arg - ;; Remove property - (save-excursion - (backward-char 1) - (when (looking-at ".?\\(->\\)") - (remove-text-properties (match-beginning 1) (match-end 1) - '(idlwave-class nil face nil)) - (message "Class property removed from arrow"))) - ;; Echo class property - (message "Arrow has text property identifying object to be class %s" - (get-text-property (point) 'idlwave-class))) - ;; No property found - (message "Arrow has no class text property")) - - ;; Not on an arrow... - (let* ((idlwave-query-class nil) - (idlwave-force-class-query (equal arg '(4))) - (module (idlwave-what-module))) - (if (car module) - (apply #'idlwave-display-calling-sequence - (idlwave-fix-module-if-obj_new module)) - (error "Don't know which calling sequence to show"))))) - -(defun idlwave-resolve (&optional arg) - "Call RESOLVE_ROUTINE on the module name at point. -Like `idlwave-routine-info', this looks for a routine call at point. -After confirmation in the minibuffer, it will use the shell to issue -a RESOLVE call for this routine, to attempt to make it defined and its -routine info available for IDLWAVE. If the routine is a method call, -both `class__method' and `class__define' will be tried. -With ARG, enforce query for the class of object methods." - (interactive "P") - (let* ((idlwave-query-class nil) - (idlwave-force-class-query (equal arg '(4))) - (module (idlwave-what-module)) - (name (idlwave-make-full-name (nth 2 module) (car module))) - (type (if (eq (nth 1 module) 'pro) "pro" "function")) - (resolve (read-string "Resolve: " (format "%s %s" type name))) - (kwd "") - class) - (if (string-match "\\(pro\\|function\\)[ \t]+\\(\\(.*\\)::\\)?\\(.*\\)" - resolve) - (setq type (match-string 1 resolve) - class (if (match-beginning 2) - (match-string 3 resolve) - nil) - name (match-string 4 resolve))) - (if (string= (downcase type) "function") - (setq kwd ",/is_function")) - - (cond - ((null class) - (idlwave-shell-send-command - (format "resolve_routine,'%s'%s" (downcase name) kwd) - 'idlwave-update-routine-info - nil t)) - (t - (idlwave-shell-send-command - (format "resolve_routine,'%s__define'%s" (downcase class) kwd) - (list 'idlwave-shell-send-command - (format "resolve_routine,'%s__%s'%s" - (downcase class) (downcase name) kwd) - '(idlwave-update-routine-info) - nil t)))))) - -(defun idlwave-find-module-this-file () - (interactive) - (idlwave-find-module '(4))) - -(defun idlwave-find-module (&optional arg) - "Find the source code of an IDL module. -Works for modules for which IDLWAVE has routine info available. -The function offers as default the module name `idlwave-routine-info' -would use. With ARG limit to this buffer. With two prefix ARG's -force class query for object methods." - (interactive "P") - (let* ((idlwave-query-class nil) - (idlwave-force-class-query (equal arg '(16))) - (this-buffer (equal arg '(4))) - (module (idlwave-fix-module-if-obj_new (idlwave-what-module))) - (default (if module - (concat (idlwave-make-full-name - (nth 2 module) (car module)) - (if (eq (nth 1 module) 'pro) "

" "")) - "none")) - (list - (idlwave-uniquify - (delq nil - (mapcar (lambda (x) - (if (eq 'system (car-safe (nth 3 x))) - ;; Take out system routines with no source. - nil - (list - (concat (idlwave-make-full-name - (nth 2 x) (car x)) - (if (eq (nth 1 x) 'pro) "

" ""))))) - (if this-buffer - (idlwave-save-buffer-update) - (idlwave-routines)))))) - (name (idlwave-completing-read - (if (or (not this-buffer) - (assoc default list)) - (format-prompt "Module" default) - "Module in this file: ") - list)) - type class) - (if (string-match "\\`\\s-*\\'" name) - ;; Nothing, use the default. - (setq name default)) - (if (string-match "<[fp]>" name) - (setq type (substring name -2 -1) - name (substring name 0 -3))) - (if (string-match "\\(.*\\)::\\(.*\\)" name) - (setq class (match-string 1 name) - name (match-string 2 name))) - (setq name (idlwave-sintern-routine-or-method name class) - class (idlwave-sintern-class class) - type (cond ((equal type "f") 'fun) - ((equal type "p") 'pro) - (t t))) - (idlwave-do-find-module name type class nil this-buffer))) - -(defun idlwave-do-find-module (name type class - &optional force-source this-buffer) - (let ((name1 (idlwave-make-full-name class name)) - source buf1 entry - (buf (current-buffer)) - (pos (point)) - file name2) - (setq entry (idlwave-best-rinfo-assq name type class (idlwave-routines) - 'WITH-FILE) - source (or force-source (nth 3 entry)) - name2 (if (nth 2 entry) - (idlwave-make-full-name (nth 2 entry) name) - name1)) - (if source - (setq file (idlwave-routine-source-file source))) - (unless file ; Try to find it on the path. - (setq file - (idlwave-expand-lib-file-name - (if class - (format "%s__define.pro" (downcase class)) - (format "%s.pro" (downcase name)))))) - (cond - ((or (null name) (equal name "")) - (error "Abort")) - ((eq (car source) 'system) - (error "Source code for system routine %s is not available" - name2)) - ((or (not file) (not (file-regular-p file))) - (error "Source code for routine %s is not available" - name2)) - (t - (when (not this-buffer) - (setq buf1 - (idlwave-find-file-noselect file 'find)) - (pop-to-buffer buf1 t)) - (goto-char (point-max)) - (let ((case-fold-search t)) - (if (re-search-backward - (concat "^[ \t]*\\<" - (cond ((eq type 'fun) "function") - ((eq type 'pro) "pro") - (t "\\(pro\\|function\\)")) - "\\>[ \t]+" - (regexp-quote (downcase name2)) - "[^a-zA-Z0-9_$]") - nil t) - (goto-char (match-beginning 0)) - (pop-to-buffer buf) - (goto-char pos) - (error "Could not find routine %s" name2))))))) - -(defun idlwave-what-module () - "Return a default module for stuff near point. -Used by `idlwave-routine-info' and `idlwave-find-module'." - (idlwave-routines) - (if (let ((case-fold-search t)) - (save-excursion - (idlwave-beginning-of-statement) - (looking-at "[ \t]*\\(pro\\|function\\)[ \t]+\\(\\([a-zA-Z0-9_$]+\\)::\\)?\\([a-zA-Z0-9$_]+\\)\\([, \t\n]\\|$\\)"))) - ;; This is a function or procedure definition statement - ;; We return the defined routine as module. - (list - (idlwave-sintern-routine-or-method (match-string-no-properties 4) - (match-string-no-properties 2)) - (if (equal (downcase (match-string 1)) "pro") 'pro 'fun) - (idlwave-sintern-class (match-string 3))) - - ;; Not a definition statement - analyze precise position. - (let* ((where (idlwave-where)) - (cw (nth 2 where)) - (pro (car (nth 0 where))) - (func (car (nth 1 where))) - (this-word (idlwave-this-word "a-zA-Z0-9$_")) - (next-char (save-excursion (skip-chars-forward "a-zA-Z0-9$_") - (following-char))) - ) - (cond - ((and (eq cw 'procedure) - (not (equal this-word ""))) - (setq this-word (idlwave-sintern-routine-or-method - this-word (nth 2 (nth 3 where)))) - (list this-word 'pro - (idlwave-determine-class - (cons this-word (cdr (nth 3 where))) - 'pro))) - ((and (eq cw 'function) - (not (equal this-word "")) - (or (eq next-char ?\() ; exclude arrays, vars. - (looking-at "[a-zA-Z0-9_]*[ \t]*("))) - (setq this-word (idlwave-sintern-routine-or-method - this-word (nth 2 (nth 3 where)))) - (list this-word 'fun - (idlwave-determine-class - (cons this-word (cdr (nth 3 where))) - 'fun))) - ((and (memq cw '(function-keyword procedure-keyword)) - (not (equal this-word "")) - (eq next-char ?\()) ; A function! - (setq this-word (idlwave-sintern-routine this-word)) - (list this-word 'fun nil)) - (func - (list func 'fun (idlwave-determine-class (nth 1 where) 'fun))) - (pro - (list pro 'pro (idlwave-determine-class (nth 0 where) 'pro))) - (t nil))))) - -(defun idlwave-what-module-find-class () - "Call `idlwave-what-module' and find the inherited class if necessary." - (let* ((module (idlwave-what-module)) - (class (nth 2 module))) - (if (and (= (length module) 3) - (stringp class)) - (list (car module) - (nth 1 module) - (apply #'idlwave-find-inherited-class module)) - module))) - -(defun idlwave-find-inherited-class (name type class) - "Find the class which defines TYPE NAME and is CLASS or inherited by CLASS." - (let ((entry (idlwave-best-rinfo-assoc name type class (idlwave-routines)))) - (if entry - (nth 2 entry) - class))) - -(defun idlwave-fix-module-if-obj_new (module) - "Check if MODULE points to obj_new. -If yes, and if the cursor is in the keyword region, change to the -appropriate Init method." - (let* ((name (car module)) - (pos (point)) - (case-fold-search t) - string) - (if (and (stringp name) - (equal (downcase name) "obj_new") - (save-excursion - (idlwave-beginning-of-statement) - (setq string (buffer-substring (point) pos)) - (string-match "obj_new([^'\"]*['\"]\\([a-zA-Z0-9_]+\\)" - string))) - (let (;; (name "Init") - (class (match-string 1 string))) - (setq module (list (idlwave-sintern-method "Init") - 'fun - (idlwave-sintern-class class))))) - module)) - -(defun idlwave-fix-keywords (name type class keywords - &optional super-classes system) - "Update a list of keywords. -Translate OBJ_NEW, adding all super-class keywords, or all keywords -from all classes if CLASS equals t. If SYSTEM is non-nil, don't -demand _EXTRA in the keyword list." - (let ((case-fold-search t) - (idlwave--super-classes super-classes)) - - ;; If this is the OBJ_NEW function, try to figure out the class and use - ;; the keywords from the corresponding INIT method. - (if (and (equal (upcase name) "OBJ_NEW") - (derived-mode-p '(idlwave-mode idlwave-shell-mode))) - (let* ((bos (save-excursion (idlwave-beginning-of-statement) (point))) - (string (buffer-substring bos (point))) - (case-fold-search t) - class) - (and (string-match "obj_new([^'\"]*['\"]\\([a-zA-Z0-9_]+\\)" - string) - (setq class (idlwave-sintern-class (match-string 1 string))) - (setq idlwave-current-obj_new-class class) - (setq keywords - (append keywords - (idlwave-entry-keywords - (idlwave-rinfo-assq - (idlwave-sintern-method "INIT") - 'fun - class - (idlwave-routines)) - 'do-link)))))) - - ;; If the class is t, combine all keywords of all methods NAME - (when (eq class t) - (mapc (lambda (entry) - (and - (nth 2 entry) ; non-nil class - (eq (nth 1 entry) type) ; correct type - (setq keywords - (append keywords - (idlwave-entry-keywords entry 'do-link))))) - (idlwave-all-assq name (idlwave-routines))) - (setq keywords (idlwave-uniquify keywords))) - - ;; If we have inheritance, add all keywords from superclasses, if - ;; the user indicated that method in `idlwave-keyword-class-inheritance' - (when (and - idlwave--super-classes - idlwave-keyword-class-inheritance - (stringp class) - (or - system - (assq (idlwave-sintern-keyword "_extra") keywords) - (assq (idlwave-sintern-keyword "_ref_extra") keywords)) - ;; Check if one of the keyword-class regexps matches the name - (let ((regexps idlwave-keyword-class-inheritance) re) - (catch 'exit - (while (setq re (pop regexps)) - (if (string-match re name) (throw 'exit t)))))) - - (cl-loop for entry in (idlwave-routines) do - (and (nth 2 entry) ; non-nil class - (memq (nth 2 entry) idlwave--super-classes) ;an inherited class - (eq (nth 1 entry) type) ; correct type - (eq (car entry) name) ; correct name - (mapc (lambda (k) (add-to-list 'keywords k)) - (idlwave-entry-keywords entry 'do-link)))) - (setq keywords (idlwave-uniquify keywords))) - - ;; Return the final list - keywords)) - -(defun idlwave-expand-keyword (keyword module) - "Expand KEYWORD to one of the valid keyword parameters of MODULE. -KEYWORD may be an exact match or an abbreviation of a keyword. -If the match is exact, KEYWORD itself is returned, even if there may be other -keywords of which KEYWORD is an abbreviation. This is necessary because some -system routines have keywords which are prefixes of other keywords. -If KEYWORD is an abbreviation of several keywords, a list of all possible -completions is returned. -If the abbreviation was unique, the correct keyword is returned. -If it cannot be a keyword, the function return nil. -If we do not know about MODULE, just return KEYWORD literally." - (let* ((name (car module)) - (type (nth 1 module)) - (class (nth 2 module)) - (kwd (idlwave-sintern-keyword keyword)) - (entry (idlwave-best-rinfo-assoc name type class (idlwave-routines))) - (kwd-alist (idlwave-entry-keywords entry)) - (extra (or (assq (idlwave-sintern-keyword "_EXTRA") kwd-alist) - (assq (idlwave-sintern-keyword "_REF_EXTRA") kwd-alist))) - (completion-ignore-case t) - candidates) - (cond ((assq kwd kwd-alist) - kwd) - ((setq candidates (all-completions kwd kwd-alist)) - (if (= (length candidates) 1) - (car candidates) - candidates)) - ((and entry extra) - ;; Inheritance may cause this keyword to be correct - keyword) - (entry - ;; We do know the function, which does not have the keyword. - nil) - (t - ;; We do not know the function, so this just might be a correct - ;; keyword - return it as it is. - keyword)))) - -(defvar idlwave-rinfo-mouse-map - (let ((map (make-sparse-keymap))) - (define-key map [mouse-2] #'idlwave-mouse-active-rinfo) - (define-key map [(shift mouse-2)] #'idlwave-mouse-active-rinfo-shift) - (define-key map [mouse-3] #'idlwave-mouse-active-rinfo-right) - (define-key map " " #'idlwave-active-rinfo-space) - (define-key map "q" #'idlwave-quit-help) - map)) - -(defvar idlwave-rinfo-map - (let ((map (make-sparse-keymap))) - (define-key map "q" #'idlwave-quit-help) - map)) - -(defvar idlwave-popup-source nil) -(defvar idlwave-rinfo-marker (make-marker)) - -(defun idlwave-quit-help () - (interactive) - (let ((ri-window (get-buffer-window "*Help*")) - (olh-window (get-buffer-window "*IDLWAVE Help*"))) - (when (and olh-window - (fboundp 'idlwave-help-quit)) - (select-window olh-window) - (idlwave-help-quit)) - (when (window-live-p ri-window) - (quit-window nil ri-window)))) - -(defun idlwave-display-calling-sequence (name type class - &optional initial-class) - ;; Display the calling sequence of module NAME, type TYPE in class CLASS. - (let* ((initial-class (or initial-class class)) - (entry (or (idlwave-best-rinfo-assq name type class - (idlwave-routines)) - (idlwave-rinfo-assq name type class - idlwave-unresolved-routines))) - (name (or (car entry) name)) - (class (or (nth 2 entry) class)) - (superclasses (idlwave-all-class-inherits initial-class)) - (twins (idlwave-routine-twins entry)) - (dtwins (idlwave-study-twins twins)) - (all dtwins) - (system (eq (car (nth 3 entry)) 'system)) - (calling-seq (nth 4 entry)) - (keywords (idlwave-entry-keywords entry 'do-link)) - (html-file (car (nth 5 entry))) - (help-echo-kwd - "Button2: Insert KEYWORD (SHIFT=`/KEYWORD') | Button3: Online Help ") - (help-echo-use - "Button2/3: Online Help") - (help-echo-src - "Button2: Jump to source and back | Button3: Source in Help window.") - (help-echo-class - "Button2: Display info about same method in superclass") - (col 0) - (data (list name type class (current-buffer) nil initial-class)) - (face 'idlwave-help-link) - beg props win cnt total) - ;; Fix keywords, but don't add chained idlwave--super-classes, since these - ;; are shown separately for that super-class - (setq keywords (idlwave-fix-keywords name type class keywords)) - (cond - ((null entry) - (error "No %s %s known %s" type name - (if initial-class (concat "in class " initial-class) ""))) - ((or (null name) (equal name "")) - (error "No function or procedure call at point")) - ((null calling-seq) - (error "Calling sequence of %s %s not available" type name)) - (t - (move-marker idlwave-rinfo-marker (point)) - (with-current-buffer (get-buffer-create "*Help*") - (use-local-map idlwave-rinfo-map) - (setq buffer-read-only nil) - (erase-buffer) - (set (make-local-variable 'idlwave-popup-source) nil) - (set (make-local-variable 'idlwave-current-obj_new-class) - idlwave-current-obj_new-class) - (when superclasses - (setq props (list 'mouse-face 'highlight - 'local-map idlwave-rinfo-mouse-map - 'help-echo help-echo-class - 'data (cons 'class data))) - (let ((classes (cons initial-class superclasses)) c) - (insert "Classes: ") - (while (setq c (pop classes)) - (insert " ") - (setq beg (point)) - (insert c) - (if (equal (downcase c) (downcase class)) - (add-text-properties beg (point) (list 'face 'bold)) - ;; If Method exists in a different class link it - (if (idlwave-rinfo-assq name type c (idlwave-routines)) - (add-text-properties beg (point) props)))) - (insert "\n"))) - (setq props (list 'mouse-face 'highlight - 'local-map idlwave-rinfo-mouse-map - 'help-echo help-echo-use - 'data (cons 'usage data))) - (if html-file (setq props (append (list 'face face 'link html-file) - props))) - (insert "Usage: ") - (setq beg (point)) - (insert (if class - (format calling-seq class name class name class name) - (format calling-seq name name name name)) - "\n") - (add-text-properties beg (point) props) - - (insert "Keywords:") - (if (null keywords) - (insert " No keywords accepted.") - (setq col 9) - (mapc - (lambda (x) - (if (>= (+ col 1 (length (car x))) - (window-width)) - (progn - (insert "\n ") - (setq col 9))) - (insert " ") - (setq beg (point) - ;; Relevant keywords already have link property attached - props (list 'mouse-face 'highlight - 'local-map idlwave-rinfo-mouse-map - 'data (cons 'keyword data) - 'help-echo help-echo-kwd - 'keyword (car x))) - (if system (setq props (append (list 'face face) props))) - (insert (car x)) - (add-text-properties beg (point) props) - (setq col (+ col 1 (length (car x))))) - keywords)) - - (setq cnt 1 total (length all)) - ;; Here entry is (key file (list of type-conses)) - (while (setq entry (pop all)) - (setq props (list 'mouse-face 'highlight - 'local-map idlwave-rinfo-mouse-map - 'help-echo help-echo-src - 'source (list (car (car (nth 2 entry))) ;type - (nth 1 entry) - nil - (cdr (car (nth 2 entry)))) - 'data (cons 'source data))) - (idlwave-insert-source-location - (format "\n%-8s %s" - (if (equal cnt 1) - (if (> total 1) "Sources:" "Source:") - "") - (if (> total 1) "- " "")) - entry props) - (cl-incf cnt) - (when (and all (> cnt idlwave-rinfo-max-source-lines)) - ;; No more source lines, please - (insert (format - "\n Source information truncated to %d entries." - idlwave-rinfo-max-source-lines)) - (setq all nil))) - (goto-char (point-min)) - (setq buffer-read-only t)) - (display-buffer "*Help*") - (if (and (setq win (get-buffer-window "*Help*")) - idlwave-resize-routine-help-window) - (progn - (let ((ww (selected-window))) - (unwind-protect - (progn - (select-window win) - (enlarge-window (- (/ (frame-height) 2) - (window-height))) - (shrink-window-if-larger-than-buffer)) - (select-window ww))))))))) - -(defun idlwave-insert-source-location (prefix entry &optional file-props) - "Insert a source location into the routine info buffer. -Start line with PREFIX. If a file name is inserted, add FILE-PROPS -to it." - (let* ((key (car entry)) - (file (nth 1 entry)) - (types (nth 2 entry)) - (shell-flag (assq 'compiled types)) - (buffer-flag (assq 'buffer types)) - (user-flag (assq 'user types)) - (lib-flag (assq 'lib types)) - (ndupl (or (and buffer-flag (idlwave-count-memq 'buffer types)) - (and user-flag (idlwave-count-memq 'user types)) - (and lib-flag (idlwave-count-memq 'lib types)) - 1)) - (doflags t) - beg special) - - (insert prefix) - - (cond - ((eq key 'system) - (setq doflags nil) - (insert "System ")) - - ((eq key 'builtin) - (setq doflags nil) - (insert "Builtin ")) - - ((and (not file) shell-flag) - (insert "Unresolved")) - - ((null file) - (insert "ERROR")) - - ((idlwave-syslib-p file) - (if (string-match "obsolete" (file-name-directory file)) - (insert "Obsolete ") - (insert "SystemLib "))) - - ;; New special syntax: taken directly from routine-info for - ;; library catalog routines - ((setq special (or (cdr lib-flag) (cdr user-flag))) - (insert (format "%-10s" special))) - - ;; Old special syntax: a matching regexp - ((setq special (idlwave-special-lib-test file)) - (insert (format "%-10s" special))) - - ;; Catch-all with file - ((idlwave-lib-p file) (insert "Library ")) - - ;; Sanity catch all - (t (insert "Other "))) - - (when doflags - (insert (concat - " [" - (if lib-flag "L" "-") - (if user-flag "C" "-") - (if shell-flag "S" "-") - (if buffer-flag "B" "-") - "] "))) - (when (> ndupl 1) - (setq beg (point)) - (insert (format "(%dx) " ndupl)) - (add-text-properties beg (point) (list 'face 'bold))) - (when (and file (not (equal file ""))) - (setq beg (point)) - (insert (apply #'abbreviate-file-name (list file))) - (if file-props - (add-text-properties beg (point) file-props))))) - -(defun idlwave-special-lib-test (file) - "Check the path of FILE against the regexps which define special libs. -Return the name of the special lib if there is a match." - (let ((alist idlwave-special-lib-alist) - entry rtn) - (cond - ((stringp file) - (while (setq entry (pop alist)) - (if (string-match (car entry) file) - (setq rtn (cdr entry) - alist nil))) - rtn) - (t nil)))) - -(defun idlwave-mouse-active-rinfo-right (ev) - (interactive "e") - (idlwave-mouse-active-rinfo ev 'right)) - -(defun idlwave-mouse-active-rinfo-shift (ev) - (interactive "e") - (idlwave-mouse-active-rinfo ev nil 'shift)) - -(defun idlwave-active-rinfo-space () - (interactive) - (idlwave-mouse-active-rinfo nil 'right)) - -(defun idlwave-mouse-active-rinfo (ev &optional right shift) - "Do the mouse actions in the routine info buffer. -Optional args RIGHT and SHIFT indicate, if mouse-3 was used, and if SHIFT -was pressed." - (interactive "e") - (if ev (mouse-set-point ev)) - (let (data id name type class buf bufwin source link keyword - word initial-class) - (setq data (get-text-property (point) 'data) - source (get-text-property (point) 'source) - keyword (get-text-property (point) 'keyword) - link (get-text-property (point) 'link) - id (car data) - name (nth 1 data) type (nth 2 data) class (nth 3 data) - buf (nth 4 data) - initial-class (nth 6 data) - word (idlwave-this-word) - bufwin (get-buffer-window buf t)) - - (cond ((eq id 'class) ; Switch class being displayed - (if (window-live-p bufwin) (select-window bufwin)) - (idlwave-display-calling-sequence - (idlwave-sintern-method name) - type (idlwave-sintern-class word) - initial-class)) - ((eq id 'usage) ; Online help on this routine - (idlwave-online-help link name type class)) - ((eq id 'source) ; Source in help or buffer - (if right ; In help - (let ((idlwave-extra-help-function 'idlwave-help-with-source) - (idlwave-help-source-try-header nil) - ;; Fake idlwave-routines so help will find the right entry - (idlwave-routines - (list (list name type class source "")))) - (idlwave-help-get-special-help name type class nil)) - ;; Otherwise just pop to the source - (setq idlwave-popup-source (not idlwave-popup-source)) - (if idlwave-popup-source - (condition-case err - (idlwave-do-find-module name type class source) - (error - (setq idlwave-popup-source nil) - (if (window-live-p bufwin) (select-window bufwin)) - (error (nth 1 err)))) - (if bufwin - (select-window bufwin) - (pop-to-buffer buf)) - (goto-char (marker-position idlwave-rinfo-marker))))) - ((eq id 'keyword) - (if right - (idlwave-online-help link name type class keyword) - (idlwave-rinfo-insert-keyword keyword buf shift)))))) - -(defun idlwave-rinfo-insert-keyword (keyword buffer &optional shift) - "Insert KEYWORD in BUFFER. Make sure buffer is displayed in a window." - (let ((bwin (get-buffer-window buffer))) - (if idlwave-complete-empty-string-as-lower-case - (setq keyword (downcase keyword))) - (if bwin - (select-window bwin) - (pop-to-buffer buffer) - (setq bwin (get-buffer-window buffer))) - (if (eq (preceding-char) ?/) - (insert keyword) - (unless (save-excursion - (re-search-backward - "[(,][ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\)?[ \t]*\\=" - (min (- (point) 100) (point-min)) t)) - (insert ", ")) - (if shift (insert "/")) - (insert keyword) - (if (and (not shift) - idlwave-keyword-completion-adds-equal) - (insert "="))))) - -(defun idlwave-list-buffer-load-path-shadows (&optional _arg) - "List the load path shadows of all routines defined in current buffer." - (interactive) - (idlwave-routines) - (if (derived-mode-p 'idlwave-mode) - (idlwave-list-load-path-shadows - nil (idlwave-update-current-buffer-info 'save-buffer) - "in current buffer") - (error "Current buffer is not in idlwave-mode"))) - -(defun idlwave-list-shell-load-path-shadows (&optional _arg) - "List the load path shadows of all routines compiled under the shell. -This is very useful for checking an IDL application. Just compile the -application, do RESOLVE_ALL, and \\`C-c C-i' to compile all referenced -routines and update IDLWAVE internal info. Then check for shadowing -with this command." - (interactive) - (cond - ((or (not (fboundp 'idlwave-shell-is-running)) - (not (idlwave-shell-is-running))) - (error "Shell is not running")) - ((null idlwave-compiled-routines) - (error "No compiled routines. Maybe you need to update with `C-c C-i'")) - (t - (idlwave-list-load-path-shadows nil idlwave-compiled-routines - "in the shell")))) - -(defun idlwave-list-all-load-path-shadows (&optional _arg) - "List the load path shadows of all routines known to IDLWAVE." - (interactive) - (idlwave-list-load-path-shadows nil nil "globally")) - -(defvar idlwave-sort-prefer-buffer-info t - "Internal variable used to influence `idlwave-routine-twin-compare'.") - -(defun idlwave-list-load-path-shadows (_arg &optional special-routines loc) - "List the routines which are defined multiple times. -Search the information IDLWAVE has about IDL routines for multiple -definitions. -When SPECIAL-ROUTINES in non-nil, only look for shadows of these routines. - -When IDL hits a routine call which is not defined, it will search on -the load path in order to find a definition. The output of this command -can be used to detect possible name clashes during this process." - (idlwave-routines) ; Make sure everything is loaded. - (unless (or idlwave-user-catalog-routines idlwave-library-catalog-routines) - (or (y-or-n-p - "You don't have any user or library catalogs. Continue anyway? ") - (error "Abort"))) - (let* ((routines (append idlwave-system-routines - idlwave-compiled-routines - idlwave-library-catalog-routines - idlwave-user-catalog-routines - idlwave-buffer-routines - nil)) - (keymap (make-sparse-keymap)) - (props (list 'mouse-face 'highlight - 'local-map keymap - 'help-echo "Mouse2: Find source")) - (nroutines (length (or special-routines routines))) - (step (/ nroutines 100)) - (n 0) - (cnt 0) - (idlwave-sort-prefer-buffer-info nil) - routine twins dtwins twin done props1 lroutines) - - (if special-routines - ;; Just looking for shadows of a few special routines - (setq lroutines routines - routines special-routines)) - - (message "Sorting routines...") - (setq routines (sort routines - (lambda (a b) - (string< (downcase (idlwave-make-full-name - (nth 2 a) (car a))) - (downcase (idlwave-make-full-name - (nth 2 b) (car b))))))) - (message "Sorting routines...done") - - (define-key keymap [(mouse-2)] - (lambda (ev) - (interactive "e") - (mouse-set-point ev) - (apply #'idlwave-do-find-module - (get-text-property (point) 'find-args)))) - (define-key keymap [(return)] - (lambda () - (interactive) - (apply #'idlwave-do-find-module - (get-text-property (point) 'find-args)))) - (message "Compiling list...( 0%%)") - (with-current-buffer (get-buffer-create "*Shadows*") - (setq buffer-read-only nil) - (erase-buffer) - (while (setq routine (pop routines)) - (if (= (mod (setq n (1+ n)) step) 0) - (message "Compiling list...(%2d%%)" (floor (* n 100.0) nroutines))) - - ;; Get a list of all twins - (setq twins (idlwave-routine-twins routine (or lroutines routines))) - (if (memq routine done) - (setq dtwins nil) - (setq dtwins (idlwave-study-twins twins))) - ;; Mark all twins as dealt with - (setq done (append twins done)) - (when (or (> (length dtwins) 1) - (> (idlwave-count-memq 'lib (nth 2 (car dtwins))) 1) - (> (idlwave-count-memq 'user (nth 2 (car dtwins))) 1) - (> (idlwave-count-memq 'buffer (nth 2 (car dtwins))) 1)) - (cl-incf cnt) - (insert (format "\n%s%s" - (idlwave-make-full-name (nth 2 routine) - (car routine)) - (if (eq (nth 1 routine) 'fun) "()" ""))) - (while (setq twin (pop dtwins)) - (setq props1 (append (list 'find-args - (list (nth 0 routine) - (nth 1 routine) - (nth 2 routine))) - props)) - (idlwave-insert-source-location "\n - " twin props1)))) - (goto-char (point-min)) - (setq buffer-read-only t)) - (setq loc (or loc "")) - (if (> cnt 0) - (progn - (display-buffer (get-buffer "*Shadows*")) - (message "%d case%s of shadowing found %s" - cnt (if (= cnt 1) "" "s") loc)) - (message "No shadowing conflicts found %s" loc)))) - -(defun idlwave-print-source (routine) - (let* ((source (nth 3 routine)) - (stype (car source)) - (sfile (idlwave-routine-source-file source))) - (if (idlwave-syslib-p sfile) (setq stype 'syslib)) - (if (and (eq stype 'compiled) - (or (not (stringp sfile)) - (not (string-match "\\S-" sfile)))) - (setq stype 'unresolved)) - (princ (format " %-10s %s\n" - stype - (if sfile sfile "No source code available"))))) - -(defun idlwave-routine-twins (entry &optional list) - "Return all twin entries of ENTRY in LIST. -LIST defaults to `idlwave-routines'. -Twin entries are those which have the same name, type, and class. -ENTRY will also be returned, as the first item of this list." - (let* ((name (car entry)) - (type (nth 1 entry)) - (class (nth 2 entry)) - (candidates (idlwave-all-assq name (or list (idlwave-routines)))) - twins candidate) - (while (setq candidate (pop candidates)) - (if (and (not (eq candidate entry)) - (eq type (nth 1 candidate)) - (eq class (nth 2 candidate))) - (push candidate twins))) - (if (setq candidate (idlwave-rinfo-assq name type class - idlwave-unresolved-routines)) - (push candidate twins)) - (cons entry (nreverse twins)))) - -;; Bound in idlwave-study-twins,idlwave-routine-entry-compare-twins. -(defvar idlwave-twin-class) -(defvar idlwave-twin-name) - -(defun idlwave-study-twins (entries) - "Return dangerous twins of first entry in ENTRIES. -Dangerous twins are routines with same name, but in different files on -the load path. If a file is in the system library and has an entry in -the `idlwave-system-routines' list, we omit the latter as -non-dangerous because many IDL routines are implemented as library -routines, and may have been scanned." - (let* ((entry (car entries)) - (idlwave-twin-name (car entry)) ; - (type (nth 1 entry)) ; Must be bound for - (idlwave-twin-class (nth 2 entry)) ; idlwave-routine-twin-compare - (cnt 0) - source type-cons file alist syslibp key) - (while (setq entry (pop entries)) - (cl-incf cnt) - (setq source (nth 3 entry) - type (car source) - type-cons (cons type (nth 3 source)) - file (idlwave-routine-source-file source)) - - ;; Make KEY to index entry properly - (setq key (cond ((eq type 'system) type) - (file (file-truename file)) - (t 'unresolved))) - - ;; Check for an entry in the system library - (if (and file - (not syslibp) - (idlwave-syslib-p file)) - (setq syslibp t)) - - ;; If there's more than one matching entry for the same file, just - ;; append the type-cons to the type list. - (if (setq entry (assoc key alist)) - (push type-cons (nth 2 entry)) - (push (list key file (list type-cons)) alist))) - - (setq alist (nreverse alist)) - - (when syslibp - ;; File is in system *library* - remove any 'system entry - (setq alist (delq (assq 'system alist) alist))) - - ;; If 'system remains and we've scanned the syslib, it's a builtin - ;; (rather than a !DIR/lib/.pro file bundled as source). - (when (and (idlwave-syslib-scanned-p) - (setq entry (assoc 'system alist))) - (setcar entry 'builtin)) - (sort alist #'idlwave-routine-twin-compare))) - -;; FIXME: Dynamically scoped vars need to use the `idlwave-' prefix. -;; (defvar type) - -(define-obsolete-function-alias 'idlwave-xor #'xor "27.1") - -(defun idlwave-routine-entry-compare (a b) - "Compare two routine info entries for sorting. -This is the general case. It first compares class, names, and type. -If it turns out that A and B are twins (same name, class, and type), -calls another routine which compares twins on the basis of their file -names and path locations." - (let ((name (car a)) (type (nth 1 a)) (class (nth 2 a))) - (cond - ((not (equal (idlwave-downcase-safe class) - (idlwave-downcase-safe (nth 2 b)))) - ;; Class decides - (cond ((null (nth 2 b)) nil) - ((null class) t) - (t (string< (downcase class) (downcase (nth 2 b)))))) - ((not (equal (downcase name) (downcase (car b)))) - ;; Name decides - (string< (downcase name) (downcase (car b)))) - ((not (eq type (nth 1 b))) - ;; Type decides - (< (if (eq type 'fun) 1 0) (if (eq (nth 1 b) 'fun) 1 0))) - (t - ;; A and B are twins - so the decision is more complicated. - ;; Call twin-compare with the proper arguments. - (idlwave-routine-entry-compare-twins a b))))) - -(defun idlwave-routine-entry-compare-twins (a b) - "Compare two routine entries, under the assumption that they are twins. -This basically calls `idlwave-routine-twin-compare' with the correct args." - (let* ((idlwave-twin-name (car a)) - ;; (type (nth 1 a)) - (idlwave-twin-class (nth 2 a)) ; used in idlwave-routine-twin-compare - (asrc (nth 3 a)) - (atype (car asrc)) - (bsrc (nth 3 b)) - (btype (car bsrc)) - (afile (idlwave-routine-source-file asrc)) - (bfile (idlwave-routine-source-file bsrc))) - (idlwave-routine-twin-compare - (if (stringp afile) - (list (file-truename afile) afile (list atype)) - (list atype afile (list atype))) - (if (stringp bfile) - (list (file-truename bfile) bfile (list btype)) - (list btype bfile (list btype)))))) - -(defun idlwave-routine-twin-compare (a b) - "Compare two routine twin entries for sorting. -In here, A and B are not normal routine info entries, but special -lists (KEY FILENAME (TYPES...)). -This expects NAME TYPE IDLWAVE-TWIN-CLASS to be bound to the right values." - (let* (;; Dis-assemble entries - (akey (car a)) (bkey (car b)) - (afile (nth 1 a)) (bfile (nth 1 b)) - (atypes (nth 2 a)) (btypes (nth 2 b)) - ;; System routines? - (asysp (memq akey '(builtin system))) - (bsysp (memq bkey '(builtin system))) - ;; Compiled routines? - (acompp (memq 'compiled atypes)) - (bcompp (memq 'compiled btypes)) - ;; Unresolved? - (aunresp (or (eq akey 'unresolved) - (and acompp (not afile)))) - (bunresp (or (eq bkey 'unresolved) - (and bcompp (not bfile)))) - ;; Buffer info available? - (abufp (memq 'buffer atypes)) - (bbufp (memq 'buffer btypes)) - ;; On search path? - (tpath-alist (idlwave-true-path-alist)) - (apathp (and (stringp akey) - (assoc (file-name-directory akey) tpath-alist))) - (bpathp (and (stringp bkey) - (assoc (file-name-directory bkey) tpath-alist))) - ;; How early on search path? High number means early since we - ;; measure the tail of the path list - (anpath (length (memq apathp tpath-alist))) - (bnpath (length (memq bpathp tpath-alist))) - ;; Look at file names - (aname (if (stringp afile) (downcase (file-name-nondirectory afile)) "")) - (bname (if (stringp bfile) (downcase (file-name-nondirectory bfile)) "")) - (fname-re (if idlwave-twin-class - (format "\\`%s__\\(%s\\|define\\)\\.pro\\'" - (regexp-quote (downcase idlwave-twin-class)) - (regexp-quote (downcase idlwave-twin-name))) - (format "\\`%s\\.pro" (regexp-quote (downcase idlwave-twin-name))))) - ;; Is file name derived from the routine name? - ;; Method file or class definition file? - (anamep (string-match fname-re aname)) - (adefp (and idlwave-twin-class anamep - (string= "define" (match-string 1 aname)))) - (bnamep (string-match fname-re bname)) - (bdefp (and idlwave-twin-class bnamep - (string= "define" (match-string 1 bname))))) - - ;; Now: follow JD's ideas about sorting. Looks really simple now, - ;; doesn't it? The difficult stuff is hidden above... - (cond - ((xor asysp bsysp) asysp) ; System entries first - ((xor aunresp bunresp) bunresp) ; Unresolved last - ((and idlwave-sort-prefer-buffer-info - (xor abufp bbufp)) abufp) ; Buffers before non-buffers - ((xor acompp bcompp) acompp) ; Compiled entries - ((xor apathp bpathp) apathp) ; Library before non-library - ((xor anamep bnamep) anamep) ; Correct file names first - ((and idlwave-twin-class anamep bnamep ; both file names match -> - (xor adefp bdefp)) bdefp) ; __define after __method - ((> anpath bnpath) t) ; Who is first on path? - (t nil)))) ; Default - -(defun idlwave-routine-source-file (source) - (if (nth 2 source) - (expand-file-name (nth 1 source) (nth 2 source)) - (nth 1 source))) - -(defun idlwave-downcase-safe (string) - "Downcase if string, else return unchanged." - (if (stringp string) - (downcase string) - string)) - -(defun idlwave-count-eq (elt list) - "How often is ELT in LIST?" - (declare (obsolete nil "30.1")) - (seq-count (lambda (x) (eq x elt)) list)) - -(defun idlwave-count-memq (elt alist) - "How often is ELT a key in ALIST?" - (seq-count (lambda (x) (eq (car x) elt)) alist)) - -(defun idlwave-syslib-p (file) - "Non-nil if FILE is in the system library." - (let* ((true-syslib (file-name-as-directory - (file-truename - (expand-file-name "lib" (idlwave-sys-dir))))) - (true-file (file-truename file))) - (string-match (concat "^" (regexp-quote true-syslib)) true-file))) - -(defun idlwave-lib-p (file) - "Non-nil if FILE is in the library." - (let ((true-dir (file-name-directory (file-truename file)))) - (assoc true-dir (idlwave-true-path-alist)))) - -(defun idlwave-path-alist-add-flag (list-entry flag) - "Add a flag to the path list entry, if not set." - (cl-pushnew flag (cdr list-entry) :test #'equal)) - -(defun idlwave-path-alist-remove-flag (list-entry flag) - "Remove a flag to the path list entry, if set." - (let ((flags (delq flag (cdr list-entry)))) - (setcdr list-entry flags))) - -(defun idlwave-true-path-alist () - "Return `idlwave-path-alist' alist with true-names. -Info is cached, but relies on the functions setting `idlwave-path-alist' -to reset the variable `idlwave-true-path-alist' to nil." - (or idlwave-true-path-alist - (setq idlwave-true-path-alist - (mapcar (lambda(x) (cons - (file-name-as-directory - (file-truename - (directory-file-name - (car x)))) - (cdr x))) - idlwave-path-alist)))) - -(defun idlwave-syslib-scanned-p () - "Non-nil if the system lib file !DIR/lib has been scanned." - (let* ((true-syslib (file-name-as-directory - (file-truename - (expand-file-name "lib" (idlwave-sys-dir)))))) - (cdr (assoc true-syslib (idlwave-true-path-alist))))) - -;; ---------------------------------------------------------------------------- -;; -;; Online Help display - - -;; ---------------------------------------------------------------------------- -;; -;; Additions for use with imenu.el -;; (pop-up a list of IDL units in the current file). -;; - -(defun idlwave-prev-index-position () - "Search for the previous procedure or function. -Return nil if not found. For use with imenu.el." - (save-match-data - (cond - ((idlwave-find-key "\\<\\(pro\\|function\\)\\>" -1 'nomark)) - ;; ((idlwave-find-key idlwave-begin-unit-reg 1 'nomark) - (t nil)))) - -(defun idlwave-unit-name () - "Return the unit name. -Assumes that point is at the beginning of the unit as found by -`idlwave-prev-index-position'." - (forward-sexp 2) - (forward-sexp -1) - (let ((begin (point))) - (re-search-forward - "[a-zA-Z_][a-zA-Z0-9$_]+\\(::[a-zA-Z_][a-zA-Z0-9$_]+\\)?") - (buffer-substring-no-properties begin (point)))) - -(define-obsolete-function-alias 'idlwave-function-menu #'imenu "29.1") - -(defun idlwave-edit-in-idlde () - "Edit the current file in IDL Development environment." - (interactive) - (start-process "idldeclient" nil - idlwave-shell-explicit-file-name "-c" "-e" - (buffer-file-name))) - -(defvar idlwave-help-use-assistant) -(defun idlwave-launch-idlhelp () - "Start the IDLhelp application." - (interactive) - (if idlwave-help-use-assistant - (idlwave-help-assistant-raise) - (start-process "idlhelp" nil idlwave-help-application))) - -;; Menus - using easymenu.el -(defvar idlwave-mode-menu-def - '("IDLWAVE" - ["PRO/FUNC menu" imenu t] - ("Motion" - ["Subprogram Start" idlwave-beginning-of-subprogram t] - ["Subprogram End" idlwave-end-of-subprogram t] - ["Block Start" idlwave-beginning-of-block t] - ["Block End" idlwave-end-of-block t] - ["Up Block" idlwave-backward-up-block t] - ["Down Block" idlwave-down-block t] - ["Skip Block Backward" idlwave-backward-block t] - ["Skip Block Forward" idlwave-forward-block t]) - ("Mark" - ["Subprogram" idlwave-mark-subprogram t] - ["Block" idlwave-mark-block t] - ["Header" idlwave-mark-doclib t]) - ("Format" - ["Indent Entire Statement" idlwave-indent-statement - :active t :keys "C-u \\[indent-for-tab-command]" ] - ["Indent Subprogram" idlwave-indent-subprogram t] - ["(Un)Comment Region" idlwave-toggle-comment-region t] - ["Continue/Split line" idlwave-split-line t] - "--" - ["Toggle Auto Fill" auto-fill-mode :style toggle - :selected auto-fill-function]) - ("Templates" - ["Procedure" idlwave-procedure t] - ["Function" idlwave-function t] - ["Doc Header" idlwave-doc-header t] - ["Log" idlwave-doc-modification t] - "--" - ["Case" idlwave-case t] - ["For" idlwave-for t] - ["Repeat" idlwave-repeat t] - ["While" idlwave-while t] - "--" - ["Close Block" idlwave-close-block t]) - ("Completion" - ["Complete" idlwave-complete t] - ("Complete Specific" - ["1 Procedure Name" (idlwave-complete 'procedure) t] - ["2 Procedure Keyword" (idlwave-complete 'procedure-keyword) t] - "--" - ["3 Function Name" (idlwave-complete 'function) t] - ["4 Function Keyword" (idlwave-complete 'function-keyword) t] - "--" - ["5 Procedure Method Name" (idlwave-complete 'procedure-method) t] - ["6 Procedure Method Keyword" (idlwave-complete 'procedure-method-keyword) t] - "--" - ["7 Function Method Name" (idlwave-complete 'function-method) t] - ["8 Function Method Keyword" (idlwave-complete 'function-method-keyword) t] - "--" - ["9 Class Name" idlwave-complete-class t])) - ("Routine Info" - ["Show Routine Info" idlwave-routine-info t] - ["Online Context Help" idlwave-context-help t] - "--" - ["Find Routine Source" idlwave-find-module t] - ["Resolve Routine" idlwave-resolve (featurep 'idlw-shell)] - "--" - ["Update Routine Info" idlwave-update-routine-info t] - ["Rescan XML Help Catalog" idlwave-convert-xml-system-routine-info t] - "--" - "IDL User Catalog" - ["Select Catalog Directories" (idlwave-create-user-catalog-file nil) t] - ["Scan Directories" (idlwave-update-routine-info '(16)) - (and idlwave-path-alist (not idlwave-catalog-process))] - ["Scan Directories &" (idlwave-update-routine-info '(64)) - (and idlwave-path-alist (not idlwave-catalog-process))] - "--" - "Routine Shadows" - ["Check Current Buffer" idlwave-list-buffer-load-path-shadows t] - ["Check Compiled Routines" idlwave-list-shell-load-path-shadows t] - ["Check Everything" idlwave-list-all-load-path-shadows t]) - ("Misc" - ["Kill auto-created buffers" idlwave-kill-autoloaded-buffers t] - "--" - ["Insert TAB character" idlwave-hard-tab t]) - "--" - ("External" - ["Start IDL shell" idlwave-shell t] - ["Edit file in IDLDE" idlwave-edit-in-idlde t] - ["Launch IDL Help" idlwave-launch-idlhelp t]) - "--" - ("Customize" - ["Browse IDLWAVE Group" idlwave-customize t] - "--" - ["Build Full Customize Menu" idlwave-create-customize-menu t]) - ("Documentation" - ["Describe Mode" describe-mode t] - ["Abbreviation List" idlwave-list-abbrevs t] - "--" - ["Commentary in idlwave.el" idlwave-show-commentary t] - ["Commentary in idlw-shell.el" idlwave-shell-show-commentary t] - "--" - ["Info" idlwave-info t] - "--" - ["Help with Topic" idlwave-help-assistant-help-with-topic - idlwave-help-use-assistant] - ["Launch IDL Help" idlwave-launch-idlhelp t]))) - -(defvar idlwave-mode-debug-menu-def - '("Debug" - ["Start IDL shell" idlwave-shell t] - ["Save and .RUN buffer" idlwave-shell-save-and-run - (and (boundp 'idlwave-shell-automatic-start) - idlwave-shell-automatic-start)])) - -(easy-menu-define idlwave-mode-menu idlwave-mode-map - "IDL and WAVE CL editing menu." - idlwave-mode-menu-def) -(easy-menu-define idlwave-mode-debug-menu idlwave-mode-map - "IDL and WAVE CL editing menu." - idlwave-mode-debug-menu-def) - -(defun idlwave-customize () - "Call the customize function with `idlwave' as argument." - (interactive) - ;; Try to load the code for the shell, so that we can customize it - ;; as well. - (or (featurep 'idlw-shell) - (load "idlw-shell" t)) - (customize-browse 'idlwave)) - -(defun idlwave-create-customize-menu () - "Create a full customization menu for IDLWAVE, insert it into the menu." - (interactive) - ;; Try to load the code for the shell, so that we can customize it - ;; as well. - (or (featurep 'idlw-shell) - (load "idlw-shell" t)) - (easy-menu-change - '("IDLWAVE") "Customize" - `(["Browse IDLWAVE group" idlwave-customize t] - "--" - ,(customize-menu-create 'idlwave) - ["Set" Custom-set t] - ["Save" Custom-save t] - ["Reset to Current" Custom-reset-current t] - ["Reset to Saved" Custom-reset-saved t] - ["Reset to Standard Settings" Custom-reset-standard t])) - (message "\"IDLWAVE\"-menu now contains full customization menu")) - -(defun idlwave-show-commentary () - "Use the finder to view the file documentation from `idlwave.el'." - (interactive) - (finder-commentary "idlwave.el")) - -(defun idlwave-shell-show-commentary () - "Use the finder to view the file documentation from `idlw-shell.el'." - (interactive) - (finder-commentary "idlw-shell.el")) - -(defun idlwave-info () - "Read documentation for IDLWAVE in the info system." - (interactive) - (info "idlwave")) - -(defun idlwave-list-abbrevs (arg) - "Show the code abbreviations define in IDLWAVE mode. -This lists all abbrevs where the replacement text differs from the input text. -These are the ones the users want to learn to speed up their writing. - -The function does *not* list abbrevs which replace a word with itself -to call a hook. These hooks are used to change the case of words or -to blink the matching `begin', and the user does not need to know them. - -With arg, list all abbrevs with the corresponding hook. - -This function was written since `list-abbrevs' looks terrible for IDLWAVE mode." - - (interactive "P") - (let ((table idlwave-mode-abbrev-table) - abbrevs - str rpl func fmt (len-str 0) (len-rpl 0)) - (mapatoms - (lambda (sym) - (if (symbol-value sym) - (progn - (setq str (symbol-name sym) - rpl (symbol-value sym) - func (symbol-function sym)) - (if arg - (setq func (prin1-to-string func)) - (if (and (listp func) (stringp (nth 2 func))) - (setq rpl (concat "EVAL: " (nth 2 func)) - func "") - (setq func ""))) - (if (or arg (not (string= rpl str))) - (progn - (setq len-str (max len-str (length str))) - (setq len-rpl (max len-rpl (length rpl))) - (setq abbrevs (cons (list str rpl func) abbrevs))))))) - table) - ;; sort the list - (setq abbrevs (sort abbrevs (lambda (a b) (string< (car a) (car b))))) - ;; Make the format - (setq fmt (format "%%-%ds %%-%ds %%s\n" len-str len-rpl)) - (with-output-to-temp-buffer "*Help*" - (if arg - (progn - (princ "Abbreviations and Actions in IDLWAVE-Mode\n") - (princ "=========================================\n\n") - (princ (format fmt "KEY" "REPLACE" "HOOK")) - (princ (format fmt "---" "-------" "----"))) - (princ "Code Abbreviations and Templates in IDLWAVE-Mode\n") - (princ "================================================\n\n") - (princ (format fmt "KEY" "ACTION" "")) - (princ (format fmt "---" "------" ""))) - (dolist (list abbrevs) - (setq str (car list) - rpl (nth 1 list) - func (nth 2 list)) - (princ (format fmt str rpl func))))) - ;; Make sure each abbreviation uses only one display line - (with-current-buffer "*Help*" - (setq truncate-lines t))) - -(declare-function speedbar-add-supported-extension "speedbar" (extension)) - -;; Add .pro files to speedbar for support, if it's loaded -(eval-after-load "speedbar" '(speedbar-add-supported-extension ".pro")) - -;; Set an idle timer to load the routine info. -;; Will only work on systems which support this. -(or idlwave-routines (idlwave-start-load-rinfo-timer)) - -;; Run the hook -(run-hooks 'idlwave-load-hook) - -;; Obsolete. -(define-obsolete-function-alias 'idlwave-uniquify #'seq-uniq "28.1") - -(provide 'idlwave) - -;;; idlwave.el ends here -- 2.39.5