@cindex Javascript mode
@cindex Awk mode
@cindex C# mode
-@cindex IDLWAVE mode
@cindex JSON mode
@cindex SQL mode
@cindex TypeScript 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,
@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
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
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@
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 \
+++ /dev/null
-\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
-<A NAME="TUTORIAL"></A>
-@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
-<A NAME="ONLINE_HELP"></A>
-@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 "\\<common\\>[ \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
-<A NAME="EDEBUG"></A>
-@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
-<A NAME="EXAMINE"></A>
-@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 <dickow__at__nbi.dk>
-@item
-Eric E. Dors <edors__at__lanl.gov>
-@item
-Stein Vidar H. Haugan <s.v.h.haugan__at__astro.uio.no>
-@item
-David Huenemoerder <dph__at__space.mit.edu>
-@item
-Kevin Ivory <Kevin.Ivory__at__linmpi.mpg.de>
-@item
-Dick Jackson <dick__at__d-jackson.com>
-@item
-Xuyong Liu <liu__at__stsci.edu>
-@item
-Simon Marshall <Simon.Marshall__at__esrin.esa.it>
-@item
-Craig Markwardt <craigm__at__cow.physics.wisc.edu>
-@item
-Laurent Mugnier <mugnier__at__onera.fr>
-@item
-Lubos Pochman <lubos__at__rsinc.com>
-@item
-Bob Portmann <portmann__at__al.noaa.gov>
-@item
-Patrick M. Ryan <pat__at__jaameri.gsfc.nasa.gov>
-@item
-Marty Ryba <ryba__at__ll.mit.edu>
-@item
-Phil Williams <williams__at__irc.chmcc.org>
-@item
-Phil Sterne <sterne__at__dublin.llnl.gov>
-@item
-Paul Sorenson <aardvark62__at__msn.com>
-@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
-<A NAME="CATALOGS"></A>
-@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
-<A NAME="LIBRARY_CATALOGS"></A>
-@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
-<A NAME="WINDOWS_MAC"></A>
-@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
-<A NAME="TROUBLE"></A>
-@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
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 <https://lists.gnu.org/r/emacs-devel/2014-07/msg00008.html>
-<https://debbugs.gnu.org/39992>
-
*** Move Org mode to elpa.gnu.org
See <https://lists.gnu.org/r/emacs-devel/2014-08/msg00300.html>
<https://lists.gnu.org/r/emacs-devel/2014-11/msg00257.html>
;; 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
("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")
"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"
\f
(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")
'("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"
+++ /dev/null
-;;; idlw-complete-structtag.el --- Completion of structure tags. -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2001-2024 Free Software Foundation, Inc.
-
-;; Author: Carsten Dominik <dominik@astro.uva.nl>
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; 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
+++ /dev/null
-;;; idlw-help.el --- HTML Help code for IDLWAVE -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2000-2024 Free Software Foundation, Inc.
-;;
-;; Authors: JD Smith <jd.smith@utoledo.edu>
-;; Carsten Dominik <dominik@science.uva.nl>
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; 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
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-\f
-
-;;; 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 "\\<inherits[ \t]+[A-Za-z0-9_]*\\="
- (max (point-min) (- (point) 40)) t)))
- ;; Class completion inside string delimiters must be
- ;; the class inside OBJ_NEW.
- (let* ((entry (assq
- (idlwave-sintern-class this-word)
- idlwave-system-class-info))
- (name (concat (downcase this-word) "__define"))
- (link (nth 1 (assq 'link entry))))
- (setq mod1 (list link name 'pro))))
-
- ;; A class structure tag (self.BLAH) -- only in-text help available
- (classtag
- (let ((tag (substring this-word (match-end 0)))
- class-with found-in)
- (when (setq class-with
- (idlwave-class-or-superclass-with-tag
- (nth 2 (idlwave-current-routine))
- tag))
- (setq found-in (idlwave-class-found-in class-with))
- (if (assq (idlwave-sintern-class class-with)
- idlwave-system-class-info)
- (error "No help available for system class tags"))
- (setq idlwave-help-do-class-struct-tag t)
- (setq mod1 (list nil
- (if found-in
- (cons (concat found-in "__define") class-with)
- (concat class-with "__define"))
- 'pro
- nil ; no class.... it's a procedure!
- tag)))))
-
- ;; A regular structure tag -- only in text, and if
- ;; optional `complete-structtag' loaded.
- (structtag
- (let ((var (match-string 1 this-word))
- (tag (substring this-word (match-end 0))))
- ;; Check if we need to update the "current" structure
- (idlwave-prepare-structure-tag-completion var)
- (setq idlwave-help-do-struct-tag
- idlwave-structtag-struct-location
- mod1 (list nil nil nil nil tag))))
-
- ;; A routine keyword -- in text or system help
- ((and (memq cw '(function-keyword procedure-keyword))
- (stringp this-word)
- (string-match "\\S-" this-word)
- (not (string-search "!" this-word)))
- (cond ((or (= (char-before beg) ?/)
- (save-excursion (goto-char end)
- (looking-at "[ \t]*=")))
- ;; Certainly a keyword. Check for abbreviation etc.
- (setq keyword (idlwave-expand-keyword this-word module))
- (cond
- ((null keyword)
- (idlwave-help-diagnostics
- (format "%s does not accept `%s' kwd"
- (idlwave-make-full-name (nth 2 module)
- (car module))
- (upcase this-word))
- 'ding))
- ((consp keyword)
- (idlwave-help-diagnostics
- (format "%d matches for kwd abbrev `%s'"
- (length keyword) this-word)
- 'ding)
- ;; We continue anyway with the first match...
- (setq keyword (car keyword))))
- ;; Keyword, or just module
- (setq mod1 (append (list t) module (list keyword)))
- (setq mod2 (append (list t) module)))
- ((equal (char-after end) ?\()
- ;; A function - what-module will have caught this
- (setq mod1 (append (list t) module)))
- (t
- ;; undecided - try function, keyword, then enclosing mod.
- ;; Check for keyword abbreviations, but do not report
- ;; errors, because it might be something else.
- ;; FIXME: is this a good way to handle this?
- (setq keyword (idlwave-expand-keyword this-word module))
- (if (consp keyword) (setq keyword (car keyword)))
- (setq mod1 (append (list t) module (list keyword))
- mod2 (list t this-word 'fun nil)
- mod3 (append (list t) module)))))
-
- ;; Everything else
- (t
- (setq mod1 (append (list t) module))))
- (if mod3
- (condition-case nil
- (apply #'idlwave-online-help mod1)
- (error (condition-case nil
- (apply #'idlwave-online-help mod2)
- (error (apply #'idlwave-online-help mod3)))))
- (if mod2
- (condition-case nil
- (apply #'idlwave-online-help mod1)
- (error (apply #'idlwave-online-help mod2)))
- (if mod1
- (apply #'idlwave-online-help mod1)
- (error "Don't know which item to show help for")))))))
-
-(defun idlwave-do-mouse-completion-help (ev)
- "Display online help on an item in the *Completions* buffer.
-Needs additional info stored in global `idlwave-completion-help-info'."
- (let* ((cw (selected-window))
- (info idlwave-completion-help-info) ; global passed in
- (what (nth 0 info))
- (idlw-help-name (nth 1 info))
- (type (nth 2 info))
- (class (nth 3 info))
- (need-class class)
- (idlw-help-kwd (nth 4 info))
- (sclasses (nth 5 info))
- word idlw-help-link)
- (mouse-set-point ev)
-
-
- ;; See if we can also find help somewhere, e.g. for multiple classes
- (setq word (idlwave-this-word))
- (if (string= word "")
- (error "No help item selected"))
- (setq idlw-help-link (get-text-property 0 'link word))
- (select-window cw)
- (cond
- ;; Routine name
- ((memq what '(procedure function routine))
- (setq idlw-help-name word)
- (if (or (eq class t)
- (and (stringp class) sclasses))
- (let* ((classes (idlwave-all-method-classes
- (idlwave-sintern-method idlw-help-name)
- type)))
- (setq idlw-help-link t) ; No specific link valid yet
- (if sclasses
- (setq classes (idlwave-members-only
- classes (cons class sclasses))))
- (setq class (idlwave-popup-select ev classes
- "Select Class" 'sort))))
-
- ;; XXX is this necessary, given all-method-classes?
- (if (stringp class)
- (setq class (idlwave-find-inherited-class
- (idlwave-sintern-routine-or-method idlw-help-name class)
- type (idlwave-sintern-class class)))))
-
- ;; Keyword
- ((eq what 'keyword)
- (setq idlw-help-kwd word)
- (if (or (eq class t)
- (and (stringp class) sclasses))
- (let ((classes (idlwave-all-method-keyword-classes
- (idlwave-sintern-method idlw-help-name)
- (idlwave-sintern-keyword idlw-help-kwd)
- type)))
- (setq idlw-help-link t) ; Link can't be correct yet
- (if sclasses
- (setq classes (idlwave-members-only
- classes (cons class sclasses))))
- (setq class (idlwave-popup-select ev classes
- "Select Class" 'sort))
- ;; XXX is this necessary, given all-method-keyword-classes?
- (if (stringp class)
- (setq class (idlwave-find-inherited-class
- (idlwave-sintern-routine-or-method
- idlw-help-name class)
- type (idlwave-sintern-class class)))))
- (if (string= (downcase idlw-help-name) "obj_new")
- (setq class idlwave-current-obj_new-class
- idlw-help-name "Init"))))
-
- ;; Class name
- ((eq what 'class)
- (setq class word
- word nil))
-
- ;; A special named function to call which sets some of our variables
- ((and (symbolp what)
- (fboundp what))
- (funcall what 'set word))
-
- (t (error "Cannot help with this item")))
- (if (and need-class (not class)
- (not (and idlw-help-link (not (eq idlw-help-link t)))))
- (error "Cannot help with this item"))
- (idlwave-online-help idlw-help-link (or idlw-help-name word)
- type class idlw-help-kwd)))
-
-(defvar idlwave-highlight-help-links-in-completion)
-(defvar idlwave-completion-help-links)
-(defun idlwave-highlight-linked-completions ()
- "Highlight all completions for which help is available and attach link.
-Those words in `idlwave-completion-help-links' have links. The
-`idlwave-help-link' face is used for this."
- (if idlwave-highlight-help-links-in-completion
- (with-current-buffer "*Completions*"
- (save-excursion
- (let* ((case-fold-search t)
- (props (list 'face 'idlwave-help-link))
- (info idlwave-completion-help-info) ; global passed in
- (what (nth 0 info)) ; what was completed, or a func
- ;; (class (nth 3 info)) ; any class
- word beg end doit)
- (goto-char (point-min))
- (re-search-forward "possible completions are:" nil t)
- (while (re-search-forward "\\s-\\([A-Za-z0-9_.]+\\)\\(\\s-\\|\\'\\)"
- nil t)
- (setq beg (match-beginning 1) end (match-end 1)
- word (match-string 1) doit nil)
- ;; Call special completion function test
- (if (and (symbolp what)
- (fboundp what))
- (setq doit (funcall what 'test word))
- ;; Look for special link property passed in help-links
- (if idlwave-completion-help-links
- (setq doit (assoc-string
- word idlwave-completion-help-links t))))
- (when doit
- (if (consp doit)
- (setq props (append props `(link ,(cdr doit)))))
- (let ((buffer-read-only nil))
- (add-text-properties beg end props)))
- (goto-char end)))))))
-
-;; Arrange for this function to be called after completion
-(add-hook 'idlwave-completion-setup-hook
- #'idlwave-highlight-linked-completions)
-
-(defvar idlwave-help-return-frame nil
- "The frame to return to from the help frame.")
-
-(defun idlwave-help-quit ()
- "Exit IDLWAVE Help buffer. Kill the dedicated frame if any."
- (interactive)
- (cond ((and idlwave-help-use-dedicated-frame
- (eq (selected-frame) idlwave-help-frame))
- (if (and idlwave-experimental
- (frame-live-p idlwave-help-return-frame))
- ;; Try to select the return frame.
- ;; This can crash on slow network connections, obviously when
- ;; we kill the help frame before the return-frame is selected.
- ;; To protect the workings, we wait for up to one second
- ;; and check if the return-frame *is* now selected.
- ;; This is marked "experimental" since we are not sure when
- ;; it's OK.
- (let ((maxtime 1.0) (time 0.) (step 0.1))
- (select-frame idlwave-help-return-frame)
- (while (and (sit-for step)
- (not (eq (selected-frame)
- idlwave-help-return-frame))
- (< (setq time (+ time step)) maxtime)))))
- (delete-frame idlwave-help-frame))
- ((window-configuration-p idlwave-help-window-configuration)
- (set-window-configuration idlwave-help-window-configuration)
- (select-window (previous-window)))
- (t (kill-buffer (idlwave-help-get-help-buffer)))))
-
-
-(defvar default-toolbar-visible-p)
-
-(defun idlwave-help-display-help-window (&optional pos-or-func)
- "Display the help window.
-Move window start to POS-OR-FUNC, if passed as a position, or call it
-if passed as a function. See `idlwave-help-use-dedicated-frame'."
- (let ((cw (selected-window))
- (buf (idlwave-help-get-help-buffer)))
- (if (and window-system idlwave-help-use-dedicated-frame)
- (progn
- (idlwave-help-show-help-frame)
- (switch-to-buffer buf))
- ;; Do it in this frame and save the window configuration
- (if (not (get-buffer-window buf nil))
- (setq idlwave-help-window-configuration
- (current-window-configuration)))
- (display-buffer buf nil (selected-frame))
- (select-window (get-buffer-window buf)))
- (raise-frame)
- (if pos-or-func
- (if (functionp pos-or-func)
- (funcall pos-or-func)
- (goto-char pos-or-func)
- (recenter 0)))
- (select-window cw)))
-
-(defun idlwave-help-select-help-frame ()
- "Select the help frame."
- (if (and (frame-live-p idlwave-help-frame)
- (not (eq (selected-frame) idlwave-help-frame)))
- (progn
- (setq idlwave-help-return-frame (selected-frame))
- (select-frame idlwave-help-frame))))
-
-(defun idlwave-help-return-to-calling-frame ()
- "Select the frame from which the help frame was selected."
- (interactive)
- (if (and (frame-live-p idlwave-help-return-frame)
- (not (eq (selected-frame) idlwave-help-return-frame)))
- (select-frame idlwave-help-return-frame)))
-
-(defun idlwave-online-help (link &optional name type class keyword)
- "Display HTML or other special help on a certain topic.
-Either loads an HTML link, if LINK is non-nil, or gets special-help on
-the optional arguments, if any special help is defined. If LINK is
-t, first look up the optional arguments in the routine info list to
-see if a link is set for it. Try extra help functions if necessary."
- ;; Lookup link
- (if (eq link t)
- (let ((entry (idlwave-best-rinfo-assoc name type class
- (idlwave-routines) nil t)))
- (if entry
- (cond
- ;; Try keyword link
- ((and keyword
- (setq link (cdr
- (idlwave-entry-find-keyword entry keyword)))))
- ;; Default, regular entry link
- (t (setq link (idlwave-entry-has-help entry))))
- (if (and
- class
- ;; Check for system class help
- (setq entry (assq (idlwave-sintern-class class)
- idlwave-system-class-info)
- link (nth 1 (assq 'link entry))))
- (message
- (concat "No routine info for %s"
- ", falling back on class help.")
- (idlwave-make-full-name class name))))))
-
- (cond
- ;; An explicit link
- ((stringp link)
- (idlwave-help-html-link link))
-
- ;; Any extra help
- (idlwave-extra-help-function
- (idlwave-help-get-special-help name type class keyword))
-
- ;; Nothing worked
- (t (idlwave-help-error name type class keyword))))
-
-
-(defun idlwave-help-get-special-help (name type class keyword)
- "Call the function given by `idlwave-extra-help-function'."
- (let* ((cw (selected-window))
- (help-pos (with-current-buffer (idlwave-help-get-help-buffer)
- (let ((buffer-read-only nil))
- (funcall idlwave-extra-help-function
- name type class keyword)))))
- (if help-pos
- (idlwave-help-display-help-window help-pos)
- (idlwave-help-error name type class keyword))
- (select-window cw)))
-
-(defun idlwave-help-html-link (link)
- "Get HTML help on a given LINK."
- (let ((browse-url-browser-function idlwave-help-browser-function)
- (help-loc (idlwave-html-help-location))
- (browse-url-generic-program idlwave-help-browser-generic-program)
- ;(browse-url-generic-args idlwave-help-browser-generic-args)
- full-link)
-
- ;; Just a regular file name (+ anchor name)
- (unless (and (stringp help-loc)
- (file-directory-p help-loc))
- (error "Invalid help location"))
- (setq full-link (browse-url-file-url (expand-file-name link help-loc)))
-
- ;; Select the browser
- (cond
- (idlwave-help-use-assistant
- (idlwave-help-assistant-open-link link))
-
- ((or idlwave-help-browser-is-local
- (string-match "w3" (symbol-name idlwave-help-browser-function)))
- (idlwave-help-display-help-window (lambda () (browse-url full-link))))
-
- (t (browse-url full-link)))))
-
-;; A special help routine for source-level syntax help in files.
-(defvar idlwave-help-fontify-source-code)
-(defvar idlwave-help-source-try-header)
-(defvar idlwave-current-tags-buffer)
-(defvar idlwave-current-tags-class)
-(defun idlwave-help-with-source (name type class keyword)
- "Provide help for routines not documented in the IDL manuals.
-Works by loading the routine source file into the help buffer.
-Depending on the value of `idlwave-help-source-try-header', it
-attempts to show the routine definition or the header description.
-If `idlwave-help-do-class-struct-tag' is non-nil, keyword is a tag
-to show help on from the class definition structure.
-If `idlwave-help-do-struct-tag' is non-nil, show help from the
-matching structure tag definition.
-
-This function can be used as `idlwave-extra-help-function'."
- (let* ((class-struct-tag idlwave-help-do-class-struct-tag)
- (struct-tag idlwave-help-do-struct-tag)
- (case-fold-search t)
- (real-class (if (consp name) (cdr name)))
- (name (if (consp name) (car name) name))
- (class-only (and (stringp class) (not (stringp name))))
- file header-pos def-pos in-buf)
- (if class-only ;Help with class? Using "Init" as source.
- (setq name "Init"
- type 'fun))
- (if (not struct-tag)
- (setq file
- (idlwave-routine-source-file
- (nth 3 (idlwave-best-rinfo-assoc
- name (or type t) class (idlwave-routines))))))
- (setq idlwave-help-def-pos nil
- idlwave-help-args (list name type class keyword)
- idlwave-help-in-header nil
- idlwave-help-do-struct-tag nil
- idlwave-help-do-class-struct-tag nil)
- (if (or struct-tag (stringp file))
- (progn
- (setq in-buf ; structure-tag completion is always in current buffer
- (if struct-tag
- idlwave-current-tags-buffer
- (find-buffer-visiting file)))
- ;; see if file is in a visited buffer, insert those contents
- (if in-buf
- (progn
- (setq file (buffer-file-name in-buf))
- (erase-buffer)
- (insert-buffer-substring in-buf))
- (if (file-exists-p file) ;; otherwise just load the file
- (progn
- (erase-buffer)
- (insert-file-contents file nil nil nil 'replace))
- (idlwave-help-error name type class keyword)))
- (goto-char (point-min))
- (if (and idlwave-help-fontify-source-code (not in-buf))
- (idlwave-help-fontify)))
- (idlwave-help-error name type class keyword))
- (setq idlwave-help-mode-line-indicator file)
-
- ;; Try to find a good place to display
- (setq def-pos
- ;; Find the class structure tag if that's what we're after
- (cond
- ;; Class structure tags: find the class or named structure
- ;; definition
- (class-struct-tag
- (save-excursion
- (setq class
- (if (string-match "[a-zA-Z0-9]\\(__\\)" name)
- (substring name 0 (match-beginning 1))
- idlwave-current-tags-class))
- (and
- (idlwave-find-class-definition class nil real-class)
- (idlwave-find-struct-tag keyword))))
-
- ;; Generic structure tags: the structure definition
- ;; location within the file has been recorded in
- ;; `struct-tag'
- (struct-tag
- (save-excursion
- (and
- (integerp struct-tag)
- (goto-char struct-tag)
- (idlwave-find-struct-tag keyword))))
-
- ;; Just find the routine definition
- (t
- (if class-only (point-min)
- (idlwave-help-find-routine-definition name type class keyword))))
- idlwave-help-def-pos def-pos)
-
- (if (and idlwave-help-source-try-header
- (not (or struct-tag class-struct-tag)))
- ;; Check if we can find the header
- (save-excursion
- (goto-char (or def-pos (point-max)))
- (setq header-pos (idlwave-help-find-in-doc-header
- name type class keyword 'exact)
- idlwave-help-in-header header-pos)))
-
- (if (or header-pos def-pos)
- (progn
- (if (boundp 'idlwave-help-min-frame-width)
- (setq idlwave-help-min-frame-width 80))
- (goto-char (or header-pos def-pos)))
- (idlwave-help-error name type class keyword))
-
- (point)))
-
-
-(defun idlwave-help-find-routine-definition (name type class _keyword)
- "Find the definition of routine CLASS::NAME in current buffer.
-Returns the point of match if successful, nil otherwise.
-KEYWORD is ignored."
- (save-excursion
- (goto-char (point-max))
- (if (re-search-backward
- (concat "^[ \t]*"
- (if (eq type 'pro) "pro"
- (if (eq type 'fun) "function"
- "\\(pro\\|function\\)"))
- "[ \t]+"
- (regexp-quote (downcase (idlwave-make-full-name class name)))
- "[, \t\r\n]")
- nil t)
- (match-beginning 0)
- nil)))
-
-(defvar idlwave-doclib-start)
-(defvar idlwave-doclib-end)
-(defun idlwave-help-find-in-doc-header (name _type class keyword
- &optional exact)
- "Find the requested help in the doc-header above point.
-
-First checks if there is a doc-lib header which describes the correct
-routine. Then tries to find the KEYWORDS section and the KEYWORD, if
-given. Returns the point which should be window start of the help
-window. If EXACT is non-nil, the full help position must be found -
-down to the keyword requested. This setting is for context help, if
-the exact spot is needed.
-
-If EXACT is nil, the position of the header is returned if it
-describes the correct routine - even if the keyword description cannot
-be found. TYPE is ignored.
-
-This function expects a more or less standard routine header. In
-particular it looks for the `NAME:' tag, either with a colon, or alone
-on a line. Then `NAME:' must be followed by the routine name on the
-same or the next line. When KEYWORD is non-nil, looks first for a
-`KEYWORDS' section. It is amazing how inconsistent this is through
-some IDL libraries I have seen. We settle for a line containing an
-upper case \"KEYWORD\" string. If this line is not found we search
-for the keyword anyway to increase the hit-rate
-
-When one of these sections exists we check for a line starting with any of
-
- /KEYWORD KEYWORD- KEYWORD= KEYWORD
-
-with spaces allowed between the keyword and the following dash or equal sign.
-If there is a match, we assume it is the keyword description."
- (let* ((case-fold-search t)
- (rname (if (stringp class)
- (concat
- "\\("
- ;; Traditional name or class::name
- "\\("
- "\\(" (regexp-quote (downcase class)) "::\\)?"
- (regexp-quote (downcase name))
- "\\>\\)"
- (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))
- "<unknown>")
- (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
+++ /dev/null
-;;; 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 <jd.smith@utoledo.edu>
-;; Carsten Dominik <dominik@astro.uva.nl>
-;; Chris Chase <chase@att.com>
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; 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'.
-;;
-;;--------------------------------------------------------------------------
-;;
-\f
-;;; 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
- '("^<onechar>$" "^<chars>$" "^</chars>$")
- "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,\\='<chars>\\=' ; Make IDLWAVE switch to character mode
- REPEAT BEGIN
- A = GET_KBRD(1)
- PRINT, BYTE(A)
- ENDREP UNTIL A EQ \\='q\\='
- print,\\='</chars>\\=' ; Make IDLWAVE switch back to line mode
-
- print,\\='Quit the program, y or n?\\='
- print,\\='<onechar>\\=' ; 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,\\='<chars>\\=' $
- else if keyword_set(off) then print,\\='</chars>\\=' $
- else print,\\='<onechar>\\='
- 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 "\\<end\\>")))
- (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
+++ /dev/null
-;;; idlw-toolbar.el --- a debugging toolbar for IDLWAVE -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1999-2024 Free Software Foundation, Inc.
-
-;; Author: Carsten Dominik <dominik@astro.uva.nl>
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; 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
-
-\f
-;;; 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
+++ /dev/null
-;;; idlwave.el --- IDL editing mode for GNU Emacs -*- lexical-binding: t; -*-
-
-;; Copyright (C) 1999-2024 Free Software Foundation, Inc.
-
-;; Authors: JD Smith <jd.smith@utoledo.edu>
-;; Carsten Dominik <dominik@science.uva.nl>
-;; Chris Chase <chase@att.com>
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; 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 <dickow_at_nbi.dk>
-;; Eric E. Dors <edors_at_lanl.gov>
-;; Stein Vidar H. Haugan <s.v.h.haugan_at_astro.uio.no>
-;; David Huenemoerder <dph_at_space.mit.edu>
-;; Kevin Ivory <Kevin.Ivory_at_linmpi.mpg.de>
-;; Dick Jackson <dick_at_d-jackson.com>
-;; Xuyong Liu <liu_at_stsci.edu>
-;; Simon Marshall <Simon.Marshall_at_esrin.esa.it>
-;; Laurent Mugnier <mugnier_at_onera.fr>
-;; Lubos Pochman <lubos_at_rsinc.com>
-;; Bob Portmann <portmann_at_al.noaa.gov>
-;; Patrick M. Ryan <pat_at_jaameri.gsfc.nasa.gov>
-;; Marty Ryba <ryba_at_ll.mit.edu>
-;; Paul Sorenson <aardvark62_at_msn.com>
-;; Phil Sterne <sterne_at_dublin.llnl.gov>
-;; Phil Williams <williams_at_irc.chmcc.org>
-;;
-;; 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.
-;;
-\f
-;;; 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 <Class1,Class2,Class3>
-
-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 "\\<common\\>[ \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 <simon_at_gnu.ai.mit.edu>
-;;; 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
- '("\\({\\|\\<inherits\\s-\\)\\s-*\\([a-zA-Z][a-zA-Z0-9_]*\\)[},\t \n]"
- (2 font-lock-function-name-face)))
-
- ;; Keyword parameters, like /xlog or ,xrange=[]
- ;; This is anchored to the comma preceding the keyword.
- ;; Treats continuation lines, works only during whole buffer
- ;; fontification. Slow, use it only in fancy fontification.
- (keyword-parameters
- '("\\(,\\|[a-zA-Z0-9_](\\)[ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\([ \t]*\\(;.*\\)?\n\\)*[ \t]*\\)?\\(/[a-zA-Z_]\\sw*\\|[a-zA-Z_]\\sw*[ \t]*=\\)"
- (6 font-lock-constant-face)))
-
- ;; System variables start with a bang.
- (system-variables
- '("\\(![a-zA-Z_0-9]+\\(\\.\\sw+\\)?\\)"
- (1 font-lock-variable-name-face)))
-
- ;; Special and unusual operators (not used because too noisy)
- ;; (special-operators
- ;; '("[<>#]" (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
- "\\<end\\(\\|case\\|switch\\|else\\|for\\|if\\|rep\\|while\\)\\>"
- "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 "\\<else\\>" 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 '(("\\<if\\>" . "[ \t]*then")
- ("\\<\\(if\\|end\\(if\\)?\\)\\>" . "[ \t]*else")
- ("\\<\\(for\\|while\\)\\>" . "[ \t]*do")
- ("\\<\\(repeat\\|end\\(rep\\)?\\)\\>" .
- "[ \t]*until")
- ("\\<case\\>" . "[ \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 '("\\<then\\>"
- "\\<do\\>"
- "\\<repeat\\>"
- "\\<else\\>"))
- 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 "\\<inherits\\s-+[a-zA-Z0-9$_]*\\'"
- match-string)
- (setq cw 'class))
- ((and func
- (> 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) "<p>" "<f>"))
- "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) "<p>" "<f>")))))
- (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