idlwave.el 343 KB
Newer Older
1
;; idlwave.el --- IDL editing mode for GNU Emacs
Glenn Morris's avatar
Glenn Morris committed
2

3 4
;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
;;   2008, 2009  Free Software Foundation, Inc.
5

6
;; Authors: J.D. Smith <jdsmith@as.arizona.edu>
Richard M. Stallman's avatar
Richard M. Stallman committed
7
;;          Carsten Dominik <dominik@science.uva.nl>
8
;;          Chris Chase <chase@att.com>
9
;; Maintainer: J.D. Smith <jdsmith@as.arizona.edu>
10
;; Version: 6.1_em22
11 12
;; Keywords: languages

13
;; This file is part of GNU Emacs.
14

15
;; GNU Emacs is free software: you can redistribute it and/or modify
16
;; it under the terms of the GNU General Public License as published by
17 18
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
19 20 21 22 23 24 25

;; 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
26
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
27 28 29

;;; Commentary:

30 31 32 33
;; 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.
34

35 36
;; In the remotely distant past, based on pascal.el, though bears
;; little resemblance to it now.
37 38 39 40 41 42 43 44 45
;;
;; 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'
;;
46 47 48
;; New versions of IDLWAVE, documentation, and more information
;; available from:
;;                 http://idlwave.org
49 50 51 52 53 54 55 56 57
;;
;; INSTALLATION
;; ============
;;
;; Follow the instructions in the INSTALL file of the distribution.
;; In short, put this file on your load path and add the following
;; lines to your .emacs file:
;;
;; (autoload 'idlwave-mode "idlwave" "IDLWAVE Mode" t)
58
;; (autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t)
59 60 61 62 63 64
;; (setq auto-mode-alist (cons '("\\.pro\\'" . idlwave-mode) auto-mode-alist))
;;
;;
;; SOURCE
;; ======
;;
65
;; The newest version of this file is available from the maintainer's
66
;; Webpage:
67
;;
68
;;   http://idlwave.org
69 70 71 72
;;
;; DOCUMENTATION
;; =============
;;
73 74 75
;; IDLWAVE is documented online in info format.  A printable version
;; of the documentation is available from the maintainers webpage (see
;; SOURCE).
76
;;
77
;;
78 79 80 81 82
;; ACKNOWLEDGMENTS
;; ===============
;;
;;  Thanks to the following people for their contributions and comments:
;;
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
;;    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>
99 100 101 102
;;
;; CUSTOMIZATION:
;; =============
;;
103 104 105
;; IDLWAVE has extensive customize support; to learn about the
;; variables which control the mode's behavior, use `M-x
;; idlwave-customize'.
106 107 108
;;
;; 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
109 110
;; the TexInfo documentation or see a complete .emacs available at the
;; website.
111 112 113 114
;;
;; KNOWN PROBLEMS:
;; ==============
;;
115 116 117
;;   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
118
;;   even have "WAVE" in its title, but it's catchy, and was required
119
;;   to avoid conflict with the CORBA idl.el mode.  Caveat WAVEor.
120
;;
121 122 123 124 125 126
;;   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
127
;;   using a temporary function in `post-command-hook' - not pretty,
128
;;   but it works.
129 130 131 132 133 134 135 136
;;
;;   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'.
;;
137 138 139 140
;;   Muti-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.
141
;;
142 143 144
;;   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
145
;;   a pre-selected region.
146 147 148
;;
;;   When forcing completion of method keywords, the initial
;;   query for a method has multiple entries for some methods.  Would
149
;;   be too difficult to fix this hardly used case.
150 151 152 153
;;

;;; Code:

154

155
(eval-when-compile (require 'cl))
156 157 158 159 160 161 162 163 164
(require 'idlw-help)

;; For XEmacs
(unless (fboundp 'line-beginning-position)
  (defalias 'line-beginning-position 'point-at-bol))
(unless (fboundp 'line-end-position)
  (defalias 'line-end-position 'point-at-eol))
(unless (fboundp 'char-valid-p)
  (defalias 'char-valid-p 'characterp))
165 166
(unless (fboundp 'match-string-no-properties)
  (defalias 'match-string-no-properties 'match-string))
167

168 169 170 171 172
(if (not (fboundp 'cancel-timer))
    (condition-case nil
	(require 'timer)
      (error nil)))

173 174 175 176 177 178
(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" ())

179
(defgroup idlwave nil
180
  "Major mode for editing IDL .pro files."
181
  :tag "IDLWAVE"
182
  :link '(url-link :tag "Home Page"
183
		   "http://idlwave.org")
184 185
  :link '(emacs-commentary-link :tag "Commentary in idlw-shell.el"
				"idlw-shell.el")
186 187 188 189 190
  :link '(emacs-commentary-link :tag "Commentary in idlwave.el" "idlwave.el")
  :link '(custom-manual "(idlwave)Top")
  :prefix "idlwave"
  :group 'languages)

191

192 193 194 195 196 197
;;; Variables for indentation behavior ---------------------------------------

(defgroup idlwave-code-formatting nil
  "Indentation and formatting options for IDLWAVE mode."
  :group 'idlwave)

198
(defcustom idlwave-main-block-indent 2
199 200 201 202 203 204
  "*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)

205
(defcustom idlwave-block-indent 3
206 207 208 209 210
  "*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)

211
(defcustom idlwave-end-offset -3
212 213 214 215 216 217
  "*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)

218
(defcustom idlwave-continuation-indent 3
219 220
  "*Extra indentation applied to continuation lines.
This extra offset applies to the first of a set of continuation lines.
221 222 223 224
The following lines receive the same indentation as the first."
  :group 'idlwave-code-formatting
  :type 'integer)

225
(defcustom idlwave-max-extra-continuation-indent 40
226 227 228
  "*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
229
parentheses, or assignment statements.  This variable specifies a
230 231 232 233
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
234
cases.  See also `idlwave-indent-to-open-paren', which can override
235
this variable."
236 237 238
  :group 'idlwave-code-formatting
  :type 'integer)

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
(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 `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)

263 264 265 266 267 268 269
(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)


270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
(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-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.
296 297
When the line end falls within a string, string concatenation with the
'+' operator will be used to distribute a long string over lines.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
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 'string)

(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 ---------------------------------------

342 343
(defgroup idlwave-routine-info nil
  "Routine Info options for IDLWAVE mode."
344 345
  :group 'idlwave)

346 347 348 349 350 351 352 353 354
(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 a
usually a good idea.."
  :group 'idlwave-routine-info
  :type 'boolean)
355 356

(defcustom idlwave-init-rinfo-when-idle-after 10
357 358 359 360 361 362 363 364 365 366 367 368 369 370
  "*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."
371 372 373
  :group 'idlwave-routine-info
  :type 'number)

374
(defcustom idlwave-scan-all-buffers-for-routine-info t
375 376 377 378 379 380 381 382 383 384 385 386
  "*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)))
387 388 389 390 391 392

(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."
393
  :group 'idlwave-routine-info
394 395
  :type 'boolean)

396 397 398 399 400 401
(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
J.D. Smith's avatar
J.D. Smith committed
402
\(...)     A list of circumstances. Allowed members are:
403 404 405 406 407 408 409 410 411 412 413 414 415
           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))))
416

417 418 419 420 421 422 423
(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.
t means to show all source files."
  :group 'idlwave-routine-info
  :type 'integer)

424
(defcustom idlwave-library-path nil
425
  "Library path for Windows and MacOS (OS9).  Not needed under UNIX.
426 427 428
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 Windows and MacOS
429
\(pre-OSX), the IDLWAVE shell does not work.  In this case, this
430 431 432 433 434 435
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
preceeded 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'."
436
  :group 'idlwave-routine-info
437 438
  :type '(repeat (directory)))

439
(defcustom idlwave-system-directory ""
440 441 442 443 444 445 446
  "The IDL system directory for Windows and MacOS.  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'."
447 448 449
  :group 'idlwave-routine-info
  :type 'directory)

450
;; Configuration files
451
(defcustom idlwave-config-directory
452 453
  (convert-standard-filename "~/.idlwave")
  "*Directory for configuration files and user-library catalog."
454
  :group 'idlwave-routine-info
455 456
  :type 'file)

457
(defvar idlwave-user-catalog-file "idlusercat.el")
458
(defvar idlwave-xml-system-rinfo-converted-file "idl_xml_rinfo.el")
459 460 461 462 463
(defvar idlwave-path-file "idlpath.el")

(defvar idlwave-libinfo-file nil
  "*Obsolete variable, no longer used.")

464 465 466
(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
467
the file defining the routine is located.  By default it lists `SystemLib'
468 469 470 471 472 473 474 475 476
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)))

477
(defcustom idlwave-auto-write-paths t
478
  "Write out path (!PATH) and system directory (!DIR) info automatically.
479 480 481 482 483
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
484
  :type 'boolean)
485

486 487 488 489 490
(defgroup idlwave-completion nil
  "Completion options for IDLWAVE mode."
  :prefix "idlwave"
  :group 'idlwave)

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
(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
509
methods.
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
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."
537
  :group 'idlwave-completion
538 539 540 541 542 543 544 545 546 547
  :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."
548
  :group 'idlwave-completion
549 550 551 552 553 554 555 556
  :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."
557
  :group 'idlwave-completion
558 559 560 561 562 563 564 565 566 567 568 569
  :type 'boolean)

(defvar idlwave-default-completion-case-is-down nil
  "Obsolete variable.  See `idlwave-complete-empty-string-as-lower-case' and
`idlwave-completion-case'.")

(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."
570 571 572 573 574 575 576 577
  :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
578 579
  :type 'boolean)

580 581
(defcustom idlwave-support-inheritance t
  "Non-nil means, treat inheritance with completion, online help etc.
582
When nil, IDLWAVE only knows about the native methods and tags of a class,
583 584 585 586
not about inherited ones."
  :group 'idlwave-routine-info
  :type 'boolean)

587 588 589 590 591 592 593 594 595
(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:")))
596

597

598 599 600
(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,
601
the *Completions* buffer will show the valid classes for each completion
602 603 604 605 606 607 608 609 610 611 612
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.

On XEmacs, a full list of classes will also be placed into a `help-echo'
property on the competion items, so that the list of classes for the current
item is displayed in the echo area.  If the value of this variable is a
negative integer, the `help-echo' property will be suppressed."
613
  :group 'idlwave-completion
614 615 616 617 618 619 620
  :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'."
621
  :group 'idlwave-completion
622 623 624 625 626 627
  :type 'boolean)

(defcustom idlwave-query-class '((method-default . nil)
				 (keyword-default . nil))
  "Association list governing specification of object classes for completion.

628 629 630
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
631 632 633 634 635 636 637 638 639 640 641 642
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
643
   `idlwave-completion-show-classes'.
644 645 646 647 648 649 650 651 652 653

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'.

654 655 656
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
J.D. Smith's avatar
J.D. Smith committed
657
\(keyword-default . VALUE), where VALUE is either t or nil.  These
658 659
specify if the class should be found during method and keyword
completion, respectively.
660

661
The alist may have additional entries specifying exceptions from the
662 663 664
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."
665
  :group 'idlwave-completion
666 667 668 669 670 671 672 673 674 675 676
  :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")))))

677
(defcustom idlwave-store-inquired-class t
678 679 680 681 682 683 684
  "*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
685
property on the `->' arrow in the source code, so that during the same
686 687 688 689 690 691 692 693 694 695 696 697 698
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."
699
  :group 'idlwave-completion
700 701 702 703 704
  :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
J.D. Smith's avatar
J.D. Smith committed
705
\(see variable `idlwave-store-inquired-class', it highlights the arrow
706
with this font in order to remind the user that this arrow is special."
707
  :group 'idlwave-completion
708 709 710 711
  :type 'symbol)

(defcustom idlwave-resize-routine-help-window t
  "*Non-nil means, resize the Routine-info *Help* window to fit the content."
712
  :group 'idlwave-completion
713 714 715 716
  :type 'boolean)

(defcustom idlwave-keyword-completion-adds-equal t
  "*Non-nil means, completion automatically adds `=' after completed keywords."
717
  :group 'idlwave-completion
718 719 720 721
  :type 'boolean)

(defcustom idlwave-function-completion-adds-paren t
  "*Non-nil means, completion automatically adds `(' after completed function.
Pavel Janík's avatar
Pavel Janík committed
722
nil means, don't add anything.
723 724
A value of `2' means, also add the closing parenthesis and position cursor
between the two."
725
  :group 'idlwave-completion
726 727 728 729 730 731 732 733 734
  :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."
735
  :group 'idlwave-completion
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
  :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 chose 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 .emacs 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'.
765
If non-nil, `=',`<',`>',`&',`,', `->' are surrounded with spaces by
766 767 768 769 770 771 772 773 774 775 776 777 778
`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
779 780 781 782 783
  "*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."
784
  :group 'idlwave-abbrev-and-indent-action
785 786 787 788
  :type '(choice
	  (const :tag "Pad like assignments" t)
	  (const :tag "Remove space near `='" nil)
	  (const :tag "Keep space near `='" 'keep)))
789 790 791 792 793 794 795 796 797 798 799

(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)

800 801 802 803 804
(defcustom idlwave-reindent-end t
  "*Non-nil means re-indent line after END was typed."
  :group 'idlwave-abbrev-and-indent-action
  :type 'boolean)

805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
(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-check-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 '(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)
;;  Capitalize label
;;   (idlwave-action-and-binding (concat "^[ \t]*" idlwave-label)
;;                           '(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.
Pavel Janík's avatar
Pavel Janík committed
955
Otherwise STRING is used. If nil, the file summary will be omitted.
956 957 958
For example you might set PATHNAME to the path for the
lib_template.pro file included in the IDL distribution.")

959
(defcustom idlwave-header-to-beginning-of-file t
960 961 962 963 964 965 966
  "*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)

967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
(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
993
  "Path locations of external commands used by IDLWAVE."
994 995 996
  :group 'idlwave)

(defcustom idlwave-shell-explicit-file-name "idl"
997
  "*If non-nil, this is the command to run IDL.
998
Should be an absolute file path or path relative to the current environment
999 1000 1001 1002 1003
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 compromizing backwards-compatibility."
1004 1005 1006 1007
  :group 'idlwave-external-programs
  :type 'string)

(defcustom idlwave-shell-command-line-options nil
1008 1009 1010 1011 1012 1013 1014 1015 1016
  "*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 "")))
1017 1018 1019
  :group 'idlwave-external-programs)

(defcustom idlwave-help-application "idlhelp"
1020 1021
  "*The external application providing reference help for programming.
Obsolete, if the IDL Assistant is being used for help."
1022 1023 1024
  :group 'idlwave-external-programs
  :type 'string)

1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
;;; 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)

1051 1052 1053 1054
;;; Miscellaneous variables -------------------------------------------------

(defgroup idlwave-misc nil
  "Miscellaneous options for IDLWAVE mode."
1055
  :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
1056 1057 1058 1059 1060 1061 1062
  :group 'idlwave)

(defcustom idlwave-startup-message t
  "*Non-nil displays a startup message when `idlwave-mode' is first called."
  :group 'idlwave-misc
  :type 'boolean)

1063
(defcustom idlwave-default-font-lock-items
J.D. Smith's avatar
J.D. Smith committed
1064
  '(pros-and-functions batch-files idlwave-idl-keywords label goto
1065 1066 1067 1068 1069 1070 1071 1072 1073
		       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
J.D. Smith's avatar
J.D. Smith committed
1074
idlwave-idl-keywords IDL Keywords
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
label                Statement Labels
goto                 Goto Statements
common-blocks        Common Blocks
keyword-parameters   Keyword Parameters in routine definitions and calls
system-variables     System Variables
fixme                FIXME: Warning in comments (on XEmacs only v. 21.0 and up)
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)
J.D. Smith's avatar
J.D. Smith committed
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
	  (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 "FIXME: Warning"                    fixme)
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
	  (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)

1108 1109 1110 1111 1112 1113
(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.")

1114 1115 1116 1117 1118 1119 1120
;;;
;;; End customization variables section
;;;

;;; Non customization variables

;;; font-lock mode - Additions by Phil Williams, Ulrik Dickow and
1121
;;; Simon Marshall <simon_at_gnu.ai.mit.edu>
1122 1123
;;; and Carsten Dominik...

1124
;; The following are the reserved words in IDL.  Maybe we should
1125
;; highlight some more stuff as well?
1126 1127
;; Procedure declarations.  Fontify keyword plus procedure name.
(defvar idlwave-idl-keywords
1128
  ;; To update this regexp, update the list of keywords and
1129
  ;; evaluate the form.
1130
  ;;	(insert
1131
  ;;	 (prin1-to-string
1132
  ;;	  (concat
1133
  ;;	   "\\<\\("
1134
  ;;	   (regexp-opt
1135
  ;;	    '("||" "&&" "and" "or" "xor" "not"
1136
  ;;	      "eq" "ge" "gt" "le" "lt" "ne"
1137
  ;;	      "for" "do" "endfor"
1138
  ;;	      "if" "then" "endif" "else" "endelse"
1139 1140 1141 1142
  ;;	      "case" "of" "endcase"
  ;;	      "switch" "break" "continue" "endswitch"
  ;;	      "begin" "end"
  ;;	      "repeat" "until" "endrep"
1143
  ;;	      "while" "endwhile"
1144 1145 1146 1147 1148
  ;;	      "goto" "return"
  ;;	      "inherits" "mod"
  ;;	      "compile_opt" "forward_function"
  ;;	      "on_error" "on_ioerror"))  ; on_error is not officially reserved
  ;;	   "\\)\\>")))
1149 1150
  "\\<\\(&&\\|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\\|||\\)\\>")

1151

J.D. Smith's avatar
J.D. Smith committed
1152
(let* (;; Procedure declarations.  Fontify keyword plus procedure name.
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
       ;; 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-reference-face nil t)      ; block name
1164
	  ("[ \t]*\\(\\sw+\\)[ ,]*"
1165
	   ;; Start with point after block name and comma
1166
	   (goto-char (match-end 0))  ; needed for XEmacs, could be nil
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
	   nil
	   (1 font-lock-variable-name-face)       ; variable names
	   )))

       ;; Batch files
       (batch-files
	'("^[ \t]*\\(@[^ \t\n]+\\)" (1 font-lock-string-face)))

       ;; FIXME warning.
       (fixme
	'("\\<FIXME:" (0 font-lock-warning-face t)))

       ;; Labels
       (label
	'("^[ \t]*\\([a-zA-Z]\\sw*:\\)" (1 font-lock-reference-face)))

       ;; The goto statement and its label
       (goto
	'("\\(goto\\)[ \t]*,[ \t]*\\([a-zA-Z]\\sw*\\)"
	  (1 font-lock-keyword-face)
	  (2 font-lock-reference-face)))

1189 1190 1191 1192
       ;; 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.
1193 1194 1195 1196 1197 1198 1199 1200
       (structtag
	'("\\<\\([a-zA-Z][a-zA-Z0-9_]*:\\)[^:]" (1 font-lock-reference-face)))

       ;; Structure names
       (structname
	'("\\({\\|\\<inherits\\s-\\)\\s-*\\([a-zA-Z][a-zA-Z0-9_]*\\)[},\t \n]"
	  (2 font-lock-function-name-face)))

1201
       ;; Keyword parameters, like /xlog or ,xrange=[]
1202
       ;; This is anchored to the comma preceeding the keyword.
1203 1204
       ;; Treats continuation lines, works only during whole buffer
       ;; fontification.  Slow, use it only in fancy fontification.
1205
       (keyword-parameters
1206 1207
	'("\\(,\\|[a-zA-Z0-9_](\\)[ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\([ \t]*\\(;.*\\)?\n\\)*[ \t]*\\)?\\(/[a-zA-Z_]\\sw*\\|[a-zA-Z_]\\sw*[ \t]*=\\)"
	  (6 font-lock-reference-face)))
1208

1209
       ;; System variables start with a bang.
1210
       (system-variables
1211
	'("\\(![a-zA-Z_0-9]+\\(\\.\\sw+\\)?\\)"
1212 1213 1214 1215 1216 1217 1218 1219 1220
	  (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)))
1221

1222 1223
       ;; Arrows with text property `idlwave-class'
       (class-arrows
J.D. Smith's avatar
J.D. Smith committed
1224 1225 1226 1227 1228
	'(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.")
1229

J.D. Smith's avatar
J.D. Smith committed
1230 1231 1232
  (defconst idlwave-font-lock-keywords-2
    (mapcar 'symbol-value idlwave-default-font-lock-items)
    "Medium level highlighting for IDLWAVE mode.")
1233

J.D. Smith's avatar
J.D. Smith committed
1234
  (defconst idlwave-font-lock-keywords-3
1235 1236
	(list pros-and-functions
	      batch-files
1237
	      idlwave-idl-keywords
1238
	      label goto
1239 1240
	      structtag
	      structname
1241 1242 1243
	      common-blocks
	      keyword-parameters
	      system-variables
J.D. Smith's avatar
J.D. Smith committed
1244 1245
	  class-arrows)
    "Gaudy level highlighting for IDLWAVE mode."))
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257

(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
1258
     idlwave-font-lock-keywords-1
1259 1260
     idlwave-font-lock-keywords-2
     idlwave-font-lock-keywords-3)
1261 1262
    nil t
    ((?$ . "w") (?_ . "w") (?. . "w") (?| . "w") (?& . "w"))
1263 1264
    beginning-of-line))

1265
(put 'idlwave-mode 'font-lock-defaults
1266 1267 1268 1269 1270 1271 1272
     idlwave-font-lock-defaults) ; XEmacs

(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.")

1273
(defconst idlwave-begin-block-reg
1274
  "\\<\\(pro\\|function\\|begin\\|case\\|switch\\)\\>"
1275 1276 1277
  "Regular expression to find the beginning of a block. The case does
not matter. The search skips matches in comments.")

1278
(defconst idlwave-begin-unit-reg "^\\s-*\\(pro\\|function\\)\\>\\|\\`"
1279 1280 1281
  "Regular expression to find the beginning of a unit. The case does
not matter.")

1282
(defconst idlwave-end-unit-reg "^\\s-*\\(pro\\|function\\)\\>\\|\\'"
1283 1284 1285 1286 1287 1288 1289 1290
  "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
1291
  "\\<end\\(\\|case\\|switch\\|else\\|for\\|if\\|rep\\|while\\)\\>"
1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
  "Regular expression to find the end of a block. The case does
not matter. The search skips matches found in comments.")

(defconst idlwave-block-matches
  '(("pro"      . "end")
    ("function" . "end")
    ("case"     . "endcase")
    ("else"     . "endelse")
    ("for"      . "endfor")
    ("then"     . "endif")
    ("repeat"   . "endrep")
1303
    ("switch"   . "endswitch")
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
    ("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'")

1318
(defconst idlwave-identifier "[a-zA-Z_][a-zA-Z0-9$_]*"
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
  "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.")

1330 1331 1332 1333
(defconst idlwave-method-call (concat idlwave-identifier  "\\s *->"
				      "\\(\\s *" idlwave-identifier "::\\)?"
))

1334 1335
(defconst idlwave-statement-match
  (list
Juanma Barranquero's avatar
Juanma Barranquero committed
1336
   ;; "endif else" is the only possible "end" that can be
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
   ;; 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))
1349
   '(switch . ("switch\\>" nil))
1350
   (cons 'call (list (concat "\\(" idlwave-variable "\\) *= *"
1351 1352 1353
			     "\\(" idlwave-method-call "\\s *\\)?"
			     idlwave-identifier
			     "\\s *(") nil))
1354
   (cons 'call (list (concat
1355
		      "\\(" idlwave-method-call "\\s *\\)?"
1356
		      idlwave-identifier
1357
		      "\\( *\\($\\|\\$\\)\\|\\s *,\\)") nil))
1358
   (cons 'assign (list (concat
1359
			"\\(" idlwave-variable "\\) *=") nil)))
1360

1361 1362