GNU bug report logs - #69171
[JD Smith] Moving packages out of core to ELPA

Previous Next

Package: elpa;

Reported by: Stefan Kangas <stefankangas <at> gmail.com>

Date: Sat, 17 Feb 2024 17:50:01 UTC

Severity: normal

To reply to this bug, email your comments to 69171 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to jdtsmith <at> gmail.com, elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 17 Feb 2024 17:50:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Stefan Kangas <stefankangas <at> gmail.com>:
New bug report received and forwarded. Copy sent to jdtsmith <at> gmail.com, elpa-maintainers <at> gnu.org. (Sat, 17 Feb 2024 17:50:01 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: submit <at> debbugs.gnu.org
Subject: [JD Smith] Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 12:47:59 -0500
Package: elpa

See the below request to add idlwave to ELPA.

JD, how should we add it?  Do you have a git repository where it is
being developed?  If yes, we could synch it from there.

-------------------- Start of forwarded message --------------------
From: JD Smith <jdtsmith <at> gmail.com>
Subject: Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 09:40:19 -0500
To: emacs-devel <emacs-devel <at> gnu.org>

There was a recent discussion about which lisp/progmodes packages
belong in core.  A sentiment was expressed that useful languages with
non-negligible user bases should probably go in, and others should be
in ELPA.

I want to bring up a related point: it should be possible to retire
packages from core, once their relevance drops below a critical
threshold [1].

I am the former maintainer of the now mostly defunct IDLWAVE mode
(lisp/progmodes/idl*.el).  IDLWAVE was put in core about 20 years ago,
long before ELPA existed, by my predecessor Carsten Dominik (of
org-mode fame).  I'd advocate moving IDLWAVE to ELPA, for the
following reasons:

The proprietary IDL
<https://en.wikipedia.org/wiki/IDL_(programming_language)> is a
language in rapid decline.  In my field (astrophysics), its use is now
relegated to older professionals who have not switched to Python (but
most of whom wish they had the time to do so).
IDL's holding company has changed approximately 5 times in the last 10
years, such that the link to its website on Wikipedia isn't even
correct.
None of the free IDL alternatives have really caught on.  IDL's costs
and licensing restrictions have gotten more onerous over the years.
IDL is also the "interface description language", confusing users of
that unrelated system.
IDL's file extension ".pro" is quite common, and in use for several
other file types, including Qt's UI build system
<https://doc.qt.io/qt-6/qmake-project-files.html> as well as
Yarn2/Prolog (which org babel plugin ob-prolog
<https://github.com/ljos/ob-prolog> supports).
Some of the best features in IDLWAVE (e.g. direct documentation
linking) required maintenance support from IDL's owners, support which
hasn't fully existed for almost a decade.
The version in core has diverged from the latest
<https://github.com/jdtsmith/idlwave> (from 7 years ago).

Judging by my email traffic on the topic, there are very few users of
IDLWAVE remaining.  Even I touch it only a few times a year.  No one
has stepped up to maintain it in the 7 years since I stepped aside.
IDL is still a powerful language and IDLWAVE itself has a great number
of features I sorely miss in other emacs programming modes.  It
deserves support in Emacs.  Just not, IMO, in core.

[1] Such a threshold may be hard to define, but here is one idea: if
the number of users who activate a mode on accident
<https://www.reddit.com/r/emacs/comments/qefx8e/til_idl_is_a_thing_and_emacs_has_it/>
is greater than the number who actively seek to do so, it may be time
to retire a mode.  My experience indicates IDLWAVE has likely passed
this threshold.




Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 17 Feb 2024 18:20:02 GMT) Full text and rfc822 format available.

Message #8 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Kangas <stefankangas <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org
Subject: Re: bug#69171: [JD Smith] Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 13:17:33 -0500
[Message part 1 (text/plain, inline)]
Yes at https://github.com/jdtsmith/idlwave.  The repo is archived but I presume that does not prevent cloning.  If there are simple changes I can unarchive and make them.  

--

> On Feb 17, 2024, at 12:49 PM, Stefan Kangas <stefankangas <at> gmail.com> wrote:
> Package: elpa
> 
> See the below request to add idlwave to ELPA.
> 
> JD, how should we add it?  Do you have a git repository where it is
> being developed?  If yes, we could synch it from there.
[Message part 2 (text/html, inline)]

Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 17 Feb 2024 21:12:01 GMT) Full text and rfc822 format available.

Message #11 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: jdtsmith <at> gmail.com
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 16:10:48 -0500
> I want to bring up a related point: it should be possible to retire
> packages from core, once their relevance drops below a critical
> threshold [1].

There can be other reasons for doing that, but: yes!

> I'd advocate moving IDLWAVE to ELPA, for the following reasons:

Sounds good, I'll add it GNU ELPA.
There remains the question about how to remove it from Emacs.

> [1] Such a threshold may be hard to define, but here is one idea: if
> the number of users who activate a mode on accident
> <https://www.reddit.com/r/emacs/comments/qefx8e/til_idl_is_a_thing_and_emacs_has_it/>
> is greater than the number who actively seek to do so, it may be time
> to retire a mode.

🙂


        Stefan





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 17 Feb 2024 22:44:01 GMT) Full text and rfc822 format available.

Message #14 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: jdtsmith <at> gmail.com
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 17:42:50 -0500
>> I'd advocate moving IDLWAVE to ELPA, for the following reasons:
> Sounds good, I'll add it GNU ELPA.

Hmm... I didn't realize the code really forked a long time ago.
I'm not really comfortable replacing Emacs's code with Github's, since
the one on Github lacks many changes.

The last "sync" that I see mentioned dates back to Feb 2014 but already
then the two code bases where quite different.

I think we'd need to make an effort to re-sync the two (more
specifically merge all the Emacs changes into the Github repository,
I don't think the other direction is worth the trouble).

I'm not even sure the Feb 2014 sync means that all previous changes in
Emacs had been reflected into the Github version.

E.g. I took the following commit from Github:

    commit 883208713a36a4deae90df7c4c6fd76e296228ff (HEAD)
    Author: JD Smith <jdtsmith <at> gmail.com>
    Date:   Sun May 12 22:53:02 2013 -0400
    
        Doc/comments fixups.

which is the last commit before the "Major re-organization and cleanup"
and then did:

    for h in $(cd ...emacs/main;
               git log --pretty=oneline lisp/progmodes/idlwave.el |
                   sed 's/ .*//');
    do (cd ...emacs/tmp/; git checkout "$h" >/dev/null 2>&1)
       echo "$h: $(diff -u ...emacs/tmp/lisp/progmodes/ . |
                       grep -v '^Seulement dans' | wc)"
    done

and this suggests that the closest commit on `emacs.git` might be:

    commit 627e0a14e8718945668b246f18053df0f82ed383
    Author: Glenn Morris <rgm <at> gnu.org>
    Date:   Thu Dec 3 17:14:33 2009 +0000
    
        (class): Restore still useful declaration.
        Restore comment that is still relevant.

but the diff is still ~250kB (tho most of it is trivial removal
of trailing whitespace).


        Stefan





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 17 Feb 2024 23:25:01 GMT) Full text and rfc822 format available.

Message #17 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>, jdtsmith <at> gmail.com
Cc: 69171 <at> debbugs.gnu.org
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 18:23:06 -0500
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

> Sounds good, I'll add it GNU ELPA.

Thanks.

> There remains the question about how to remove it from Emacs.

I think we just move it to lisp/obsolete plus the additions to NEWS and
maybe the header of that file.

It's been discussed on emacs-devel starting here:
https://lists.gnu.org/r/emacs-devel/2024-02/msg00570.html




Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sun, 18 Feb 2024 01:01:01 GMT) Full text and rfc822 format available.

Message #20 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 17 Feb 2024 19:59:18 -0500
[Message part 1 (text/plain, inline)]

> On Feb 17, 2024, at 5:42 PM, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
> 
>>> I'd advocate moving IDLWAVE to ELPA, for the following reasons:
>> Sounds good, I'll add it GNU ELPA.
> 
> Hmm... I didn't realize the code really forked a long time ago.
> I'm not really comfortable replacing Emacs's code with Github's, since
> the one on Github lacks many changes.

Yep, this is a known issue.  Back in the day I had no idea how much would be added to the package when it went into core, and that happened without any communication with me, so years would go by.  When I'd notice how many changes had accumulated, I would sync what I could — things like typos and obsoleted functions — usually by hand, but there were lots of conflicts as development had continued and the versions had diverged.  It was frankly a bit frustrating.  I also found many changes to be nitpicky (preferring a certain style, etc.), or they removed backward or other compatibility I felt was still needed (XEmacs was explicitly supported for quite a while, for example).

> The last "sync" that I see mentioned dates back to Feb 2014 but already
> then the two code bases where quite different.

Yes, it was probably one of my by-hand, best-effort sync's, because so much had been added without my involvement.  In hindsight, it might have been easier to develop it fully outside of core, but I believe Carsten made that call before I had taken over from him, and I didn't really understand the implications at that time.

> I think we'd need to make an effort to re-sync the two (more
> specifically merge all the Emacs changes into the Github repository,
> I don't think the other direction is worth the trouble).

I agree.  I think this has even been suggested before, but I don't have the resources to take it on myself (though I'm happy to test it).  Maybe it's quasi-automate-able?  I notice many of the recent changes in core were broad across the board updates to lots of files, presumably with some kind of script; perhaps those could be rerun?

> I'm not even sure the Feb 2014 sync means that all previous changes in
> Emacs had been reflected into the Github version.

Yes, that's probably a fair assessment, as I was often doing these by hand.

> E.g. I took the following commit from Github:
> 
>    commit 883208713a36a4deae90df7c4c6fd76e296228ff (HEAD)
>    Author: JD Smith <jdtsmith <at> gmail.com>
>    Date:   Sun May 12 22:53:02 2013 -0400
> 
>        Doc/comments fixups.
> 
> which is the last commit before the "Major re-organization and cleanup"
> and then did:
> 
>    for h in $(cd ...emacs/main;
>               git log --pretty=oneline lisp/progmodes/idlwave.el |
>                   sed 's/ .*//');
>    do (cd ...emacs/tmp/; git checkout "$h" >/dev/null 2>&1)
>       echo "$h: $(diff -u ...emacs/tmp/lisp/progmodes/ . |
>                       grep -v '^Seulement dans' | wc)"
>    done
> 
> and this suggests that the closest commit on `emacs.git` might be:
> 
>    commit 627e0a14e8718945668b246f18053df0f82ed383
>    Author: Glenn Morris <rgm <at> gnu.org>
>    Date:   Thu Dec 3 17:14:33 2009 +0000
> 
>        (class): Restore still useful declaration.
>        Restore comment that is still relevant.
> 
> but the diff is still ~250kB (tho most of it is trivial removal
> of trailing whitespace).

There honestly hasn't been too much of significance added since that time.  I did the "major re-organization" you mentioned to make it more appealing for a new maintainer to take on 10 years ago (without success, sadly).  One option would be to try to achieve sync up to the commit just prior to that big reorg (which divided things up, creating 6 new files):

883208713a36a4deae90df7c4c6fd76e296228ff
Commit:     JD Smith <jdtsmith <at> gmail.com>
CommitDate: Mon Jan 27 15:27:46 2014 -0500

I guess another even cheaper option would be to take the current version in Emacs, make it a branch in my repo, and draw the ELPA package from that.  That's not ideal given the last date of divergence, but better than nothing I suppose. 

[Message part 2 (text/html, inline)]

Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Mon, 19 Feb 2024 23:08:01 GMT) Full text and rfc822 format available.

Message #23 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Mon, 19 Feb 2024 18:06:27 -0500
[Message part 1 (text/plain, inline)]
> I agree.  I think this has even been suggested before, but I don't have the
> resources to take it on myself (though I'm happy to test it).  Maybe it's

Can you test the patch below (which basically applies the
diff between commits 627e0a14e87 to 77576cd7626e on `emacs.git).
Clearly, the code reorg made the work harder.

But it's a bit worse: the split chosen for the reorganization tends
to create circular dependencies (e.g. all the files need to depend on
`idlw-variables`, so `idlw-variables` can't depend on anything at all).
So it's harder to get rid of all the warnings.

I also attach the warnings resulting from compiling the code (after
applying the patch).


        Stefan
[idlwave.patch (text/x-diff, inline)]
diff --git a/.gitignore b/.gitignore
index 496616a9ed..60ea92613a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,8 @@
 *.elc
 \#*
 .\#*
-*~
\ No newline at end of file
+*~
+
+# ELPA-generated files
+/idlwave-autoloads.el
+/idlwave-pkg.el
diff --git a/idlw-bindings.el b/idlw-bindings.el
index d5fbd8c08c..6c276244a4 100644
--- a/idlw-bindings.el
+++ b/idlw-bindings.el
@@ -1,42 +1,44 @@
-;; IDLWAVE keyboard/mouse bindings, syntax tables, templates, and abbreviations.
+;; IDLWAVE keyboard/mouse bindings, syntax tables, templates, and abbreviations.  -*- lexical-binding: t; -*-
 
-(fset 'idlwave-debug-map (make-sparse-keymap))
+(require 'idlw-variables)   ;At least for `idlwave-abbrev-start-char'.
+
+(defalias 'idlwave-debug-map (make-sparse-keymap))
 
 ;;----------------------------------------------------
 ;; Keyboard bindings, in buffer
 (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" 'idlwave-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)
+    (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.
@@ -45,79 +47,78 @@
              (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)
+          #'idlwave-shell-save-and-run)
         (define-key map
           (vector (append mods-noshift (list (if shift ?B ?b))))
-          'idlwave-shell-break-here)
+          #'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)
+          #'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-with-topic)
-    ;; Pickup both forms of Esc/Meta binding
-    (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
-      (if (featurep 'xemacs) [(shift button3)] [(shift mouse-3)])
-      'idlwave-mouse-context-help)
+      #'idlwave-help-with-topic)
+    ;; Don't pickup both forms of Esc/Meta binding, since that overrides
+    ;; the tab => \t remap and thus other \t bindings of higher priority!
+    ;; (define-key map [(meta tab)] #'idlwave-complete)
+    ;; FIXME: Use `completion-at-point'!
+    (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.")
 
 ;;----------------------------------------------------
 ;; Keyboard bindings, in routine info window
-(defvar idlwave-rinfo-mouse-map (make-sparse-keymap))
-(defvar idlwave-rinfo-map (make-sparse-keymap))
-(define-key idlwave-rinfo-mouse-map 
-  (if (featurep 'xemacs) [button2] [mouse-2])
-  'idlwave-mouse-active-rinfo)
-(define-key idlwave-rinfo-mouse-map 
-  (if (featurep 'xemacs) [(shift button2)] [(shift mouse-2)])
-  'idlwave-mouse-active-rinfo-shift)
-(define-key idlwave-rinfo-mouse-map 
-  (if (featurep 'xemacs) [button3] [mouse-3])
-  'idlwave-mouse-active-rinfo-right)
-(define-key idlwave-rinfo-mouse-map " " 'idlwave-active-rinfo-space)
-(define-key idlwave-rinfo-map "q" 'idlwave-quit-help)
-(define-key idlwave-rinfo-mouse-map "q" 'idlwave-quit-help)
+(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))
 
 ;;----------------------------------------------------
 ;;  Keyboard bindings, in source-help window
-(defvar idlwave-help-mode-map (make-sparse-keymap)
-  "The keymap used in idlwave-help-mode.")
-
-(define-key idlwave-help-mode-map "q" 'idlwave-help-quit)
-(define-key idlwave-help-mode-map "w" 'widen)
-(define-key idlwave-help-mode-map "\C-m" (lambda (arg)
-					   (interactive "p")
-					   (scroll-up arg)))
-(define-key idlwave-help-mode-map " " 'scroll-up)
-(define-key idlwave-help-mode-map [delete] 'scroll-down)
-(define-key idlwave-help-mode-map "h" 'idlwave-help-find-header)
-(define-key idlwave-help-mode-map "H" 'idlwave-help-find-first-header)
-(define-key idlwave-help-mode-map "." 'idlwave-help-toggle-header-match-and-def)
-(define-key idlwave-help-mode-map "F" 'idlwave-help-fontify)
-(define-key idlwave-help-mode-map "\M-?" 'idlwave-help-return-to-calling-frame)
-(define-key idlwave-help-mode-map "x" 'idlwave-help-return-to-calling-frame)
-
+(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'.")
 
 ;;----------------------------------------------------
 ;; Keyboard utility callbacks
@@ -166,86 +167,64 @@
     st)
   "Syntax table that treats symbol characters as word characters.")
 
-(defmacro idlwave-with-special-syntax (&rest body)
-  "Execute BODY with a different syntax table."
-  `(let ((saved-syntax (syntax-table)))
-     (unwind-protect
-	 (progn
-	   (set-syntax-table idlwave-find-symbol-syntax-table)
-	   ,@body)
-       (set-syntax-table saved-syntax))))
-
-;(defmacro idlwave-with-special-syntax1 (&rest body)
-;  "Execute BODY with a different syntax table."
-;  `(let ((saved-syntax (syntax-table)))
-;     (unwind-protect
-;	  (progn
-;	    (set-syntax-table idlwave-find-symbol-syntax-table)
-;	    ,@body)
-;	(set-syntax-table saved-syntax))))
-
 (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 no arguments or a list to be evaluated.  CMD is bound to
+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.
+character a binding will only be set if SELECT is `both'.
 
-\(KEY . CMD\) is also placed in the `idlwave-indent-expand-table',
+\(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
+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 \",\"  '(idlwave-surround 0 1))
+   (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 \"=\"  '(idlwave-expand-equal -1 -1))
+   (idlwave-action-and-binding \"=\"  (lambda (_) (idlwave-expand-equal -1 -1)))
 Capitalize system variables - action only
-   (idlwave-action-and-binding idlwave-sysvar '(capitalize-word 1) t)"
+   (idlwave-action-and-binding idlwave-sysvar
+                               (lambda (_) (capitalize-word 1) t) 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))
-             (cell (assoc table-key (eval table))))
-        (if cell
-            ;; Replace action command
-            (setcdr cell cmd)
-          ;; New action
-          (set table (append (eval table) (list (cons table-key cmd)))))))
+	     (table-key (regexp-quote key)))
+        (setf (alist-get table-key (symbol-value table) nil nil #'equal) cmd)))
   ;; Make key binding for action
-  (if (or (and (null select) (= (length key) 1))
-          (equal select 'noaction)
-          (equal select 'both))
+  (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 (listp cmd) cmd (list cmd))))))
+        (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)
+(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 "="  '(idlwave-expand-equal -1 -1))
+(idlwave-action-and-binding "="  (lambda (_) (idlwave-expand-equal -1 -1)))
 
-;; Actions for > and < are complicated by >=, <=, and ->... 
-(idlwave-action-and-binding "<"  '(idlwave-custom-ltgtr-surround nil))
-(idlwave-action-and-binding ">"  '(idlwave-custom-ltgtr-surround 'gtr))
+;; 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 ","  '(idlwave-surround 0 -1 1))
+(idlwave-action-and-binding ","  (lambda (a) (idlwave-surround 0 -1 1 a)))
 
 
 ;;----------------------------------------------------
@@ -254,39 +233,38 @@ Capitalize system variables - action only
 ;; 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.
 ;;
-(defvar idlwave-mode-abbrev-table nil
-  "Abbreviation table used for IDLWAVE mode.")
-(define-abbrev-table 'idlwave-mode-abbrev-table ())
+(define-abbrev-table 'idlwave-mode-abbrev-table ()
+  "Abbreviation table used for IDLWAVE mode."
+  :enable-function (lambda () (not (idlwave-quoted))))
 
-(defun idlwave-check-abbrev (arg &optional reserved)
-  "Reverse abbrev expansion if in comment or string.
+(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
+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 (idlwave-quoted)
-      (progn (unexpand-abbrev)
-             nil)
-    (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))
-        (if (boundp 'post-command-hook)
-            (setq idlwave-command-hook (list 'backward-char (1+ arg)))
-          (backward-char arg)))
-    t))
+  (require 'idlwave)
+  (defvar idlwave--command-function)
+  (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-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
@@ -297,8 +275,8 @@ If NOPREFIX is non-nil, don't prepend prefix character.  Installs into
 		    expansion
 		    hook)))
     (condition-case nil
-	(apply 'define-abbrev (append args '(0 t)))
-      (error (apply 'define-abbrev args)))))
+	(apply #'define-abbrev (append args '(0 t)))
+      (error (apply #'define-abbrev args)))))
 
 (defun idlwave-expand-region-abbrevs (start end)
   "Expand each abbrev occurrence in the region.
@@ -310,32 +288,12 @@ Calling from a program, arguments are START END."
           (idlwave-abbrev-move nil))        ;Do not move
       (expand-region-abbrevs start end 'noquery))))
 
-(defmacro idlwave-keyword-abbrev (&rest args)
-  "Creates a function for abbrev hooks to call `idlwave-check-abbrev' with args."
-  `(quote (lambda ()
-	    ,(append '(idlwave-check-abbrev) args))))
-
-;; If I take the time I can replace idlwave-keyword-abbrev with
-;; idlwave-code-abbrev and remove the quoted abbrev check from
-;; idlwave-check-abbrev.  Then, e.g, (idlwave-keyword-abbrev 0 t) becomes
-;; (idlwave-code-abbrev idlwave-check-abbrev 0 t).  In fact I should change
-;; the name of idlwave-check-abbrev to something like idlwave-modify-abbrev.
-
-(defmacro idlwave-code-abbrev (&rest args)
-  "Creates a function for abbrev hooks that ensures abbrevs are not quoted.
-Specifically, if the abbrev is in a comment or string it is unexpanded.
-Otherwise ARGS forms a list that is evaluated."
-  ;; FIXME: it would probably be better to rely on the new :enable-function
-  ;; to enforce the "don't expand in comments or strings".
-  `(lambda ()
-     ,(prin1-to-string args)  ;; Puts the code in the doc string
-     (if (idlwave-quoted)
-         (progn (unexpand-abbrev) nil)
-       ,(append args))))
-
+(defun idlwave-keyword-abbrev (&rest args)
+  "Create a function for abbrev hooks to call `idlwave-check-abbrev' with ARGS."
+  (lambda () (apply #'idlwave-modify-abbrev args)))
 
 (condition-case nil
-    (modify-syntax-entry (string-to-char idlwave-abbrev-start-char) 
+    (modify-syntax-entry (string-to-char idlwave-abbrev-start-char)
 			 "w" idlwave-mode-syntax-table)
   (error nil))
 
@@ -343,16 +301,16 @@ Otherwise ARGS forms a list that is evaluated."
 ;;----------------------------------------------------
 ;; Templates
 
-(idlwave-define-abbrev "c"   "" (idlwave-code-abbrev idlwave-case))
-(idlwave-define-abbrev "sw"  "" (idlwave-code-abbrev idlwave-switch))
-(idlwave-define-abbrev "f"   "" (idlwave-code-abbrev idlwave-for))
-(idlwave-define-abbrev "fe"  "" (idlwave-code-abbrev idlwave-foreach))
-(idlwave-define-abbrev "fu"  "" (idlwave-code-abbrev idlwave-function))
-(idlwave-define-abbrev "pr"  "" (idlwave-code-abbrev idlwave-procedure))
-(idlwave-define-abbrev "r"   "" (idlwave-code-abbrev idlwave-repeat))
-(idlwave-define-abbrev "w"   "" (idlwave-code-abbrev idlwave-while))
-(idlwave-define-abbrev "i"   "" (idlwave-code-abbrev idlwave-if))
-(idlwave-define-abbrev "elif" "" (idlwave-code-abbrev idlwave-elif))
+(idlwave-define-abbrev "c"    "" #'idlwave-case)
+(idlwave-define-abbrev "sw"   "" #'idlwave-switch)
+(idlwave-define-abbrev "f"    "" #'idlwave-for)
+(idlwave-define-abbrev "fe"   "" #'idlwave-foreach)
+(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
 ;;
@@ -367,15 +325,15 @@ Otherwise ARGS forms a list that is evaluated."
 (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 "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))
@@ -423,16 +381,16 @@ Otherwise ARGS forms a list that is evaluated."
 (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 "endforeach" "endforeach" '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 "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 "endforeach" "endforeach" #'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)
diff --git a/idlw-complete-structtag.el b/idlw-complete-structtag.el
index b3699091f9..9afcd3332b 100644
--- a/idlw-complete-structtag.el
+++ b/idlw-complete-structtag.el
@@ -1,11 +1,11 @@
-;;; idlw-complete-structtag.el --- Completion of structure tags.
-;; Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 
-;;               2009, 2010  Free Software Foundation, Inc.
+;;; idlw-complete-structtag.el --- Completion of structure tags.  -*- lexical-binding: t; -*-
+;; Copyright (c) 2001-2024  Free Software Foundation, Inc.
 ;;
 ;; Author: Carsten Dominik <dominik _AT_ astro.uva.nl>
 ;; Maintainer: J.D. Smith <jdsmith _AT_ alum.mit.edu>
-;; Version: 1.2
+;; Old-Version: 1.2
 ;; Keywords: languages
+;; Package: idlwave
 
 ;; This file is part of GNU Emacs.
 
@@ -20,7 +20,7 @@
 ;; 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 <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -48,20 +48,19 @@
 ;; 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
+;; completion.  It is also an example which shows how completion plugins
 ;; should be programmed.
 ;;
 ;; New versions of IDLWAVE, documentation, and more information available
 ;; from:
-;;                 http://github.com/jdtsmith/idlwave
+;;                 https://github.com/jdtsmith/idlwave
 ;;
 ;; INSTALLATION
 ;; ============
-;; Put this file on the emacs load path and load it with the following 
-;; line in your .emacs file:
+;; Load it with the following line in your init file:
 ;;
-;;   (add-hook 'idlwave-load-hook 
-;;             (lambda () (require 'idlw-complete-structtag)))
+;;   (with-eval-after-load 'idlwave
+;;     (require 'idlw-complete-structtag))
 ;;
 ;; DESCRIPTION
 ;; ===========
@@ -94,7 +93,9 @@
 ;;  - You can force an update of the tag list with the usual command
 ;;    to update routine info in IDLWAVE: C-c C-i
 
-;;(require 'idlwave)
+;;; Code:
+
+(require 'idlwave)
 
 (declare-function idlwave-shell-buffer "idlw-shell")
 
@@ -105,15 +106,13 @@
 
 ;; 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 tags
-(add-hook 'idlwave-load-hook
-	  (lambda () (idlwave-new-sintern-type 'structtag)))
+(idlwave-new-sintern-type structtag)
 
 ;; Hook the plugin into idlwave
-(add-to-list 'idlwave-complete-special 'idlwave-complete-structure-tag)
-(add-hook 'idlwave-update-rinfo-hook 'idlwave-structtag-reset)
+(add-hook 'idlwave-complete-functions #'idlwave-complete-structure-tag)
+(add-hook 'idlwave-update-rinfo-hook #'idlwave-structtag-reset)
 
 ;;; The main code follows below
 (defun idlwave-complete-structure-tag ()
@@ -134,7 +133,7 @@ an up-to-date completion list."
           ;; 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._$]")
+	  (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
@@ -154,9 +153,9 @@ an up-to-date completion list."
                   (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 
+	  (setq idlwave-completion-help-info
 		(list 'idlwave-complete-structure-tag-help))
-	  (idlwave-complete-in-buffer 'structtag 'structtag 
+	  (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
@@ -172,10 +171,10 @@ an up-to-date completion list."
 (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 (eq major-mode 'idlwave-shell-mode)
+  (if (derived-mode-p 'idlwave-shell-mode)
       ;; OK, we are in the shell, do it dynamically
       (progn
-        (message "preparing shell tags") 
+        (message "preparing shell tags")
         ;; The following call puts the tags into `idlwave-current-struct-tags'
         (idlwave-complete-structure-tag-query-shell var)
         ;; initialize
@@ -197,7 +196,7 @@ an up-to-date completion list."
             ;; Find possible definitions of the structure.
             (while (idlwave-find-structure-definition var nil 'all)
               (let ((tags (idlwave-struct-tags)))
-                (when tags 
+                (when tags
                   ;; initialize
                   (setq idlwave-sint-structtags nil
                         idlwave-current-tags-buffer (current-buffer)
@@ -214,7 +213,7 @@ an up-to-date completion list."
   "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
+   #'idlwave-complete-structure-tag-get-tags-from-help
    'hide 'wait))
 
 (defvar idlwave-shell-prompt-pattern)
@@ -229,6 +228,8 @@ an up-to-date completion list."
 
 
 ;; 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
@@ -238,7 +239,7 @@ an up-to-date completion list."
 	(not (equal idlwave-current-tags-buffer
 		    (get-buffer (idlwave-shell-buffer))))))
    ((eq mode 'set)
-    (setq kwd word ;; dynamic var
+    (setq idlw-help-kwd word ;; dynamic var
 	  idlwave-help-do-struct-tag idlwave-structtag-struct-location))
    (t (error "This should not happen"))))
 
diff --git a/idlw-complete.el b/idlw-complete.el
index b1c90e5394..28c645fddd 100644
--- a/idlw-complete.el
+++ b/idlw-complete.el
@@ -1,25 +1,31 @@
-;; IDLWAVE code for completion
+;; IDLWAVE code for completion  -*- lexical-binding: t; -*-
 
 ;; ---------------------------------------------------------------------------
 ;;
 ;; Completion and displaying routine calling sequences
 
+;;; Code:
+
+(require 'idlw-variables)
+
 ;;----------------------------------------------------
 ;; Internal variables
 (defvar idlwave-completion-help-info nil
   "Global variable passing information for invoking help during completions.
-Format: (what name type class kwd super-classes)"
+Format: (WHAT NAME TYPE CLASS KWD SUPER-CLASSES)"
 )
 (defvar idlwave-completion-help-links nil)
 (defvar idlwave-current-obj_new-class nil)
-(defvar idlwave-complete-special nil)
-(defvar method-selector)
-(defvar class-selector)
-(defvar type-selector)
-(defvar super-classes)
+(defvar idlwave--method-selector)
+(defvar idlwave--class-selector)
+(defvar idlwave--type-selector)
+(defvar idlwave--super-classes)
 (defvar idlwave-before-completion-wconf nil
   "The window configuration just before the completion buffer was displayed.")
-(defvar idlwave-complete-special nil
+(define-obsolete-variable-alias 'idlwave-complete-special
+  'idlwave-complete-functions "28.1")
+(defvar idlwave-complete-functions nil
+  ;; FIXME: Use `completion-at-point-functions' instead!
   "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
@@ -27,13 +33,12 @@ 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.")
-(defvar idlwave-complete-after-success-form nil
-  "A form to evaluate after successful completion.")
-(defvar idlwave-complete-after-success-form-force nil
-  "A form to evaluate after completion selection in *Completions* buffer.")
+(defvar idlwave--complete-after-success-function #'ignore
+  "A function to evaluate after successful completion.")
+(defvar idlwave--complete-after-success-form-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.")
-(defvar completion-highlight-first-word-only) ;XEmacs.
 (defvar idlwave-completion-setup-hook nil)
 
 ;;----------------------------------------------------
@@ -42,7 +47,7 @@ other completions will be tried.")
 (defun idlwave-complete (&optional arg module class)
   "Complete a function, procedure (method) or keyword name at point.
 This function is smart and figures out what can be completed at
-this point.  Extensions are supported. 
+this point.  Extensions are supported.
 
 - At the beginning of a statement it completes procedure names.
 - In the middle of a statement it completes function names.
@@ -69,21 +74,21 @@ 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 C-u forces completion
+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, e.g., a
 keyword.
 
-Two prefix argument, C-u C-u, prompts for a regexp by which to
+Two prefix argument, \\[universal-argument] \\[universal-argument] prompts for a regexp by which to
 limit completion list, limited to the list of completions which
 would have been generated.
 
@@ -92,6 +97,7 @@ 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)
+  (defvar idlwave-force-class-query)
   (let* ((where-list
 	  (if (and arg
 		   (or (and (integerp arg) (not (equal arg '(16))))
@@ -104,7 +110,7 @@ When we force a method or a method keyword, CLASS can specify the class."
 	 (completion-regexp-list
 	  (if (equal arg '(16))
 	      (list (read-string (concat "Completion Regexp: "))))))
-    
+
     (if (and module (string-match "::" module))
 	(setq class (substring module 0 (match-beginning 0))
 	      module (substring module (match-end 0))))
@@ -123,10 +129,8 @@ When we force a method or a method keyword, CLASS can specify the class."
       (idlwave-complete-filename))
 
      ;; Check for any special completion functions
-     ((and idlwave-complete-special
-	   (condition-case nil
-	       (idlwave-call-special idlwave-complete-special)
-	     (error nil))))
+     ((with-demoted-errors "%S"
+	(run-hook-with-args-until-success 'idlwave-complete-functions)))
 
      ((null what)
       (error "Nothing to complete here"))
@@ -139,22 +143,26 @@ When we force a method or a method keyword, CLASS can specify the class."
      ((eq what 'procedure)
       ;; Complete a procedure name
       (let* ((cw-list (nth 3 where-list))
-	     (class-selector (idlwave-determine-class cw-list 'pro))
-	     (super-classes (unless (idlwave-explicit-class-listed cw-list)
-			      (idlwave-all-class-inherits class-selector)))
-	     (isa (concat "procedure" (if class-selector "-method" "")))
-	     (type-selector 'pro))
-	(setq idlwave-completion-help-info 
-	      (list 'routine nil type-selector class-selector nil super-classes))
+	     (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 class-selector 'method 'routine)
+	 'procedure (if idlwave--class-selector 'method 'routine)
 	 (idlwave-routines) 'idlwave-selector
 	 (format "Select a %s name%s"
 		 isa
-		 (if class-selector
-		     (format " (class is %s)" 
-			     (if (eq class-selector t) 
-				 "unknown" class-selector))
+		 (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)))
@@ -162,22 +170,25 @@ When we force a method or a method keyword, CLASS can specify the class."
      ((eq what 'function)
       ;; Complete a function name
       (let* ((cw-list (nth 3 where-list))
-	     (class-selector (idlwave-determine-class cw-list 'fun))
-	     (super-classes (unless (idlwave-explicit-class-listed cw-list)
-			      (idlwave-all-class-inherits class-selector)))
-	     (isa (concat "function" (if class-selector "-method" "")))
-	     (type-selector 'fun))
-	(setq idlwave-completion-help-info 
-	      (list 'routine nil type-selector class-selector nil super-classes))
+	     (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 class-selector 'method 'routine)
+	 'function (if idlwave--class-selector 'method 'routine)
 	 (idlwave-routines) 'idlwave-selector
 	 (format "Select a %s name%s"
 		 isa
-		 (if class-selector
-		     (format " (class is %s)" 
-			     (if (eq class-selector t)
-				 "unknown" class-selector))
+		 (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)))
@@ -190,11 +201,12 @@ When we force a method or a method keyword, CLASS can specify the class."
       ;; Complete a procedure keyword
       (let* ((where (nth 3 where-list))
 	     (name  (car where))
-	     (method-selector name)
-	     (type-selector 'pro)
+	     (idlwave--method-selector name)
+	     (idlwave--type-selector 'pro)
 	     (class (idlwave-determine-class where 'pro))
-	     (class-selector class)
-	     (super-classes (idlwave-all-class-inherits class-selector))
+	     (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)))
@@ -203,18 +215,20 @@ When we force a method or a method keyword, CLASS can specify the class."
 	(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 
-					 super-classes system))
+	(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 type-selector class-selector entry super-classes))
+	(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))			 
+			 (member '("_REF_EXTRA") list))
 		     " (note _EXTRA)" ""))
 	 isa
 	 'idlwave-attach-keyword-classes)))
@@ -223,11 +237,12 @@ When we force a method or a method keyword, CLASS can specify the class."
       ;; Complete a function keyword
       (let* ((where (nth 3 where-list))
 	     (name  (car where))
-	     (method-selector name)
-	     (type-selector 'fun)
+	     (idlwave--method-selector name)
+	     (idlwave--type-selector 'fun)
 	     (class (idlwave-determine-class where 'fun))
-	     (class-selector class)
-	     (super-classes (idlwave-all-class-inherits class-selector))
+	     (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)))
@@ -237,8 +252,8 @@ When we force a method or a method keyword, CLASS can specify the class."
 	(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 
-					 super-classes system))
+	(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"))
@@ -247,13 +262,15 @@ When we force a method or a method keyword, CLASS can specify the class."
 			 (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 type-selector class-selector nil super-classes))
+	(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))			 
+			 (member '("_REF_EXTRA") list))
 		     " (note _EXTRA)" ""))
 	 isa
 	 'idlwave-attach-keyword-classes)))
@@ -265,8 +282,8 @@ When we force a method or a method keyword, CLASS can specify the class."
 					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, etc.  SPECIAL-SELECTOR is
+PROMPT in echo area.  TYPE is one of the intern types, e.g. `function',
+`procedure', `class-tag', `keyword', `sysvar', etc.  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)
@@ -281,12 +298,12 @@ accumulate information on matching completions."
       (skip-chars-backward "a-zA-Z0-9_$")
       (setq slash (eq (preceding-char) ?/)
 	    beg (point)
-	    idlwave-complete-after-success-form
-	    (list 'idlwave-after-successful-completion
-		  (list 'quote type) slash beg)
-	    idlwave-complete-after-success-form-force
-	    (list 'idlwave-after-successful-completion
-		  (list 'quote type) slash (list 'quote 'force))))
+	    idlwave--complete-after-success-function
+	    (lambda () (idlwave-after-successful-completion
+		   type slash beg))
+	    idlwave--complete-after-success-form-force-function
+	    (lambda () (idlwave-after-successful-completion
+		   type slash 'force))))
 
     ;; Try a completion
     (setq part (buffer-substring beg end)
@@ -316,18 +333,18 @@ accumulate information on matching completions."
      ((or (eq completion t)
 	  (and (= 1 (length (setq all-completions
 				  (idlwave-uniquify
-				   (all-completions part list 
-						    (or special-selector 
+				   (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        
+     (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))))
@@ -337,12 +354,8 @@ accumulate information on matching completions."
 	      list))
       (let* ((list all-completions)
 	     ;; "complete" means, this is already a valid completion
-	     (complete (memq spart all-completions))
-	     (completion-highlight-first-word-only t)) ; XEmacs
-	     ;; (completion-fixup-function             ; Emacs
-	     ;;  (lambda () (and (eq (preceding-char) ?>)
-	     ;;    	      (re-search-backward " <" beg t)))))
-	     
+	     (complete (memq spart all-completions)))
+
 	(setq list (sort list (lambda (a b)
 				(string< (downcase a) (downcase b)))))
 	(if prepare-display-function
@@ -352,7 +365,7 @@ accumulate information on matching completions."
 		     idlwave-complete-empty-string-as-lower-case)
 		 (not idlwave-completion-force-default-case))
 	    (setq list (mapcar (lambda (x)
-				 (if (listp x) 
+				 (if (listp x)
 				     (setcar x (downcase (car x)))
 				   (setq x (downcase x)))
 				 x)
@@ -373,7 +386,7 @@ accumulate information on matching completions."
 			    (nth 2 last-command))
 		       (progn
 			 (select-window win)
-			 (eval idlwave-complete-after-success-form))
+			 (funcall idlwave--complete-after-success-function))
 		     (set-window-start cwin (point-min)))))
 	  (and message (message "%s" message)))
       (select-window win))))
@@ -385,7 +398,7 @@ accumulate information on matching completions."
     (move-marker idlwave-completion-mark beg)
     (setq idlwave-before-completion-wconf (current-window-configuration)))
 
-  (idlwave-display-completion-list-emacs list)
+  (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.
@@ -435,10 +448,10 @@ Restore the pre-completion window configuration if possible."
       nil)))
 
   ;; Restore the pre-completion window configuration if this is safe.
-  (if (or (eq verify 'force)                                    ; force 
-	  (and 
+  (if (or (eq verify 'force)                                    ; force
+	  (and
 	   (get-buffer-window "*Completions*")                  ; visible
-	   (idlwave-local-value 'idlwave-completion-p 
+	   (idlwave-local-value 'idlwave-completion-p
 				"*Completions*")                ; cib-buffer
 	   (eq (marker-buffer idlwave-completion-mark)
 	       (current-buffer))                                ; buffer OK
@@ -461,10 +474,10 @@ Restore the pre-completion window configuration if possible."
 		      ("class")))
 	 (module (idlwave-sintern-routine-or-method module class))
 	 (class (idlwave-sintern-class class))
-	 (what (cond 
+	 (what (cond
 		((equal what 0)
 		 (setq what
-		       (intern (completing-read 
+		       (intern (completing-read
 				"Complete what? " what-list nil t))))
 		((integerp what)
 		 (setq what (intern (car (nth (1- what) what-list)))))
@@ -482,11 +495,11 @@ Restore the pre-completion window configuration if possible."
       (list nil-list nil-list 'procedure nil-list nil))
 
      ((eq what 'procedure-keyword)
-      (let* ((class-selector nil)
-	     (super-classes nil)
-	     (type-selector 'pro)
+      (let* ((idlwave--class-selector nil)
+	     (idlwave--super-classes nil)
+	     (idlwave--type-selector 'pro)
 	     (pro (or module
-		      (idlwave-completing-read 
+		      (idlwave-completing-read
 		       "Procedure: " (idlwave-routines) 'idlwave-selector))))
 	(setq pro (idlwave-sintern-routine pro))
 	(list nil-list nil-list 'procedure-keyword
@@ -496,11 +509,11 @@ Restore the pre-completion window configuration if possible."
       (list nil-list nil-list 'function nil-list nil))
 
      ((eq what 'function-keyword)
-      (let* ((class-selector nil)
-	     (super-classes nil)
-	     (type-selector 'fun)
+      (let* ((idlwave--class-selector nil)
+	     (idlwave--super-classes nil)
+	     (idlwave--type-selector 'fun)
 	     (func (or module
-		       (idlwave-completing-read 
+		       (idlwave-completing-read
 			"Function: " (idlwave-routines) 'idlwave-selector))))
 	(setq func (idlwave-sintern-routine func))
 	(list nil-list nil-list 'function-keyword
@@ -511,12 +524,14 @@ Restore the pre-completion window configuration if possible."
 
      ((eq what 'procedure-method-keyword)
       (let* ((class (idlwave-determine-class class-list 'pro))
-	     (class-selector class)
-	     (super-classes (idlwave-all-class-inherits class-selector))
-	     (type-selector '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: " class-selector)
+		       (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
@@ -527,12 +542,14 @@ Restore the pre-completion window configuration if possible."
 
      ((eq what 'function-method-keyword)
       (let* ((class (idlwave-determine-class class-list 'fun))
-	     (class-selector class)
-	     (super-classes (idlwave-all-class-inherits class-selector))
-	     (type-selector '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: " class-selector)
+			(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
@@ -540,10 +557,11 @@ Restore the pre-completion window configuration if possible."
 
      ((eq what 'class)
       (list nil-list nil-list 'class nil-list nil))
-     
+
      (t (error "Invalid value for WHAT")))))
 
 (defun idlwave-call-special (functions &rest args)
+  (declare (obsolete run-hook-with-args-until-success "28.1"))
   (let ((funcs functions)
 	fun ret)
     (catch 'exit
@@ -558,27 +576,26 @@ Restore the pre-completion window configuration if possible."
     (unwind-protect
 	(progn
 	  (setq-default completion-ignore-case t)
-	  (apply 'completing-read args))
+	  (apply #'completing-read args))
       (setq-default completion-ignore-case old-value))))
 
 (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 (eq major-mode 'idlwave-shell-mode)
-	   (boundp 'font-lock-mode)
+  (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))))
-  (eval idlwave-complete-after-success-form-force))
+  (funcall idlwave--complete-after-success-form-force-function))
 
 (defun idlwave-choose-completion (&rest args)
   "Choose the completion that point is in or next to."
-  (interactive)
-  (apply 'idlwave-choose 'choose-completion args))
+  (interactive (list last-nonmenu-event))
+  (apply #'idlwave-choose #'choose-completion args))
 
 ;;----------------------------------------------------
 ;; Mouse/Interaction/Fontification
@@ -586,11 +603,10 @@ Restore the pre-completion window configuration if possible."
 (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-emacs (list)
+(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))
@@ -598,23 +614,22 @@ Restore the pre-completion window configuration if possible."
     (use-local-map
      (or idlwave-completion-map
 	 (setq idlwave-completion-map
-	       (idlwave-make-modified-completion-map-emacs
+	       (idlwave-make-modified-completion-map
 		(current-local-map)))))))
 
-(defun idlwave-make-modified-completion-map-emacs (old-map)
-  "Replace `choose-completion' and `mouse-choose-completion' in OLD-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)
     (substitute-key-definition
-     'mouse-choose-completion 'idlwave-mouse-choose-completion new-map)
-    (define-key new-map [mouse-3] 'idlwave-mouse-completion-help)
+     #'choose-completion #'idlwave-choose-completion new-map)
+    (define-key new-map [mouse-3] #'idlwave-mouse-completion-help)
     new-map))
 
-(defun idlwave-mouse-choose-completion (&rest args)
-  "Click on an alternative in the `*Completions*' buffer to choose it."
-  (interactive "e")
-  (apply 'idlwave-choose 'mouse-choose-completion args))
+(define-obsolete-function-alias 'idlwave-mouse-choose-completion
+  #'idlwave-choose-completion "28.1")
 
 (defun idlwave-restore-wconf-after-completion ()
   "Restore the old (before completion) window configuration."
@@ -624,14 +639,13 @@ Restore the pre-completion window configuration if possible."
 
 (defun idlwave-completion-fontify-classes ()
   "Goto the *Completions* buffer and fontify the class info."
-  (when (featurep 'font-lock)
-    (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)))))))
+  (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))))))
 
 
 ;;----------------------------------------------------
@@ -641,14 +655,14 @@ Restore the pre-completion window configuration if possible."
 (defun idlwave-complete-filename ()
   "Use the comint stuff to complete a file name."
   (require 'comint)
-  (let* ((comint-file-name-chars "~/A-Za-z0-9+@:_.$#%={}\\-")
+  (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)))	   
+	     default-directory)))
     (comint-dynamic-complete-filename)))
 
 ;;----------------------------------------------------
@@ -666,13 +680,13 @@ Restore the pre-completion window configuration if possible."
 	   (re-search-backward "\\<\\(pro\\|function\\)[ \t]+\\="
 			       (- (point) 15) t)
 	   (goto-char (point-min))
-	   (re-search-forward 
+	   (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 
+    (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)
@@ -685,10 +699,10 @@ Restore the pre-completion window configuration if possible."
 
 ;; Completion selector/predicate function
 (defun idlwave-selector (a)
-  (and (eq (nth 1 a) type-selector)
-       (or (and (nth 2 a) (eq class-selector t))
-	   (eq (nth 2 a) class-selector)
-	   (memq (nth 2 a) super-classes))))
+  (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-attach-classes (list type show-classes)
   ;; Attach the proper class list to a LIST of completion items.
@@ -696,59 +710,59 @@ Restore the pre-completion window configuration if possible."
   ;; '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 class-selector)         ; not a method call
-	  (and 
-	   (stringp class-selector) ; the class is already known
-	   (not super-classes)))    ; no possibilities for inheritance
+	  (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 (and (>= show-classes 0)
-			 (>= emacs-major-version 21)))
+    (let* ((do-prop (>= show-classes 0))
 	   (do-buf (not (= show-classes 0)))
-	   ;; (do-dots (featurep 'xemacs))
-	   (do-dots t)
-	   (inherit (if (and (not (eq type 'class-tag)) super-classes)
-			(cons class-selector super-classes)))
+	   ;; (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))))
+	   (lmax ;; (if do-dots
+	             (apply #'max (mapcar #'length list)))
 	  classes nclasses class-info space)
-      (mapcar 
+      (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 class-selector x)))
+		   (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
-		      method-selector x type-selector)
-		   (idlwave-all-method-classes x type-selector)))
+		      idlwave--method-selector x idlwave--type-selector)
+		   (idlwave-all-method-classes x idlwave--type-selector)))
 	   (if inherit
-	       (setq classes 
+	       (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-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 ",") ">"))
+				   "<" (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 " ")
+                              'help-echo (mapconcat #'identity classes " ")
                               x))
 	 (if class-info
 	     (list x class-info)
@@ -766,19 +780,35 @@ Restore the pre-completion window configuration if possible."
 (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))
-					
+
 ;;----------------------------------------------------
 ;; Class structure tags
 
+(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
+		(setq ,var (cons (cons (downcase name) name) ,var))
+		name)
+	       (name))))))
+
 (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)
-(declare-function idlwave-sintern-class-tag "idlwave" t t)
-(add-hook 'idlwave-load-hook
-	  (lambda () (idlwave-new-sintern-type 'class-tag)))
-(add-to-list 'idlwave-complete-special 'idlwave-complete-class-structure-tag)
-(add-hook 'idlwave-update-rinfo-hook 'idlwave-class-tag-reset)
+
+(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."
@@ -790,47 +820,52 @@ Restore the pre-completion window configuration if possible."
 	  (skip-chars-backward "a-zA-Z0-9._$")
 	  (and (< (point) (- pos 4))
 	       (looking-at "self\\.")))
-	(let* ((class-selector (nth 2 (idlwave-current-routine)))
-	       (super-classes (idlwave-all-class-inherits class-selector)))
+	(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 class-selector
+	  (unless idlwave--class-selector
 	    (error "Not in a method procedure or function"))
 	  ;; Check if we need to update the "current" class
-	  (if (not (equal class-selector idlwave-current-tags-class))
-	      (idlwave-prepare-class-tag-completion class-selector))
-	  (setq idlwave-completion-help-info 
+	  (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 class-selector "__define"))
+		      (idlwave-sintern-routine
+		       (concat idlwave--class-selector "__define"))
 		      nil))
-	  (let  ((idlwave-current-native-class-tags))
+	  (let  ((idlwave-current-native-class-tags)) ;FIXME: Really?
 	    (idlwave-complete-in-buffer
-	     'class-tag 'class-tag 
+	     'class-tag 'class-tag
 	     idlwave-current-class-tags nil
-	     (format "Select a tag of class %s" class-selector)
+	     (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)))
 
 ;; Fake help in the source buffer for class structure tags.
+;; Get rid of opaque dynamic variable passing of `idlw-help-link'?
+(defvar idlw-help-link) ;Dynbound var from `idlwave-do-mouse-completion-help'.
+(defvar idlw-help-name)
 (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 
+      (when (setq class-with
+		(idlwave-class-or-superclass-with-tag
 		 idlwave-current-tags-class
 		 word))
-	(if (assq (idlwave-sintern-class class-with) 
+	(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 name (cons (concat found-in "__define") class-with))
-	  (setq name (concat class-with "__define")))))
-    (setq kwd word
+	(setq idlw-help-name
+	      (if (setq found-in (idlwave-class-found-in class-with))
+	          (cons (concat found-in "__define") class-with)
+	        (concat class-with "__define")))))
+    (setq idlw-help-link word
 	  idlwave-help-do-class-struct-tag t))
    (t (error "This should not happen"))))
 
@@ -846,10 +881,10 @@ Restore the pre-completion window configuration if possible."
 		  (list (idlwave-sintern-class-tag x 'set)))
 		(idlwave-all-class-tags class)))
   (setq idlwave-current-native-class-tags
-	(mapcar 'downcase (idlwave-class-tags class))))
+	(mapcar #'downcase (idlwave-class-tags class))))
 
 (defun idlwave-class-add-init-special ()
-  ;; Create special entries for Class::Init() methods as Class() 
+  ;; Create special entries for Class::Init() methods as Class()
   ;; (syntactic sugar in IDL >=8).
   (idlwave-routines)
   (setcdr (last idlwave-routines)
@@ -865,20 +900,14 @@ Restore the pre-completion window configuration if possible."
 	   'set)))
 
 ;;----------------------------------------------------
-;; System variables/fields 
-
-(defvar idlwave-sint-sysvars nil)
-(defvar idlwave-sint-sysvartags nil)
-(declare-function idlwave-sintern-sysvar    "idlwave" t t)
-(declare-function idlwave-sintern-sysvartag "idlwave" t t)
-(add-hook 'idlwave-load-hook
-	  (lambda () 
-	    (idlwave-new-sintern-type 'sysvar)
-	    (idlwave-new-sintern-type 'sysvartag)))
-(add-to-list 'idlwave-complete-special 'idlwave-complete-sysvar-or-tag)
-(add-hook 'idlwave-update-rinfo-hook 'idlwave-sysvars-reset)
-(add-hook 'idlwave-update-rinfo-hook 'idlwave-class-add-init-special)
-(add-hook 'idlwave-after-load-rinfo-hook 'idlwave-sintern-sysvar-alist)
+;; System variables/fields
+
+(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-update-rinfo-hook #'idlwave-class-add-init-special)
+(add-hook 'idlwave-after-load-rinfo-hook #'idlwave-sintern-sysvar-alist)
 
 (defun idlwave-complete-sysvar-or-tag ()
   "Complete a system variable."
@@ -887,10 +916,10 @@ Restore the pre-completion window configuration if possible."
 	(case-fold-search t))
     (cond ((save-excursion
 	     ;; Check if the context is right for system variable
-	     (skip-chars-backward "[a-zA-Z0-9_$]")
+	     (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-complete-in-buffer 'sysvar 'sysvar
 				       idlwave-system-variables-alist nil
 				       "Select a system variable"
 				       "system variable")
@@ -909,14 +938,13 @@ Restore the pre-completion window configuration if possible."
 	     (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 
+	     (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 idlwave-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)))
@@ -924,7 +952,8 @@ Restore the pre-completion window configuration if possible."
      ((eq mode 'test)
       (and (stringp word) entry (nth 1 (assq 'link entry))))
      ((eq mode 'set)
-      (if entry (setq idlwave-link (nth 1 (assq 'link entry))))) ;; setting dynamic!!!
+      ;; 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)
@@ -939,11 +968,11 @@ Restore the pre-completion window configuration if possible."
      ((eq mode 'test) ; we can at least link the main
       (and (stringp word) entry main))
      ((eq mode 'set)
-      (if entry 
-	  (setq link ;; setting dynamic!!!
-		(if (setq target (cdr (assoc-ignore-case word tags)))
-		  (idlwave-substitute-link-target main target)
-		main)))) 
+      (if entry
+	  (setq idlw-help-link ;; setting dynamic!!!
+		(if (setq target (cdr (assoc-string word tags 'ignore-case)))
+		    (idlwave-substitute-link-target main target)
+		  main))))
      (t (error "This should not happen")))))
 
 (defvar idlwave-help-do-class-struct-tag nil)
@@ -952,7 +981,7 @@ Restore the pre-completion window configuration if possible."
 ;; Specialized completion in the shell
 
 (defun idlwave-shell-complete (&optional arg)
-  "Do completion in the idlwave-shell buffer.
+  "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."
@@ -1000,20 +1029,22 @@ keywords."
      ((eq mode 'test)
       (and (stringp word) entry (cdr entry)))
      ((eq mode 'set)
-      (if entry (setq idlwave-link (cdr entry)))) ;; setting dynamic variable!!!
+      (if entry (setq idlw-help-link (cdr entry)))) ;; setting dynamic variable!!!
      (t (error "This should not happen")))))
 
+(defvar comint-file-name-chars)
+
 (defun idlwave-shell-complete-filename (&optional nospace)
   "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 
+  (let ((comint-file-name-chars
 	 (if (and nospace (string-match "[ ]" idlwave-shell-file-name-chars))
 	     (replace-match "" nil t idlwave-shell-file-name-chars)
 	   idlwave-shell-file-name-chars)))
-    (comint-dynamic-complete-as-filename)))
+    (comint-dynamic-complete-filename)))
 
 
 (provide 'idlw-complete)
diff --git a/idlw-help.el b/idlw-help.el
index 4ebf1b713a..fd8bcd645d 100644
--- a/idlw-help.el
+++ b/idlw-help.el
@@ -1,12 +1,12 @@
-;;; idlw-help.el --- HTML Help code for IDLWAVE
+;;; idlw-help.el --- HTML Help code for IDLWAVE  -*- lexical-binding: t; -*-
 
-;; Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-;;               2009, 2010, 2012, 2013 Free Software Foundation, Inc.
+;; Copyright (c) 2000-2024 Free Software Foundation, Inc.
 ;;
 ;; Authors: J.D. Smith <jdtsmith _AT_ gmail.com>
 ;;          Carsten Dominik <dominik _AT_ science.uva.nl>
 ;; Maintainer: J.D. Smith
 ;; Version: VERSIONTAG
+;; Package: idlwave
 
 ;; This file is part of GNU Emacs.
 
@@ -21,7 +21,7 @@
 ;; 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 <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -33,22 +33,20 @@
 ;; along with new versions of IDLWAVE, documentation, and more
 ;; information, at:
 ;;
-;;           http://github.com/jdtsmith/idlwave
+;;           https://github.com/jdtsmith/idlwave
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
 ;;; Code:
-(defvar idlwave-help-browse-url-available t
-  "Whether browse-url is available")
 
 (require 'browse-url)
-
+(require 'idlw-variables) ;Define the mode-map before `define-derived-mode'.
+(require 'idlw-complete)  ;For `idlwave-completion-help-info'?
 
 (defvar idlwave-html-link-sep "#")
 
 (defface idlwave-help-link
-  '((((class color)) (:foreground "Blue"))
-    (t (:weight bold)))
+  '((t :inherit link))
   "Face for highlighting links into IDLWAVE online help."
   :group 'idlwave-online-help)
 
@@ -58,10 +56,10 @@
   "The default width of the help frame.")
 
 (defvar idlwave-html-help-is-available nil
-  "Is the system online help text avaiable?")
+  "Is the system online help text available?")
 
 (defvar idlwave-help-mode-line-indicator ""
-  "Used for the special mode line in the idlwave-help-mode.")
+  "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
@@ -72,7 +70,7 @@
 (defvar idlwave-help-in-header)
 (declare-function idlwave-prepare-structure-tag-completion "idlw-complete-structtag")
 
-(defun idlwave-help-mode ()
+(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,
@@ -83,21 +81,16 @@ 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 hep text is a source file, the following commands are available
+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 forward between header and definition
+                    [.] back and forth between header and definition
 
 Here are all keybindings.
 \\{idlwave-help-mode-map}"
-  (kill-all-local-variables)
   (buffer-disable-undo)
-  (setq major-mode 'idlwave-help-mode
-	mode-name "IDLWAVE Help")
-  (use-local-map idlwave-help-mode-map)
-  (easy-menu-add idlwave-help-menu idlwave-help-mode-map)
   (setq truncate-lines t)
   (setq case-fold-search t)
   (setq mode-line-format
@@ -109,15 +102,14 @@ Here are all keybindings.
   (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)
-  (run-mode-hooks 'idlwave-help-mode-hook))
+  (set (make-local-variable 'idlwave-help-in-header) 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-context-help1.
+  "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))
@@ -132,7 +124,7 @@ It collects and prints the diagnostics messages."
       (setq idlwave-last-context-help-pos marker)
       (idlwave-do-context-help1 arg)
       (if idlwave-help-diagnostics
-	  (message "%s" (mapconcat 'identity 
+	  (message "%s" (mapconcat #'identity
 				   (nreverse idlwave-help-diagnostics)
 				   "; "))))))
 
@@ -142,10 +134,16 @@ It collects and prints the diagnostics messages."
 (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) ?/) 
+    (if (equal (char-after) ?/)
 	(forward-char 1)
       (if (equal (char-before) ?=)
 	  (backward-char 1)))
@@ -155,15 +153,16 @@ It collects and prints the diagnostics messages."
 	   (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-ignore-case this-word
-				      idlwave-help-special-topic-words))
+	   (st-ass (assoc-string this-word
+				 idlwave-help-special-topic-words
+				 'ignore-case))
 	   (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 
+      (if (or arg
 	      (and (not classtag)
 		   (not (member (string-to-char this-word) '(?!)))))
 	  ;; Get the module information
@@ -180,16 +179,16 @@ It collects and prints the diagnostics messages."
 		      (setq module (list "init" 'fun (match-string 1 str))
 			    idlwave-current-obj_new-class (match-string 1 str))
 		    )))))
-      (cond 
+      (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_]+\\)\\)?" 
+       ((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)
@@ -201,18 +200,18 @@ It collects and prints the diagnostics messages."
 				      (cdr (assq 'tags entry))))))
 	       (link (cdr (assq 'link entry))))
 	  (if tag-target
-	      (setq link (idlwave-substitute-link-target link 
+	      (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-ignore-case 
-			    word
-			    idlwave-executive-commands-alist))))
+	       (link  (cdr (assoc-string
+			    word idlwave-executive-commands-alist
+			    'ignore-case))))
 	  (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
@@ -226,28 +225,28 @@ It collects and prints the diagnostics messages."
 	       (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 
+	  (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) 
+	    (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 
+	    (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
        ;; `complete-structtag' loaded.
        ((and structtag
@@ -260,12 +259,12 @@ It collects and prints the diagnostics messages."
 	(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-match "!" this-word)))
+	     (not (string-search "!" this-word)))
 	(cond ((or (= (char-before beg) ?/)
 		   (save-excursion (goto-char end)
 				   (looking-at "[ \t]*=")))
@@ -302,23 +301,22 @@ It collects and prints the diagnostics messages."
 	       (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)
+	      (apply #'idlwave-online-help mod1)
 	    (error (condition-case nil
-		       (apply 'idlwave-online-help mod2)
-		     (error (apply 'idlwave-online-help mod3)))))
+		       (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)))
+		(apply #'idlwave-online-help mod1)
+	      (error (apply #'idlwave-online-help mod2)))
 	  (if mod1
-	      (apply 'idlwave-online-help mod1)
+	      (apply #'idlwave-online-help mod1)
 	    (error "Don't know which item to show help for")))))))
 
 (defun idlwave-do-mouse-completion-help (ev)
@@ -327,82 +325,85 @@ 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))
-	 (name (nth 1 info))
+	 (idlw-help-name (nth 1 info))
 	 (type (nth 2 info))
 	 (class (nth 3 info))
 	 (need-class class)
-	 (kwd (nth 4 info))
+	 (idlw-help-kwd (nth 4 info))
 	 (sclasses (nth 5 info))
-	 word link)
+	 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 link (get-text-property 0 'link word))
+    (setq idlw-help-link (get-text-property 0 'link word))
     (select-window cw)
-    (cond 
+    (cond
      ;; Routine name
      ((memq what '(procedure function routine))
-      (setq name word)
+      (setq idlw-help-name word)
       (if (or (eq class t)
 	      (and (stringp class) sclasses))
 	  (let* ((classes (idlwave-all-method-classes
-			   (idlwave-sintern-method name)
+			   (idlwave-sintern-method idlw-help-name)
 			   type)))
-	    (setq link t)		; No specific link valid yet
+	    (setq idlw-help-link t)		; No specific link valid yet
 	    (if sclasses
-		(setq classes (idlwave-members-only 
+		(setq classes (idlwave-members-only
 			       classes (cons class sclasses))))
-	    (setq class (idlwave-popup-select ev classes 
+	    (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 name class)
+		       (idlwave-sintern-routine-or-method idlw-help-name class)
 		       type (idlwave-sintern-class class)))))
 
      ;; Keyword
      ((eq what 'keyword)
-      (setq kwd word)
+      (setq idlw-help-kwd word)
       (if (or (eq class t)
 	      (and (stringp class) sclasses))
 	  (let ((classes  (idlwave-all-method-keyword-classes
-			   (idlwave-sintern-method name)
-			   (idlwave-sintern-keyword kwd)
+			   (idlwave-sintern-method idlw-help-name)
+			   (idlwave-sintern-keyword idlw-help-kwd)
 			   type)))
-	    (setq link t) ; Link can't be correct yet
+	    (setq idlw-help-link t) ; Link can't be correct yet
 	    (if sclasses
-		(setq classes (idlwave-members-only 
+		(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 name class)
+			     (idlwave-sintern-routine-or-method
+			      idlw-help-name class)
 			     type (idlwave-sintern-class class)))))
-	(if (string= (downcase name) "obj_new")
+	(if (string= (downcase idlw-help-name) "obj_new")
 	    (setq class idlwave-current-obj_new-class
-		  name "Init"))))
-	  
+		  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) 
+     ((and (symbolp what)
 	   (fboundp what))
       (funcall what 'set word))
 
      (t (error "Cannot help with this item")))
-    (if (and need-class (not class) (not (and link (not (eq link t)))))
+    (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 link (or name word) type class kwd)))
+    (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)
@@ -410,14 +411,14 @@ Needs additional info stored in global `idlwave-completion-help-info'."
   "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      
+  (if idlwave-highlight-help-links-in-completion
       (with-current-buffer (get-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
+		 ;; (class (nth 3 info)) ; any class
 		 word beg end doit)
 	    (goto-char (point-min))
 	    (re-search-forward "possible completions are:" nil t)
@@ -426,13 +427,14 @@ Those words in `idlwave-completion-help-links' have links.  The
 	      (setq beg (match-beginning 1) end (match-end 1)
 		    word (match-string 1) doit nil)
 	      ;; Call special completion function test
-	      (if (and (symbolp what) 
+	      (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-ignore-case
-				word idlwave-completion-help-links))))
+		    (setq doit (assoc-string
+				word idlwave-completion-help-links
+				'ignore-case))))
 	      (when doit
 		(if (consp doit)
 		    (setq props (append props `(link ,(cdr doit)))))
@@ -442,7 +444,7 @@ Those words in `idlwave-completion-help-links' have links.  The
 
 ;; Arrange for this function to be called after completion
 (add-hook 'idlwave-completion-setup-hook
-	  'idlwave-highlight-linked-completions)
+	  #'idlwave-highlight-linked-completions)
 
 (defvar idlwave-help-return-frame nil
   "The frame to return to from the help frame.")
@@ -457,13 +459,14 @@ Those words in `idlwave-completion-help-links' have links.  The
 	     ;; 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 
+	     ;; To protect the workings, we wait for up to one second
 	     ;; and check if the return-frame *is* now selected.
-	     ;; This is marked "eperimental" since we are not sure when its OK.
+	     ;; 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) 
+			   (not (eq (selected-frame)
 				    idlwave-help-return-frame))
 			   (< (setq time (+ time step)) maxtime)))))
 	 (delete-frame idlwave-help-frame))
@@ -475,7 +478,7 @@ Those words in `idlwave-completion-help-links' have links.  The
 (defvar default-toolbar-visible-p)
 
 (defun idlwave-help-display-help-window (&optional pos-or-func)
-  "Display the (source-based) help window.  
+  "Display the (source-based) 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))
@@ -486,13 +489,13 @@ if passed as a function.  See `idlwave-help-use-dedicated-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 
+	  (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) 
+    (if pos-or-func
+	(if (functionp pos-or-func)
 	    (funcall pos-or-func)
 	  (goto-char pos-or-func)
 	  (recenter 0)))
@@ -514,44 +517,44 @@ if passed as a function.  See `idlwave-help-use-dedicated-frame'."
       (select-frame idlwave-help-return-frame)))
 
 (defun idlwave-online-help (link &optional name type class keyword entry)
-  "Display HTML or other special help on a certain topic.  
+  "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
+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) 
+  (if (eq link t)
       (let ((entry (or entry
-		       (idlwave-best-rinfo-assoc name type class 
+		       (idlwave-best-rinfo-assoc name type class
 						 (idlwave-routines) nil t))))
 	(if entry
 	    (cond
 	     ;; Try keyword link
-	     ((and keyword 
-		    (setq link (cdr 
+	     ((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 
+	  (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 
+	      (message
 	       (concat "No routine info for %s"
 		       ", falling back on class help.")
 	       (idlwave-make-full-name class name))))))
 
   (cond
    ;; An explicit link
-   ((stringp 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))))
 
@@ -561,7 +564,7 @@ see if a link is set for it.  Try extra help functions if necessary."
   (let* ((cw (selected-window))
 	 (help-pos (with-current-buffer (idlwave-help-get-help-buffer)
 		     (let ((buffer-read-only nil))
-		       (funcall idlwave-extra-help-function 
+		       (funcall idlwave-extra-help-function
 				name type class keyword)))))
     (if help-pos
 	(idlwave-help-display-help-window help-pos)
@@ -569,7 +572,7 @@ see if a link is set for it.  Try extra help functions if necessary."
     (select-window cw)))
 
 (defun idlwave-help-html-link (link)
-  "Get html help on a given LINK."
+  "Get HTML help on a given LINK."
   (let* ((browse-url-browser-function idlwave-help-browser-function)
 	 (browse-url-generic-program idlwave-help-browser-generic-program)
 	 (help-loc (idlwave-html-help-location))
@@ -581,7 +584,7 @@ see if a link is set for it.  Try extra help functions if necessary."
 		(and (stringp help-loc)
 		     (file-directory-p help-loc)))
       (error "Invalid help request"))
-    
+
     ;; If possible, subsume as anchor under idl.htm, new as of IDL 8.3
     (if (file-exists-p alternate)
 	(setq link (file-relative-name link help-loc)
@@ -596,7 +599,7 @@ see if a link is set for it.  Try extra help functions if necessary."
 
      ((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))))
+      (idlwave-help-display-help-window (lambda () (browse-url full-link))))
 
      (t (browse-url full-link)))))
 
@@ -606,14 +609,14 @@ see if a link is set for it.  Try extra help functions if necessary."
 (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.
+  "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)
@@ -626,7 +629,7 @@ This function can be used as `idlwave-extra-help-function'."
     (if class-only   ;Help with class?  Using "Init" as source.
 	(setq name "Init"
 	      type 'fun))
-    (if (not struct-tag) 
+    (if (not struct-tag)
 	(setq file
 	      (idlwave-routine-source-file
 	       (nth 3 (idlwave-best-rinfo-assoc
@@ -639,14 +642,14 @@ This function can be used as `idlwave-extra-help-function'."
     (if (or struct-tag (stringp file))
 	(progn
 	  (setq in-buf ; structure-tag completion is always in current buffer
-		(if struct-tag 
+		(if struct-tag
 		    idlwave-current-tags-buffer
-		  (idlwave-get-buffer-visiting file)))
+                  (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)		
+		(erase-buffer)
 		(insert-buffer-substring in-buf))
 	    (if (file-exists-p file) ;; otherwise just load the file
 		(progn
@@ -662,19 +665,19 @@ This function can be used as `idlwave-extra-help-function'."
     ;; Try to find a good place to display
     (setq def-pos
 	  ;; Find the class structure tag if that's what we're after
-	  (cond 
+	  (cond
 	   ;; Class structure tags: find the class or named structure
 	   ;; definition
 	   (class-struct-tag
-	    (save-excursion 
+	    (save-excursion
 	      (setq class
-		    (if (string-match "[a-zA-Z0-9]\\(__\\)" name) 
+		    (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'
@@ -684,14 +687,14 @@ This function can be used as `idlwave-extra-help-function'."
 	       (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 
+    (if (and idlwave-help-source-try-header
 	     (not (or struct-tag class-struct-tag)))
 	;; Check if we can find the header
 	(save-excursion
@@ -701,7 +704,7 @@ This function can be used as `idlwave-extra-help-function'."
 		idlwave-help-in-header header-pos)))
 
     (if (or header-pos def-pos)
-	(progn 
+	(progn
 	  (if (boundp 'idlwave-help-min-frame-width)
 	      (setq idlwave-help-min-frame-width 80))
 	  (goto-char (or header-pos def-pos)))
@@ -709,12 +712,14 @@ This function can be used as `idlwave-extra-help-function'."
 
     (point)))
 
-(defun idlwave-help-find-routine-definition (name type class keyword)
+
+(defun idlwave-help-find-routine-definition (name type class _keyword)
   "Find the definition of routine CLASS::NAME in current buffer.
-KEYWORD is ignored. Returns the point of match if successful, nil otherwise."
+Returns the point of match if successful, nil otherwise.
+KEYWORD is ignored."
   (save-excursion
     (goto-char (point-max))
-    (if (re-search-backward 
+    (if (re-search-backward
 	 (concat "^[ \t]*"
 		 (if (eq type 'pro) "pro"
 		   (if (eq type 'fun) "function"
@@ -728,7 +733,7 @@ KEYWORD is ignored. Returns the point of match if successful, nil otherwise."
 
 (defvar idlwave-doclib-start)
 (defvar idlwave-doclib-end)
-(defun idlwave-help-find-in-doc-header (name type class keyword
+(defun idlwave-help-find-in-doc-header (name _type class keyword
 					     &optional exact)
   "Find the requested help in the doc-header above point.
 
@@ -744,12 +749,12 @@ 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
-particlar it looks for the `NAME:' tag, either with a colon, or alone
+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 inconsisten this is through
+`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 fould we search
+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
@@ -760,22 +765,22 @@ 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 
+		    (concat
 		     "\\("
 		     ;; Traditional name or class::name
 		     "\\("
 		     "\\(" (regexp-quote (downcase class)) "::\\)?"
 		     (regexp-quote (downcase name))
 		     "\\>\\)"
-		     (concat 
+		     (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 
+	 (name-re (concat
 		   "\\(^;+\\*?[ \t]*"
 		   idlwave-help-doclib-name
 		   "\\([ \t]*:\\|[ \t]*$\\)[ \t]*\\(\n;+[ \t]*\\)*"
@@ -786,9 +791,9 @@ If there is a match, we assume it is the keyword description."
 		   ":[ \t]*$\\)"))
 
 	 ;; Header start plus name
-	 (header-re (concat "\\(" idlwave-doclib-start "\\).*\n"
-			    "\\(^;+.*\n\\)*"
-			    "\\(" name-re "\\)"))
+	 ;; (header-re (concat "\\(" idlwave-doclib-start "\\).*\n"
+	 ;;        	    "\\(^;+.*\n\\)*"
+	 ;;        	    "\\(" name-re "\\)"))
 	 ;; A keywords section
 	 (kwds-re (concat		                    ; forgiving
 		   "^;+\\*?[ \t]*"
@@ -810,7 +815,7 @@ If there is a match, we assume it is the keyword description."
 		       (regexp-quote (upcase keyword))
 		      "\\>")))
 	 dstart dend name-pos kwds-pos kwd-pos)
-    (catch 'exit 
+    (catch 'exit
       (save-excursion
 	(goto-char (point-min))
 	(while (and (setq dstart (re-search-forward idlwave-doclib-start nil t))
@@ -818,7 +823,7 @@ If there is a match, we assume it is the keyword description."
 	  ;; found a routine header
 	  (goto-char dstart)
 	  (if (setq name-pos (re-search-forward name-re dend t))
-	      (progn 
+	      (progn
 		(if keyword
 		    ;; We do need a keyword
 		    (progn
@@ -856,8 +861,8 @@ When DING is non-nil, ring the bell as well."
 	      (cons string idlwave-help-diagnostics))
 	(if ding (ding)))))
 
-(defun idlwave-help-toggle-header-top-and-def (arg)
-  (interactive "P")
+(defun idlwave-help-toggle-header-top-and-def (&optional _arg)
+  (interactive)
   (let (pos)
     (if idlwave-help-in-header
 	;; Header was the last thing displayed
@@ -880,8 +885,8 @@ When DING is non-nil, ring the bell as well."
 	  (goto-char pos)
 	  (recenter 0)))))
 
-(defun idlwave-help-find-first-header (arg)
-  (interactive "P")
+(defun idlwave-help-find-first-header (&optional _arg)
+  (interactive)
   (let (pos)
     (save-excursion
       (goto-char (point-min))
@@ -900,9 +905,9 @@ When DING is non-nil, ring the bell as well."
       (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 (arg &optional top)
-  (interactive "P")
+
+(defun idlwave-help-toggle-header-match-and-def (&optional _arg top)
+  (interactive)
   (let ((args idlwave-help-args)
 	pos)
     (if idlwave-help-in-header
@@ -911,8 +916,8 @@ When DING is non-nil, ring the bell as well."
 	  (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 
+      (setq pos (apply #'idlwave-help-find-in-doc-header
+		       (if top
 			   (list (car args) (nth 1 args) (nth 2 args) nil)
 			 args)))
       (if pos
@@ -925,7 +930,6 @@ When DING is non-nil, ring the bell as well."
 	  (goto-char pos)
 	  (recenter 0)))))
 
-(defvar font-lock-verbose)
 (defvar idlwave-mode-syntax-table)
 (defvar idlwave-font-lock-defaults)
 (defun idlwave-help-fontify ()
@@ -933,16 +937,18 @@ When DING is non-nil, ring the bell as well."
 Useful when source code is displayed as help.  See the option
 `idlwave-help-fontify-source-code'."
   (interactive)
-  (if (featurep 'font-lock)
-      (let ((major-mode 'idlwave-mode)
-	    (font-lock-verbose
-	     (if (interactive-p) font-lock-verbose nil)))
-	(set-syntax-table idlwave-mode-syntax-table)
-	(set (make-local-variable 'font-lock-defaults)
-	     idlwave-font-lock-defaults)
-	(font-lock-fontify-buffer))))
-      
-(defun idlwave-help-error (name type class keyword)
+  (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>")
@@ -952,22 +958,15 @@ Useful when source code is displayed as help.  See the option
 	   "(help location unknown)")))
 
 (defun idlwave-help-show-help-frame ()
-  "Show the help frame, creating it if necessary"
+  "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.
-    (if (fboundp 'set-specifier)
-	(progn
-	  ;; XEmacs
-	  (let ((sval (cons idlwave-help-frame nil)))
-	    ;; (set-specifier menubar-visible-p sval)
-	    (set-specifier default-toolbar-visible-p sval)))
-      ;; Emacs
-      (modify-frame-parameters idlwave-help-frame
-			       '(;;(menu-bar-lines . 0)
-				 (tool-bar-lines . 0)))))
+    (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 ()
@@ -1005,16 +1004,16 @@ Useful when source code is displayed as help.  See the option
     (unless topic
       (idlwave-routines)
       (setq list (append (mapcar (lambda (x)
-				   (cons (idlwave-make-full-name x) 
+				   (cons (idlwave-make-full-name x)
 					 (idlwave-routine-first-link-file x)))
 				 idlwave-system-routines)
 			 (mapcar (lambda (x)
 				   (cons (concat "." (car x)) (cdr x)))
 				 idlwave-executive-commands-alist)
-			 (mapcar (lambda (x) 
+			 (mapcar (lambda (x)
 				   (cons (car x) (nth 1 (assq 'link x))))
 				 idlwave-system-class-info))
-	    topic  (idlwave-completing-read 
+	    topic  (idlwave-completing-read
 		    "Help Topic: " list
 		    nil nil nil
 		    'idlwave-help-with-topic-history)))
@@ -1034,40 +1033,40 @@ Useful when source code is displayed as help.  See the option
 		(> (length idlwave-html-system-help-location) 0)
 		(file-exists-p (setq help-dir
 				     (expand-file-name
-				      idlwave-system-html-help-location 
+				      idlwave-system-html-help-location
 				      sys-dir))))
 	   help-dir) ;; And explicitly specified directory
 
-	  ((file-exists-p (setq help-dir 
-				(expand-file-name 
+	  ((file-exists-p (setq help-dir
+				(expand-file-name
 				 "help/online_help/Subsystems/idl/Content" sys-dir)))
 	   help-dir) ;; IDL 8.6
-	  
-	  ((file-exists-p (setq help-dir 
-				(expand-file-name 
+
+	  ((file-exists-p (setq help-dir
+				(expand-file-name
 				 "help/online_help/IDL/Content" sys-dir)))
 	   help-dir) ;; IDL 8.0-8.5
 
-	  ((file-exists-p (setq help-dir 
+	  ((file-exists-p (setq help-dir
 				(expand-file-name "help/online_help/" sys-dir)))
 	   help-dir) ;; IDL 6.3-7.0
 
-	  ((file-exists-p (setq help-dir 
+	  ((file-exists-p (setq help-dir
 				(expand-file-name "help/" sys-dir)))
 	   help-dir)))) ;; IDL <6.3
 
 
 (defvar idlwave-help-use-eclipse-help nil)
 (defun idlwave-help-check-locations ()
-  ;; Check help locations, etc. 
+  ;; Check help locations, etc.
   (if (not (file-directory-p (idlwave-sys-dir)))
       (message "IDL system directory not found: try setting `idlwave-system-directory' or IDL_DIR."))
 
   ;; see if we have eclipse (or nothing)
   (setq idlwave-help-use-eclipse-help
 	(and (file-executable-p (idlwave-help-eclipse-help-command))
-	     (file-exists-p (expand-file-name "idl_catalog.xml" 
-					      (expand-file-name 
+	     (file-exists-p (expand-file-name "idl_catalog.xml"
+					      (expand-file-name
 					       "help" (idlwave-sys-dir))))
 	     (not (file-directory-p (idlwave-html-help-location))))))
 
@@ -1081,8 +1080,8 @@ Useful when source code is displayed as help.  See the option
   (if (memq system-type '(ms-dos windows-nt))
       "idlde/idlhelp.exe"
     "bin/idlhelp")
-  "The command, rooted at idlwave-system-directory, which invokes the
-the idlhelp script.")
+  "The command, rooted at `idlwave-system-directory', which invokes the
+the \"idlhelp\" script.")
 
 (defun idlwave-help-eclipse-help-command ()
   (expand-file-name idlwave-help-eclipse-help-command (idlwave-sys-dir)))
@@ -1092,13 +1091,13 @@ the idlhelp script.")
 (defun idlwave-help-eclipse-help-open-link (&optional link)
   "Start IDL Eclipse-Help (if needed), loading link FULL-LINK, if passed."
   (let ((command (idlwave-help-eclipse-help-command)))
-    (if (string-match "\.html$" link) ;; Strip HTML, unless anchored
+    (if (string-match "\\.html\\'" link) ;; Strip HTML, unless anchored
 	(setq link (substring link 0 (match-beginning 0))))
     (if (not idlwave-help-eclipse-hook-added)
-	(add-hook 'kill-emacs-hook 'idlwave-help-eclipse-kill)
+	(add-hook 'kill-emacs-hook #'idlwave-help-eclipse-kill)
 	(setq idlwave-help-eclipse-hook-added t))
-    (apply 'call-process command nil 0 nil (if link `("-topic" ,link)))))
-  
+    (apply #'call-process command nil 0 nil (if link `("-topic" ,link)))))
+
 (defun idlwave-help-eclipse-kill ()
   (let ((command (idlwave-help-eclipse-help-command)))
     (call-process command nil 0 nil "-command" "shutdown")))
@@ -1110,7 +1109,3 @@ the idlhelp script.")
 
 ;; arch-tag: d27b5505-59de-497f-ba3f-f199fd4fb911
 ;;; idlw-help.el ends here
-
-
-
-(defvar idlwave-system-routines)
diff --git a/idlw-menus.el b/idlw-menus.el
index 0e9678c159..e30ade61d8 100644
--- a/idlw-menus.el
+++ b/idlw-menus.el
@@ -1,18 +1,19 @@
-;; IDLWAVE menus and associated code
+;;; IDLWAVE menus and associated code  -*- lexical-binding: t; -*-
+
+;;; Code:
+
+;; Define the mode-maps before we modify them.
+(require 'idlw-variables)
+(require 'idlw-bindings)
 
 ;; Define - using easymenu.el
-(defvar idlwave-mode-menu)  
+(defvar idlwave-mode-menu)
 (defvar idlwave-mode-debug-menu)
 
-(defalias 'idlwave-function-menu
-  (condition-case nil
-      (progn
-	(require 'imenu)
-	'imenu)
-    (error nil)))
+(define-obsolete-function-alias 'idlwave-function-menu #'imenu "29.1")
 (defvar idlwave-mode-menu-def
   `("IDLWAVE"
-    ["PRO/FUNC menu" idlwave-function-menu t]
+    ["PRO/FUNC menu" imenu t]
     ("Motion"
      ["Subprogram Start" idlwave-beginning-of-subprogram t]
      ["Subprogram End" idlwave-end-of-subprogram t]
@@ -27,14 +28,14 @@
      ["Block" idlwave-mark-block t]
      ["Header" idlwave-mark-doclib t])
     ("Format"
-     ["Indent Entire Statement" idlwave-indent-statement 
+     ["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" idlwave-auto-fill-mode :style toggle
-      :selected (symbol-value idlwave-fill-function)])
+     ["Toggle Auto Fill" auto-fill-mode :style toggle
+      :selected auto-fill-function])
     ("Templates"
      ["Procedure" idlwave-procedure t]
      ["Function" idlwave-function t]
@@ -88,7 +89,7 @@
      ["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])
@@ -96,8 +97,7 @@
     ("Customize"
      ["Browse IDLWAVE Group" idlwave-customize t]
      "--"
-     ["Build Full Customize Menu" idlwave-create-customize-menu 
-      (fboundp 'customize-menu-create)])
+     ["Build Full Customize Menu" idlwave-create-customize-menu t])
     ("Documentation"
      ["Describe Mode" describe-mode t]
      ["Abbreviation List" idlwave-list-abbrevs t]
@@ -114,17 +114,15 @@
   '("Debug"
     ["Start IDL shell" idlwave-shell t]
     ["Save and .RUN buffer" idlwave-shell-save-and-run
-     (and (boundp 'idlwave-shell-automatic-start) 
+     (and (boundp 'idlwave-shell-automatic-start)
 	  idlwave-shell-automatic-start)]))
 
-(if (or (featurep 'easymenu) (load "easymenu" t))
-    (progn
-      (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)))
+(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)
 
 
 ;;----------------------------------------------------
@@ -132,7 +130,7 @@
 (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 
+  ;; Try to load the code for the shell, so that we can customize it
   ;; as well.
   (or (featurep 'idlw-shell)
       (load "idlw-shell" t))
@@ -141,24 +139,20 @@
 (defun idlwave-create-customize-menu ()
   "Create a full customization menu for IDLWAVE, insert it into the menu."
   (interactive)
-  (if (fboundp 'customize-menu-create)
-      (progn
-	;; 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"))
-    (error "Cannot expand menu (outdated version of cus-edit.el)")))
+  ;; Try to load the code for the shell, so that we can customize it
+  ;; as well.
+  (require 'idlw-shell)
+  (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'."
@@ -189,10 +183,10 @@ 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 (symbol-value 'idlwave-mode-abbrev-table))
+  (let ((table idlwave-mode-abbrev-table)
 	abbrevs
 	str rpl func fmt (len-str 0) (len-rpl 0))
-    (mapatoms 
+    (mapatoms
      (lambda (sym)
        (if (symbol-value sym)
 	   (progn
@@ -218,7 +212,7 @@ This function was written since `list-abbrevs' looks terrible for IDLWAVE mode."
     (with-output-to-temp-buffer "*Help*"
       (if arg
 	  (progn
-	    (princ "Abbreviations and Actions in IDLWAVE-Mode\n") 
+	    (princ "Abbreviations and Actions in IDLWAVE-Mode\n")
 	    (princ "=========================================\n\n")
 	    (princ (format fmt "KEY" "REPLACE" "HOOK"))
 	    (princ (format fmt "---" "-------" "----")))
@@ -226,13 +220,11 @@ This function was written since `list-abbrevs' looks terrible for IDLWAVE mode."
 	(princ "================================================\n\n")
 	(princ (format fmt "KEY" "ACTION" ""))
 	(princ (format fmt "---" "------" "")))
-      (mapcar
-       (lambda (list)
-	 (setq str (car list)
-	       rpl (nth 1 list)
-	       func (nth 2 list))
-	 (princ (format fmt str rpl func)))
-       abbrevs)))
+      (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)))
@@ -244,9 +236,8 @@ This function was written since `list-abbrevs' looks terrible for IDLWAVE mode."
 
 ;; Define the menu for the Help application
 
-(easy-menu-define
-  idlwave-help-menu idlwave-help-mode-map
-  "Menu for Help IDLWAVE system"
+(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]
diff --git a/idlw-roprompt.el b/idlw-roprompt.el
index d50cdccd10..c6ee4d282a 100644
--- a/idlw-roprompt.el
+++ b/idlw-roprompt.el
@@ -1,5 +1,5 @@
-;; idlw-shell.el --- run IDL as an inferior process of Emacs.
-;; Copyright (c) 2002 Free Software Foundation
+;;; idlw-reprompt.el --- run IDL as an inferior process of Emacs.  -*- lexical-binding: t; -*-
+;; Copyright (c) 2002-2024 Free Software Foundation
 
 ;; Author: J.D. Smith <jdsmith <at> as.arizona.edu>
 ;; Maintainer: J.D. Smith <jdsmith <at> as.arizona.edu>
@@ -32,11 +32,11 @@
 ;;
 ;; New versions of IDLWAVE, documentation, and more information
 ;; available from:
-;;                 http://github.com/jdtsmith/idlwave
+;;                 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 .emacs file:
@@ -50,9 +50,9 @@
 ;;
 ;;   The newest version of this file can be found on the maintainers
 ;;   web site.
-;; 
-;;     http://github.com/jdtsmith/idlwave
-;; 
+;;
+;;     https://github.com/jdtsmith/idlwave
+;;
 ;; DOCUMENTATION
 ;; =============
 ;;
@@ -63,7 +63,7 @@
 ;;
 ;; KNOWN PROBLEMS
 ;; ==============
-;; 
+;;
 ;; This functionality will probably fail for some future version of
 ;; comint, given how explicitly
 ;;
@@ -71,71 +71,69 @@
 ;;
 
 ;;; Code:
-(when (fboundp 'comint-snapshot-last-prompt)
-  (defvar idlwave-shell-save-comint-last-prompt-overlay nil)
-  (defun idlwave-shell-comint-signal-read-only (overlay after start end 
-							&optional len)
-    (if (and (not after)
-	     (or (< (overlay-start overlay) start)
-		 (> (overlay-end overlay) end)))
-	(error "")))
+(defvar idlwave-shell-save-comint-last-prompt-overlay nil)
+(defun idlwave-shell-comint-signal-read-only (overlay after start end
+						      &optional _len)
+  (if (and (not after)
+	   (or (< (overlay-start overlay) start)
+	       (> (overlay-end overlay) end)))
+      (error "")))
 
-  ;; Caution: in Emacs <~21.2, a new overlay gets created for each
-  ;; prompt... in later versions, text-properties for old prompts
-  ;; are used instead, and the original overlay is recycled.  In
-  ;; this case, we can advise snapshot-prompt to remove the
-  ;; read-only text properties (not the overlay properties), and
-  ;; here we test to ensure the prompt isn't in the same position as
-  ;; the process-mark before removing the read-only stuff.
-  (defadvice idlwave-shell-comint-filter (around swap-read-only activate)
-    "Add a read-only equivalency to the last prompt overlay."
-;    (when (and idlwave-shell-save-comint-last-prompt-overlay 
-;	       (not (equal
-;		     (marker-position (process-mark 
-;				       (get-buffer-process 
-;					(get-buffer (idlwave-shell-buffer)))))
-;		     (overlay-end 
-;		      idlwave-shell-save-comint-last-prompt-overlay))))
-;      (setq save-overlay idlwave-shell-save-comint-last-prompt-overlay)
+;; Caution: in Emacs <~21.2, a new overlay gets created for each
+;; prompt... in later versions, text-properties for old prompts
+;; are used instead, and the original overlay is recycled.  In
+;; this case, we can advise snapshot-prompt to remove the
+;; read-only text properties (not the overlay properties), and
+;; here we test to ensure the prompt isn't in the same position as
+;; the process-mark before removing the read-only stuff.
+(advice-add 'idlwave-shell-comint-filter :around #'idlwave--swap-read-only)
+(defun idlwave--swap-read-only (orig-fun &rest args)
+  "Add a read-only equivalency to the last prompt overlay."
+  ;; (when (and idlwave-shell-save-comint-last-prompt-overlay
+  ;;             (not (equal
+  ;;      	     (marker-position (process-mark
+  ;;      			       (get-buffer-process
+  ;;      				(get-buffer (idlwave-shell-buffer)))))
+  ;;      	     (overlay-end
+  ;;      	      idlwave-shell-save-comint-last-prompt-overlay))))
+  ;;   (setq save-overlay idlwave-shell-save-comint-last-prompt-overlay)
 
-    
 
-    ;; Remove the read-only status in case comint needs to do
-    ;; something with the prompt area.
-    (save-current-buffer
-      (set-buffer (idlwave-shell-buffer))
-      (when (and idlwave-shell-save-comint-last-prompt-overlay
-		 (not (eq idlwave-shell-save-comint-last-prompt-overlay 
-			  comint-last-prompt-overlay)))
-	(overlay-put idlwave-shell-save-comint-last-prompt-overlay 
-		     'insert-in-front-hooks nil)
-	(overlay-put idlwave-shell-save-comint-last-prompt-overlay
-		     'modification-hooks nil))
-      (when comint-last-prompt-overlay
-	(overlay-put comint-last-prompt-overlay 'insert-in-front-hooks nil)
-	(overlay-put comint-last-prompt-overlay 'modification-hooks nil)))
 
-    ad-do-it
-    
-    (save-current-buffer
-      (set-buffer (idlwave-shell-buffer))
+  ;; Remove the read-only status in case comint needs to do
+  ;; something with the prompt area.
+  (with-current-buffer (idlwave-shell-buffer)
+    (when (and idlwave-shell-save-comint-last-prompt-overlay
+	       (not (eq idlwave-shell-save-comint-last-prompt-overlay
+			comint-last-prompt-overlay)))
+      (overlay-put idlwave-shell-save-comint-last-prompt-overlay
+		   'insert-in-front-hooks nil)
+      (overlay-put idlwave-shell-save-comint-last-prompt-overlay
+		   'modification-hooks nil))
+    (when comint-last-prompt-overlay
+      (overlay-put comint-last-prompt-overlay 'insert-in-front-hooks nil)
+      (overlay-put comint-last-prompt-overlay 'modification-hooks nil)))
+
+  (prog1 (apply orig-fun args)
+
+    (with-current-buffer (idlwave-shell-buffer)
       (when comint-last-prompt-overlay
-	(setq idlwave-shell-save-comint-last-prompt-overlay 
+	(setq idlwave-shell-save-comint-last-prompt-overlay
 	      comint-last-prompt-overlay)
-	(overlay-put comint-last-prompt-overlay 'modification-hooks 
+	(overlay-put comint-last-prompt-overlay 'modification-hooks
 		     '(idlwave-shell-comint-signal-read-only))
-	(overlay-put comint-last-prompt-overlay 'insert-in-front-hooks 
-		     '(idlwave-shell-comint-signal-read-only)))))
+	(overlay-put comint-last-prompt-overlay 'insert-in-front-hooks
+		     '(idlwave-shell-comint-signal-read-only))))))
 
-  (defadvice comint-snapshot-last-prompt (after remove-text-read-only activate)
-    "Remove the read-only text properties potentially set by snapshot"
-    (save-current-buffer
-      (set-buffer (idlwave-shell-buffer))
-      (when comint-last-prompt-overlay
-	(remove-text-properties 
-	 (overlay-start comint-last-prompt-overlay)
-	 (overlay-end comint-last-prompt-overlay)
-	 '(modification-hooks nil insert-in-front-hooks nil))))))
+(advice-add 'comint-snapshot-last-prompt :after #'idlwave--remove-text-read-only)
+(defun idlwave--remove-text-read-only (&rest _)
+  "Remove the read-only text properties potentially set by snapshot."
+  (with-current-buffer (idlwave-shell-buffer)
+    (when comint-last-prompt-overlay
+      (remove-text-properties
+       (overlay-start comint-last-prompt-overlay)
+       (overlay-end comint-last-prompt-overlay)
+       '(modification-hooks nil insert-in-front-hooks nil)))))
 
 (provide 'idlw-roprompt)
-;;; idlw-roprompt.el ends here
\ No newline at end of file
+;;; idlw-roprompt.el ends here
diff --git a/idlw-routine.el b/idlw-routine.el
index 7ea2881862..fa20b09256 100644
--- a/idlw-routine.el
+++ b/idlw-routine.el
@@ -1,4 +1,4 @@
-;; IDLWAVE Routine Information code and variables
+;; IDLWAVE Routine Information code and variables  -*- lexical-binding: t; -*-
 
 ;; The list format for all routine info user catalog, library
 ;; catalogs, etc.:
@@ -6,7 +6,7 @@
 ;; ("ROUTINE" type class
 ;;  (system nil nil nil) | (lib pro_file dir "LIBNAME") | (user pro_file dir "USERLIB") |
 ;;  (buffer pro_file dir) | (compiled pro_file dir)
-;;   "calling_string" ("LINKFILE" (("KWD1" . anchorlink1) ...)) 
+;;   "calling_string" ("LINKFILE" (("KWD1" . anchorlink1) ...))
 ;;                    ("LINKFILE2" (("KWD2" . ancorlink2) ...)) ...)
 ;;
 ;; DIR will be supplied dynamically while loading library catalogs,
@@ -17,6 +17,10 @@
 ;; referenced in multiples files (e.g. Graphics Keywords), there are
 ;; multiple keyword link lists.
 
+;;; Code:
+
+(require 'idlw-variables)
+(require 'idlw-scan)                    ;For `idlwave-routines' var.
 
 ;;----------------------------------------------------
 ;; Convenience Routines for routine info lists
@@ -34,7 +38,9 @@
 ;;----------------------------------------------------
 ;; Routine Info
 
-(defun idlwave-routine-info (&optional arg external)
+(defvar idlwave-force-class-query)
+
+(defun idlwave-routine-info (&optional arg _external)
   "Display a routine's 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
@@ -71,7 +77,7 @@ arg, the class property is cleared out."
 	   (idlwave-force-class-query (equal arg '(4)))
 	   (module (idlwave-what-module)))
       (if (car module)
-	  (apply 'idlwave-display-calling-sequence
+	  (apply #'idlwave-display-calling-sequence
 		 (idlwave-fix-module-if-obj_new module))
 	(error "Don't know which calling sequence to show")))))
 
@@ -80,7 +86,7 @@ arg, the class property is cleared out."
 
 (defun idlwave-rinfo-assoc (name type class list)
   "Like `idlwave-rinfo-assq', but sintern strings first."
-  (idlwave-rinfo-assq 
+  (idlwave-rinfo-assq
    (idlwave-sintern-routine-or-method name class)
    type (idlwave-sintern-class class) list))
 
@@ -95,7 +101,7 @@ arg, the class property is cleared out."
 	     (throw 'exit match))
 	(setq list (cdr (memq match list)))))))
 
-(defun idlwave-best-rinfo-assq (name type class list &optional with-file 
+(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
@@ -106,7 +112,7 @@ syslib files."
 		list))
 	syslibp)
     (when (> (length twins) 1)
-      (setq twins (sort twins 'idlwave-routine-entry-compare-twins))
+      (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)))
@@ -120,7 +126,7 @@ syslib files."
 				    twins)))))
     (car twins)))
 
-(defun idlwave-best-rinfo-assoc (name type class list &optional with-file 
+(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
@@ -130,7 +136,7 @@ syslib files."
 (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)))
-	 class rtn)
+	 rtn) ;; class
     (while classes
       (if (setq rtn (idlwave-rinfo-assq name type (pop classes) list))
 	  (setq classes nil)))
@@ -157,30 +163,31 @@ ENTRY will also be returned, as the first item of this list."
 	       (eq type (nth 1 candidate))
 	       (eq class (nth 2 candidate)))
 	  (push candidate twins)))
-    (if (setq candidate (idlwave-rinfo-assq name type class 
+    (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-class)
+;; 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.  
+  "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))
-	 (name (car entry))      ; 
-	 (type (nth 1 entry))    ; Must be bound for
-	 (idlwave-class (nth 2 entry))   ;  idlwave-routine-twin-compare
+	 (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 type-cons file alist syslibp key)
+	 source type-cons file alist syslibp key)
     (while (setq entry (pop entries))
-      (incf cnt)
+      (cl-incf cnt)
       (setq source (nth 3 entry)
 	    type (car source)
 	    type-cons (cons type (nth 3 source))
@@ -192,29 +199,29 @@ routines, and may have been scanned."
 		      (t 'unresolved)))
 
       ;; Check for an entry in the system library
-      (if (and file 
+      (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)))
+    (sort alist #'idlwave-routine-twin-compare)))
 
 (defun idlwave-routine-entry-compare (a b)
   "Compare two routine info entries for sorting.
@@ -236,7 +243,7 @@ names and path locations."
      ((not (eq type (nth 1 b)))
       ;; Type decides
       (< (if (eq type 'fun) 1 0) (if (eq (nth 1 b) 'fun) 1 0)))
-     (t	
+     (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)))))
@@ -244,9 +251,9 @@ names and path locations."
 (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* ((name (car a)) 
-	 (type (nth 1 a)) 
-	 (idlwave-class (nth 2 a)) ; needed outside
+  (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))
@@ -254,20 +261,16 @@ This basically calls `idlwave-routine-twin-compare' with the correct args."
 	 (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))))
-    ))
-
+     (list (if (stringp afile) (file-truename afile) atype)
+	   afile (list atype))
+     (list (if (stringp bfile) (file-truename bfile) 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 CLASS to be bound to the right values."
+This expects `idlwave-twin-name' and `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))
@@ -290,7 +293,7 @@ This expects NAME TYPE CLASS to be bound to the right values."
 	 (tpath-alist (idlwave-true-path-alist))
 	 (apathp (and (stringp akey)
 		      (assoc (file-name-directory akey) tpath-alist)))
-	 (bpathp (and (stringp bkey) 
+	 (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
@@ -299,52 +302,55 @@ This expects NAME TYPE CLASS to be bound to the right values."
 	 ;; 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-class (format "\\`%s__\\(%s\\|define\\)\\.pro\\'"
-					     (regexp-quote 
-					      (downcase idlwave-class))
-					     (regexp-quote (downcase name)))
-		     (format "\\`%s\\.pro" (regexp-quote (downcase name)))))
+	 (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-class anamep 
+	 (adefp (and idlwave-twin-class anamep
 		     (string= "define" (match-string 1 aname))))
 	 (bnamep (string-match fname-re bname))
-	 (bdefp (and idlwave-class bnamep 
+	 (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
-     ((idlwave-xor asysp  bsysp)       asysp)	; System entries first
-     ((idlwave-xor aunresp bunresp)    bunresp) ; Unresolved last
+     ((xor asysp  bsysp)       asysp)	; System entries first
+     ((xor aunresp bunresp)    bunresp) ; Unresolved last
      ((and idlwave-sort-prefer-buffer-info
-	   (idlwave-xor abufp bbufp))  abufp)	; Buffers before non-buffers
-     ((idlwave-xor acompp bcompp)      acompp)	; Compiled entries
-     ((idlwave-xor apathp bpathp)      apathp)	; Library before non-library
-     ((idlwave-xor anamep bnamep)      anamep)	; Correct file names first
-     ((and idlwave-class anamep bnamep          ; both file names match ->
-	   (idlwave-xor adefp bdefp))  bdefp)	; __define after __method
+	   (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-list-buffer-load-path-shadows (&optional arg)
+(defun idlwave-list-buffer-load-path-shadows (&optional _arg)
   "List the load path shadows of all routines defined in current buffer."
-  (interactive "P")
+  (interactive)
   (idlwave-routines)
-  (if (eq major-mode 'idlwave-mode)
+  (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)
+(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
+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 "P")
+  (interactive)
   (cond
    ((or (not (fboundp 'idlwave-shell-is-running))
 	(not (idlwave-shell-is-running)))
@@ -355,15 +361,15 @@ with this command."
     (idlwave-list-load-path-shadows nil idlwave-compiled-routines
 				    "in the shell"))))
 
-(defun idlwave-list-all-load-path-shadows (&optional arg)
+(defun idlwave-list-all-load-path-shadows (&optional _arg)
   "List the load path shadows of all routines known to IDLWAVE."
-  (interactive "P")
+  (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)
+(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.
@@ -374,7 +380,7 @@ 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 
+    (or (y-or-n-p
 	 "You don't have any user or library catalogs.  Continue anyway? ")
 	(error "Abort")))
   (let* ((routines (append idlwave-system-routines
@@ -383,11 +389,10 @@ can be used to detect possible name clashes during this process."
 			   idlwave-user-catalog-routines
 			   idlwave-buffer-routines
 			   nil))
-	 (km-prop (if (featurep 'xemacs) 'keymap 'local-map))
 	 (keymap (make-sparse-keymap))
 	 (props (list 'mouse-face 'highlight
-		      km-prop keymap
-		      'help-echo "Mouse2: Find source"))      
+		      'local-map keymap
+		      'help-echo "Mouse2: Find source"))
 	 (nroutines (length (or special-routines routines)))
 	 (step (max 1 (/ nroutines 100)))
 	 (n 0)
@@ -409,24 +414,25 @@ can be used to detect possible name clashes during this process."
 					       (nth 2 b) (car b)))))))
     (message "Sorting routines...done")
 
-    (define-key keymap (if (featurep 'xemacs) [(button2)] [(mouse-2)])
-      (lambda (ev) 
+    (define-key keymap [mouse-2]
+      (lambda (ev)
 	(interactive "e")
 	(mouse-set-point ev)
-	(apply 'idlwave-do-find-module
+	(apply #'idlwave-do-find-module
 	       (get-text-property (point) 'find-args))))
-    (define-key keymap [(return)]
-      (lambda () 
+    (define-key keymap "\r"
+      (lambda ()
 	(interactive)
-	(apply 'idlwave-do-find-module
+	(apply #'idlwave-do-find-module
 	       (get-text-property (point) 'find-args))))
+    ;; FIXME: Use `make-progress-reporter'.
     (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%%)" (/ (* n 100) nroutines)))
+	    (message "Compiling list...(%2d%%)" (floor (* n 100.0) nroutines)))
 
 	;; Get a list of all twins
 	(setq twins (idlwave-routine-twins routine (or lroutines routines)))
@@ -439,15 +445,15 @@ can be used to detect possible name clashes during this process."
 		  (> (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))
-	  (incf cnt)
+	  (cl-incf cnt)
 	  (insert (format "\n%s%s"
-			  (idlwave-make-full-name (nth 2 routine) 
+			  (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) 
+				       (list (nth 0 routine)
+					     (nth 1 routine)
 					     (nth 2 routine)))
 				 props))
 	    (idlwave-insert-source-location "\n   - " twin props1))))
@@ -465,7 +471,7 @@ can be used to detect possible name clashes during this process."
 ;; Routine data structure tools
 
 (defun idlwave-routine-source-file (source)
-  (if (nth 2 source) 
+  (if (nth 2 source)
       (expand-file-name (nth 1 source) (nth 2 source))
     (nth 1 source)))
 
@@ -475,7 +481,7 @@ If yes, return the index (>=1)."
   (let (file (cnt 0))
     (catch 'exit
       (while entries
-	(incf cnt)
+	(cl-incf cnt)
 	(setq file (idlwave-routine-source-file (nth 3 (car entries))))
 	(if (and file (idlwave-syslib-p file))
 	    (throw 'exit cnt)
@@ -484,10 +490,10 @@ If yes, return the index (>=1)."
 
 (defun idlwave-all-method-classes (method &optional type)
   "Return all classes which have a method METHOD.
-TYPE is 'fun or 'pro.
+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))
+      (mapcar #'car (idlwave-class-alist))
     (let (rtn)
       (mapc (lambda (x)
 	      (and (nth 2 x)
@@ -499,7 +505,7 @@ When TYPE is not specified, both procedures and functions will be considered."
 
 (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.
+TYPE is `fun' or `pro'.
 When TYPE is not specified, both procedures and functions will be considered."
   (if (or (null method)
 	  (null keyword))
@@ -543,16 +549,19 @@ When TYPE is not specified, both procedures and functions will be considered."
 		      (dassoc (cdr dassoc))
 		      (t t)))
 	 arrow-len
-	 (arrow (and apos (or (and (string= (buffer-substring apos (min (point-max)
-									(+ 2 apos))) "->")
-				   (setq arrow-len 2))
-			      (and (string= (buffer-substring apos (min (point-max)
-									(+ 1 apos))) ".")
-				   (setq arrow-len 1)))))
-	 (is-self 
+	 (arrow (and apos
+		     (or (and (string= (buffer-substring apos (min (point-max)
+								   (+ 2 apos)))
+				       "->")
+			      (setq arrow-len 2))
+			 (and (string= (buffer-substring apos (min (point-max)
+								   (+ 1 apos)))
+				       ".")
+			      (setq arrow-len 1)))))
+	 (is-self
 	  (and arrow
 	       (save-excursion (goto-char apos)
-			       (forward-word -1)
+			       (forward-word-strictly -1)
 			       (let ((case-fold-search t))
 				 (looking-at "self\\>")))))
 	 (force-query idlwave-force-class-query)
@@ -570,20 +579,20 @@ When TYPE is not specified, both procedures and functions will be considered."
 	  (setq class (or (nth 2 (idlwave-current-routine)) class)))
 
       ;; Before prompting, try any special class determination routines
-      (when (and (eq t class) 
-		 idlwave-determine-class-special
+      (when (and (eq t class)
 		 (not force-query))
-	(setq special-class 
-	      (idlwave-call-special idlwave-determine-class-special apos))
-	(if special-class 
+	(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 cw-list) type)))
+	(setq class-alist
+	      (mapcar #'list (idlwave-all-method-classes (car cw-list) type)))
 	(setq class
 	      (idlwave-sintern-class
 	       (cond
@@ -591,9 +600,9 @@ When TYPE is not specified, both procedures and functions will be considered."
 		 (error "No classes available with method %s" (car cw-list)))
 		((and (= (length class-alist) 1) (not force-query))
 		 (car (car class-alist)))
-		(t 
+		(t
 		 (setq store idlwave-store-inquired-class)
-		 (idlwave-completing-read 
+		 (idlwave-completing-read
 		  (format "Class%s: " (if (stringp (car cw-list))
 					  (format " for %s method %s"
 						  type (car cw-list))
@@ -605,9 +614,9 @@ When TYPE is not specified, both procedures and functions will be considered."
 	;; We have a real class here
 	(when (and store arrow)
 	  (condition-case ()
-	      (add-text-properties 
-	       apos (+ apos arrow-len) 
-	       `(idlwave-class ,class face ,idlwave-class-arrow-face 
+	      (add-text-properties
+	       apos (+ apos arrow-len)
+	       `(idlwave-class ,class face ,idlwave-class-arrow-face
 			       rear-nonsticky t))
 	    (error nil)))
 	(setf (nth 2 cw-list) class))
@@ -619,19 +628,21 @@ When TYPE is not specified, both procedures and functions will be considered."
 ;;----------------------------------------------------
 ;; Context (buffer-local)
 
-(defvar idlwave-determine-class-special nil
-  "List of special functions for determining class.
-Must accept two arguments: `apos' and `info'.")
+(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-where ()
-  "Find out where we are. 
+  "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 
+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).
@@ -643,7 +654,7 @@ POINT:  Where is this
 CLASS:  What class has the routine (nil=no, t=is method, but class unknown)
 ARROW:  Location of the arrow for method calls"
   (idlwave-routines)
-  (let* (;(bos (save-excursion (idlwave-beginning-of-statement) (point))) 
+  (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))
@@ -673,43 +684,43 @@ ARROW:  Location of the arrow for method calls"
       nil)
 
      ;; Procedure call
-     ((string-match 
-       "\\`[ \t]*\\([a-zA-Z][a-zA-Z0-9$_]*\\)?\\'" 
+     ((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 
+      (setq cw 'procedure
+	    cw-class pro-class
 	    cw-point pro-point
 	    cw-arrow pro-arrow))
 
      ;; Complete class name inside obj_new statement
-     ((string-match "OBJ_NEW([ \t]*['\"]\\([a-zA-Z0-9$_]*\\)?\\'"
+     ((string-match "OBJ_NEW([ \t]*['\"][a-zA-Z0-9$_]*\\'"
 		    match-string)
       (setq cw 'class))
 
      ;; Or in an INHERITS statement
-     ((string-match "\\<inherits\\s-+\\([a-zA-Z0-9$_]*\\)?\\'"
+     ((string-match "\\<inherits\\s-+[a-zA-Z0-9$_]*\\'"
 		    match-string)
       (setq cw 'class))
 
      ;; Function keyword inside function
-     ((and func 
+     ((and func
 	   (> func-point pro-point)
 	   (= func-level 1)
 	   (memq last-char '(?\( ?,)))
-      (setq cw 'function-keyword 
-	    cw-mod func 
+      (setq cw 'function-keyword
+	    cw-mod func
 	    cw-point func-point
-	    cw-class func-class 
+	    cw-class func-class
 	    cw-arrow func-arrow))
 
      ;; Procedure keyword otherwise
      ((and pro (eq last-char ?,))
-      (setq cw 'procedure-keyword 
-	    cw-mod pro 
+      (setq cw 'procedure-keyword
+	    cw-mod pro
 	    cw-point pro-point
-	    cw-class pro-class 
+	    cw-class pro-class
 	    cw-arrow pro-arrow))
 
 ;     ((member last-char '(?\' ?\) ?\] ?!))
@@ -742,11 +753,11 @@ ARROW:  Location of the arrow for method calls"
   ;;    searches to this point.
 
   (catch 'exit
-    (let (pos 
+    (let (pos
 	  func-point
 	  (cnt 0)
 	  func arrow-start class)
-      (idlwave-with-special-syntax
+      (with-syntax-table idlwave-find-symbol-syntax-table
        (save-restriction
 	 (save-excursion
 	   (narrow-to-region (max 1 (or bound 0)) (point-max))
@@ -755,20 +766,20 @@ ARROW:  Location of the arrow for method calls"
 		      (progn (up-list -1) t)
 		    (error nil))
 	     (setq pos (point))
-	     (incf cnt)
+	     (cl-incf cnt)
 	     (when (and (= (following-char) ?\()
-			(re-search-backward 
+			(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 
+	       (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 
+	       (throw
+		'exit
 		(list
 		 (idlwave-sintern-routine-or-method func class)
 		 (idlwave-sintern-class class)
@@ -776,7 +787,7 @@ ARROW:  Location of the arrow for method calls"
 	     (goto-char pos))
 	   (throw 'exit nil)))))))
 
-(defun idlwave-what-procedure (&optional bound)
+(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)).
 
@@ -784,18 +795,18 @@ ARROW:  Location of the arrow for method calls"
   ;;    searches to this point.
   (let ((pos (point)) pro-point
 	pro class arrow-start string)
-    (save-excursion 
+    (save-excursion
       ;;(idlwave-beginning-of-statement)
       (idlwave-start-of-substatement 'pre)
       (setq string (buffer-substring (point) pos))
-      (if (string-match 
+      (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-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))
@@ -839,7 +850,7 @@ ARROW:  Location of the arrow for method calls"
 	      (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
@@ -877,7 +888,7 @@ This function is not general, can only be used for completion stuff."
 (defun idlwave-what-module ()
   "Return a default module for stuff near point.
 Used by `idlwave-routine-info' and `idlwave-find-module'.
-A module specification has the simple format (name 'type class)"
+A module specification has the simple format (NAME TYPE CLASS)"
   (idlwave-routines)
   (if (let ((case-fold-search t))
 	(save-excursion
@@ -903,18 +914,18 @@ A module specification has the simple format (name 'type class)"
       (cond
        ((and (eq cw 'procedure)
 	     (not (equal this-word "")))
-	(setq this-word (idlwave-sintern-routine-or-method 
+	(setq this-word (idlwave-sintern-routine-or-method
 			 this-word (nth 2 (nth 3 where))))
 	(list this-word 'pro
-	      (idlwave-determine-class 
+	      (idlwave-determine-class
 	       (cons this-word (cdr (nth 3 where)))
 	       'pro)))
 
-       ((and (eq cw 'function) 
+       ((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 
+	(setq this-word (idlwave-sintern-routine-or-method
 			 this-word (nth 2 (nth 3 where))))
 	(list this-word 'fun
 	      (idlwave-determine-class
@@ -932,7 +943,7 @@ A module specification has the simple format (name 'type class)"
 
        (pro
 	(list pro 'pro (idlwave-determine-class (nth 0 where) 'pro)))
-       
+
        (t nil)))))
 
 (defun idlwave-what-module-find-class ()
@@ -943,7 +954,7 @@ A module specification has the simple format (name 'type class)"
 	     (stringp class))
 	(list (car module)
 	      (nth 1 module)
-	      (apply 'idlwave-find-inherited-class module))
+	      (apply #'idlwave-find-inherited-class module))
       module)))
 
 (defun idlwave-find-inherited-class (name type class)
@@ -954,7 +965,7 @@ A module specification has the simple format (name 'type class)"
       class)))
 
 (defun idlwave-fix-module-if-obj_new (module)
-  "Check if MODULE points to obj_new.  
+  "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))
@@ -968,26 +979,26 @@ appropriate Init method."
 	       (setq string (buffer-substring (point) pos))
 	       (string-match "obj_new([^'\"]*['\"]\\([a-zA-Z0-9_]+\\)"
 			     string)))
-	(let ((name "Init")
+	(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 
+(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))
+  (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")
-	     (or (eq major-mode 'idlwave-mode)
-		 (eq major-mode 'idlwave-shell-mode)))
+	     (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)
@@ -996,34 +1007,35 @@ demand _EXTRA in the keyword list."
 			     string)
 	       (setq class (idlwave-sintern-class (match-string 1 string)))
 	       (setq idlwave-current-obj_new-class class)
-	       (setq keywords 
-		     (append keywords 
+	       (setq keywords
+		     (append keywords
 			     (idlwave-entry-keywords
 			      (idlwave-rinfo-assq
 			       (idlwave-sintern-method "INIT")
 			       'fun
 			       class
-			       (idlwave-routines)) 'do-link))))))
-    
+			       (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 
+	       (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 
-	   super-classes
+    (when (and
+	   idlwave--super-classes
 	   idlwave-keyword-class-inheritance
 	   (stringp class)
-	   (or 
+	   (or
 	    system
 	    (assq (idlwave-sintern-keyword "_extra") keywords)
 	    (assq (idlwave-sintern-keyword "_ref_extra") keywords))
@@ -1033,15 +1045,15 @@ demand _EXTRA in the keyword list."
 	       (while (setq re (pop regexps))
 		 (if (string-match re name) (throw 'exit t))))))
 
-      (loop for entry in (idlwave-routines) do
-	    (and (nth 2 entry)                           ; non-nil class
-		 (memq (nth 2 entry) 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))))
+      (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))
 
@@ -1066,14 +1078,14 @@ If we do not know about MODULE, just return KEYWORD literally."
 		    (assq (idlwave-sintern-keyword "_REF_EXTRA") kwd-alist)))
 	 (completion-ignore-case t)
 	 candidates)
-    (cond ((assq kwd kwd-alist) 
+    (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 
+	   ;; Inheritance may cause this keyword to be correct
 	   keyword)
 	  (entry
 	   ;; We do know the function, which does not have the keyword.
@@ -1087,31 +1099,31 @@ If we do not know about MODULE, just return KEYWORD literally."
   "Return the class alist - make it if necessary."
   (or idlwave-class-alist
       (let (class)
-	(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)))      
+	(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)))
 
 (defun idlwave-entry-keywords (entry &optional record-link)
-  "Return the flat entry keywords alist from routine-info entry.  
+  "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) 
+     (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 
+			 (put-text-property
 			  0 (length key)
-			  'link 
-			  (concat 
-			   file 
-			   (if link 
+			  'link
+			  (concat
+			   file
+			   (if link
 			       (concat idlwave-html-link-sep link)))
 			  key))
 		     (push (list key) kwds)))
@@ -1123,13 +1135,13 @@ property indicating the link is added."
   "Find keyword KEYWORD in entry ENTRY, and return (with link) if set."
   (catch 'exit
     (mapc
-     (lambda (key-list) 
+     (lambda (key-list)
        (let ((file (car key-list))
 	     (kwd (assoc keyword (cdr key-list))))
 	 (when kwd
-	   (setq kwd (cons (car kwd) 
+	   (setq kwd (cons (car kwd)
 			   (if (and file (cdr kwd))
-			       (concat file 
+			       (concat file
 				       idlwave-html-link-sep
 				       (cdr kwd))
 			     (cdr kwd))))
@@ -1148,7 +1160,7 @@ property indicating the link is added."
   (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-rinfo-assq name type class
 					idlwave-unresolved-routines)))
 	 (name (or (car entry) name))
 	 (class (or (nth 2 entry) class))
@@ -1170,10 +1182,9 @@ property indicating the link is added."
 	  "Button2: Display info about same method in superclass")
 	 (col 0)
 	 (data (list name type class (current-buffer) nil initial-class))
-	 (km-prop (if (featurep 'xemacs) 'keymap 'local-map))
 	 (face 'idlwave-help-link)
 	 beg props win cnt total)
-    ;; Fix keywords, but don't add chained super-classes, since these 
+    ;; 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
@@ -1195,7 +1206,7 @@ property indicating the link is added."
 				  idlwave-current-obj_new-class)
 	(when superclasses
 	  (setq props (list 'mouse-face 'highlight
-			    km-prop idlwave-rinfo-mouse-map
+			    'local-map idlwave-rinfo-mouse-map
 			    'help-echo help-echo-class
 			    'data (cons 'class data)))
 	  (let ((classes (cons initial-class superclasses)) c)
@@ -1211,10 +1222,10 @@ property indicating the link is added."
 		    (add-text-properties beg (point) props))))
 	    (insert "\n")))
 	(setq props (list 'mouse-face 'highlight
-			  km-prop idlwave-rinfo-mouse-map
+			  '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) 
+	(if html-file (setq props (append (list 'face face 'link html-file)
 					  props)))
 	(insert "Usage:    ")
 	(setq beg (point))
@@ -1223,14 +1234,14 @@ property indicating the link is added."
 		  (format calling-seq name name name 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))) 
+	     (if (>= (+ col 1 (length (car x)))
 		     (window-width))
 		 (progn
 		   (insert "\n         ")
@@ -1239,7 +1250,7 @@ property indicating the link is added."
 	     (setq beg (point)
 		   ;; Relevant keywords already have link property attached
 		   props (list 'mouse-face 'highlight
-			       km-prop idlwave-rinfo-mouse-map
+			       'local-map idlwave-rinfo-mouse-map
 			       'data (cons 'keyword data)
 			       'help-echo help-echo-kwd
 			       'keyword (car x)))
@@ -1248,12 +1259,12 @@ property indicating the link is added."
 	     (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
-			    km-prop idlwave-rinfo-mouse-map
+			    'local-map idlwave-rinfo-mouse-map
 			    'help-echo help-echo-src
 			    'source (list (car (car (nth 2 entry))) ;type
 					  (nth 1 entry)
@@ -1261,16 +1272,16 @@ property indicating the link is added."
 					  (cdr (car (nth 2 entry))))
 			    'data (cons 'source data)))
 	  (idlwave-insert-source-location
-	   (format "\n%-8s  %s" 
+	   (format "\n%-8s  %s"
 		   (if (equal cnt 1)
 		       (if (> total 1) "Sources:" "Source:")
 		     "")
 		   (if (> total 1) "- " ""))
 	   entry props)
-	  (incf cnt)
+	  (cl-incf cnt)
 	  (when (and all (> cnt idlwave-rinfo-max-source-lines))
 	    ;; No more source lines, please
-	    (insert (format 
+	    (insert (format
 		     "\n          Source information truncated to %d entries."
 		     idlwave-rinfo-max-source-lines))
 	    (setq all nil)))
@@ -1284,7 +1295,7 @@ property indicating the link is added."
 	      (unwind-protect
 		  (progn
 		    (select-window win)
-		    (enlarge-window (- (/ (frame-height) 2) 
+		    (enlarge-window (- (/ (frame-height) 2)
 				       (window-height)))
 		    (shrink-window-if-larger-than-buffer))
 		(select-window ww)))))))))
@@ -1321,9 +1332,9 @@ to it."
      ((and (not file) shell-flag)
       (insert "Unresolved"))
 
-     ((null file)               
+     ((null file)
       (insert "ERROR"))
-     
+
      ((idlwave-syslib-p file)
       (if (string-match "obsolete" (file-name-directory file))
 	  (insert "Obsolete  ")
@@ -1337,7 +1348,7 @@ to it."
      ;; 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   "))
 
@@ -1352,14 +1363,13 @@ to it."
 	       (if shell-flag "S" "-")
 	       (if buffer-flag "B" "-")
 	       "] ")))
-    (when (> ndupl 1) 
+    (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
-		     (if (featurep 'xemacs) (list file t) (list file))))
+      (insert (apply 'abbreviate-file-name (list file)))
       (if file-props
 	  (add-text-properties beg (point) file-props)))))
 
@@ -1379,7 +1389,7 @@ Return the name of the special lib if there is a match."
 
 
 ;;----------------------------------------------------
-;; Routine Info callbacks  
+;; Routine Info callbacks
 
 (defun idlwave-mouse-active-rinfo-right (ev)
   (interactive "e")
@@ -1399,7 +1409,7 @@ 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 
+  (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)
@@ -1414,9 +1424,9 @@ was pressed."
 
     (cond ((eq id 'class) ; Switch class being displayed
 	   (if (window-live-p bufwin) (select-window bufwin))
-	   (idlwave-display-calling-sequence 
+	   (idlwave-display-calling-sequence
 	    (idlwave-sintern-method name)
-	    type (idlwave-sintern-class word) 
+	    type (idlwave-sintern-class word)
 	    initial-class))
 	  ((eq id 'usage) ; Online help on this routine
 	   (idlwave-online-help link name type class))
@@ -1457,9 +1467,9 @@ was pressed."
       (setq bwin (get-buffer-window buffer)))
     (if (eq (preceding-char) ?/)
 	(insert keyword)
-      (unless (save-excursion 
+      (unless (save-excursion
 		(re-search-backward
-		 "[(,][ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\)?[ \t]*\\=" 
+		 "[(,][ \t]*\\(\\$[ \t]*\\(;.*\\)?\n\\)?[ \t]*\\="
 		 (min (- (point) 100) (point-min)) t))
 	(insert ", "))
       (if shift (insert "/"))
@@ -1479,7 +1489,7 @@ was pressed."
 	     (or (not (stringp sfile))
 		 (not (string-match "\\S-" sfile))))
 	(setq stype 'unresolved))
-    (princ (format "      %-10s %s\n" 
+    (princ (format "      %-10s %s\n"
 		   stype
 		   (if sfile sfile "No source code available")))))
 
diff --git a/idlw-scan.el b/idlw-scan.el
index 91b93e94dd..9abc83b4f5 100644
--- a/idlw-scan.el
+++ b/idlw-scan.el
@@ -1,14 +1,15 @@
-;; IDLWAVE: scan routine information provided with IDL, and among the
+;; IDLWAVE: scan routine information provided with IDL, and among the  -*- lexical-binding: t; -*-
 ;; user's library, as well as in open buffers (for scanning the shell,
 ;; see idlw-shell.el)
 
 (require 'timer)
+(require 'idlw-variables)
 
 ;; idlwave-routines format (whether system, library, or userlib)
 ;; ("ROUTINE" type class
 ;;  (system) | (lib pro_file dir "LIBNAME") | (user pro_file dir "USERLIB") |
 ;;  (buffer pro_file dir) | (compiled pro_file dir)
-;;   "calling_string" ("LINKFILE" (("KWD1" . anchorlink1) ...)) 
+;;   "calling_string" ("LINKFILE" (("KWD1" . anchorlink1) ...))
 ;;                    ("LINKFILE2" (("KWD2" . ancorlink2) ...)) ...)
 
 ;;----------------------------------------------------
@@ -30,7 +31,7 @@
   "Holds the routine-info from the .idlwave_catalog library files.")
 (defvar idlwave-class-alist nil
   "Holds the class names and brief info known to IDLWAVE.")
-(defvar idlwave-class-info nil) 
+(defvar idlwave-class-info nil)
 
 (defvar idlwave-library-catalog-libname nil
   "Name of library catalog loaded from .idlwave_catalog files.")
@@ -105,7 +106,7 @@ Later it only returns the value of the variable."
 	    (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)
@@ -130,7 +131,7 @@ Later it only returns the value of the variable."
 		  (progn
 		    (setq idlwave-library-routines nil)
 		    (ding)
-		    (message "Outdated user catalog: %s... recreate" 
+		    (message "Outdated user catalog: %s... recreate"
 			     idlwave-user-catalog-file))
 		(message "Loading user catalog in idle time...done")))
 	    (aset arr 2 t)
@@ -139,16 +140,16 @@ Later it only returns the value of the variable."
 	  (when (not (aref arr 3))
 	    (when idlwave-user-catalog-routines
 	      (message "Normalizing user catalog routines in idle time...")
-	      (setq idlwave-user-catalog-routines 
+	      (setq idlwave-user-catalog-routines
 		    (idlwave-sintern-rinfo-list
 		     idlwave-user-catalog-routines 'sys))
-	      (message 
+	      (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 
+	    (idlwave-scan-library-catalogs
 	     "Loading and normalizing library catalogs in idle time...")
 	    (aset arr 4 t)
 	    (throw 'exit t))
@@ -156,7 +157,7 @@ Later it only returns the value of the variable."
 	    (message "Finishing initialization in idle time...")
 	    (idlwave-routines)
 	    (message "Finishing initialization in idle time...done")
-	    (aset arr 5 t)	    
+	    (aset arr 5 t)
 	    (throw 'exit nil)))
 	;; restart the timer
 	(if (sit-for 1)
@@ -164,7 +165,7 @@ Later it only returns the value of the variable."
 	  (setq idlwave-load-rinfo-idle-timer
 		(run-with-idle-timer
 		 idlwave-init-rinfo-when-idle-after
-		 nil 'idlwave-load-rinfo-next-step))))))
+		 nil #'idlwave-load-rinfo-next-step))))))
 
 (defun idlwave-load-all-rinfo (&optional force)
   ;; Load and case-treat the system, user catalog, and library routine
@@ -190,17 +191,17 @@ Later it only returns the value of the variable."
 	(when (or force (not (aref idlwave-load-rinfo-steps-done 2)))
 	  (load-file idlwave-user-catalog-file))
       (error nil))
-    (when (and 
+    (when (and
 	   (boundp 'idlwave-library-routines)
 	   idlwave-library-routines)
       (setq idlwave-library-routines nil)
-      (error "Outdated user catalog: %s... recreate" 
+      (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 
+      (setq idlwave-user-catalog-routines
+	    (idlwave-sintern-rinfo-list
 	     idlwave-user-catalog-routines 'sys))
       (message "Normalizing user catalog routines...done")))
 
@@ -242,10 +243,7 @@ automatically when called interactively.  When you need routine
 information updated immediately, leave NO-CONCATENATE nil."
   (interactive "P\np")
   ;; Stop any idle processing
-  (if (or (and (fboundp 'itimerp)
-	       (itimerp idlwave-load-rinfo-idle-timer))
-	  (and (fboundp 'timerp)
-	       (timerp idlwave-load-rinfo-idle-timer)))
+  (if (timerp idlwave-load-rinfo-idle-timer)
       (cancel-timer idlwave-load-rinfo-idle-timer))
   (cond
    ((equal arg '(64))
@@ -261,7 +259,7 @@ information updated immediately, leave NO-CONCATENATE nil."
 	   ;; 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)
@@ -272,7 +270,7 @@ information updated immediately, leave NO-CONCATENATE 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
@@ -287,14 +285,14 @@ information updated immediately, leave NO-CONCATENATE nil."
 				    (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 
+	(when arg
 	  (if shell-is-running
 	      (idlwave-shell-send-command idlwave-shell-path-query
-					  '(progn
-					     (idlwave-shell-get-path-info)
-					     (idlwave-scan-library-catalogs))
+					  (lambda ()
+					    (idlwave-shell-get-path-info)
+					    (idlwave-scan-library-catalogs))
 					  'hide)
 	    (idlwave-scan-library-catalogs)))
 
@@ -309,7 +307,7 @@ information updated immediately, leave NO-CONCATENATE nil."
 	    ;;    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")
@@ -317,10 +315,11 @@ information updated immediately, leave NO-CONCATENATE nil."
 
 (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 
+  ;; 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.
   (if (consp idlwave-last-system-routine-info-cons-cell)
+      ;; FIXME: Where is this var actually used?
       (setcdr idlwave-last-system-routine-info-cons-cell
 	      (append idlwave-buffer-routines
 		      idlwave-compiled-routines
@@ -330,7 +329,7 @@ information updated immediately, leave NO-CONCATENATE nil."
 
   ;; Give a message with information about the number of routines we have.
   (unless quiet
-    (message 
+    (message
      "Routines Found: buffer(%d) compiled(%d) library(%d) user(%d) system(%d)"
      (length idlwave-buffer-routines)
      (length idlwave-compiled-routines)
@@ -349,9 +348,8 @@ information updated immediately, leave NO-CONCATENATE nil."
 Does not run after automatic updates of buffer or the shell.")
 (defvar idlwave-class-reset nil) ; to reset buffer-local classes
 
-(add-hook 'idlwave-load-hook
-	  (lambda ()
-	    (or idlwave-routines (idlwave-start-load-rinfo-timer))))
+(with-eval-after-load 'idlwave
+  (or idlwave-routines (idlwave-start-load-rinfo-timer)))
 (add-hook 'idlwave-update-rinfo-hook
 	  (lambda () (setq idlwave-class-reset t)))
 (add-hook 'idlwave-after-load-rinfo-hook
@@ -360,10 +358,7 @@ Does not run after automatic updates of buffer or the shell.")
 (defvar idlwave-load-rinfo-steps-done (make-vector 6 nil))
 (defvar idlwave-load-rinfo-idle-timer nil)
 (defun idlwave-start-load-rinfo-timer ()
-  (if (or (and (fboundp 'itimerp)
-	       (itimerp idlwave-load-rinfo-idle-timer))
-	  (and (fboundp 'timerp)
-	       (timerp idlwave-load-rinfo-idle-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)
@@ -376,7 +371,7 @@ Does not run after automatic updates of buffer or the shell.")
 	    (setq idlwave-load-rinfo-idle-timer
 		  (run-with-idle-timer
 		   idlwave-init-rinfo-when-idle-after
-		   nil 'idlwave-load-rinfo-next-step)))
+		   nil #'idlwave-load-rinfo-next-step)))
 	(error nil))))
 
 (defvar idlwave-library-routines nil "Older library routine info.")
@@ -386,7 +381,7 @@ Does not run after automatic updates of buffer or the shell.")
 
 (defun idlwave-xml-system-routine-info-file()
   "Return the file for the XML catalog file bundled with IDL."
-  (let* ((dir (file-name-as-directory 
+  (let* ((dir (file-name-as-directory
 	       (expand-file-name "help/" (idlwave-sys-dir)))))
     (if (and (not (file-exists-p (expand-file-name "idl_catalog.xml" dir)))
 	     (file-directory-p (expand-file-name "online_help" dir)))
@@ -399,25 +394,25 @@ Cache to disk for quick recovery."
   (interactive)
   (let* ((catalog-file (idlwave-xml-system-routine-info-file))
 	 (elem-cnt 0)
-	 props rinfo msg-cnt elem type nelem class-result alias 
+	 props rinfo msg-cnt elem type nelem class-result alias
 	 routines routine-aliases graphics-keywords
 	 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...")   
+    (message "Reading XML routine info...")
     (require 'xml)
-    (setq rinfo 
+    (setq rinfo
 	  (let ((xml-validating-parser t))
 	    (condition-case nil
 		(xml-parse-file catalog-file)
 	      (error ;; Deal with XML.el bug
 	       (setq xml-validating-parser nil)
-	       (with-temp-buffer 
+	       (with-temp-buffer
 		 (insert-file-contents catalog-file)
-		 (while 
-		     (re-search-forward 
+		 (while
+		     (re-search-forward
 		      "^\\s-*<!\\(ATTLIST\\|ELEMENT\\) * [A-Z]+_[A-Z]+.*>\\s-*[\r\n]"
 		      nil t)
 		   (replace-match ""))
@@ -426,13 +421,14 @@ Cache to disk for quick recovery."
     (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)
+    ;; FIXME: Use `make-progress-reporter'
     (message "Converting XML routine info...")
     (setq idlwave-system-routines nil
 	  idlwave-system-variables-alist nil
@@ -448,13 +444,13 @@ Cache to disk for quick recovery."
 	(setq type (car elem)
 	      props (car (cdr elem)))
 	(if (= (mod elem-cnt msg-cnt) 0)
-	    (message "Converting XML routine info...%2d%%" 
-		     (/ (* elem-cnt 100) nelem)))
-	(cond 
+	    (message "Converting XML routine info...%2d%%"
+		     (floor (* elem-cnt 100.0) nelem)))
+	(cond
 	 ((eq type 'ROUTINE)
 	  (if (and (setq alias (cdr (assq 'alias_to props)))
 		   (not (string= "" alias)))
-	      (push (cons (cdr (assq 'name props)) alias) 
+	      (push (cons (cdr (assq 'name props)) alias)
 		    routine-aliases)
 	    (setq routines (idlwave-xml-create-rinfo-list elem))
 	    (if (listp (cdr routines))
@@ -462,7 +458,7 @@ Cache to disk for quick recovery."
 		      (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)
@@ -482,10 +478,10 @@ Cache to disk for quick recovery."
 	 ((eq type 'SYSVAR)
 	  (if (and (setq alias (cdr (assq 'alias_to props)))
 		   (not (string= "" alias)))
-	      (push (cons (substring (cdr (assq 'name props)) 1) 
+	      (push (cons (substring (cdr (assq 'name props)) 1)
 			  (substring alias 1))
 		    sysvar-aliases)
-	    (push (idlwave-xml-create-sysvar-alist elem) 
+	    (push (idlwave-xml-create-sysvar-alist elem)
 		  idlwave-system-variables-alist)))
 	 (t))))
     (idlwave-convert-xml-add-link-path-information)
@@ -500,16 +496,16 @@ Cache to disk for quick recovery."
 (defun idlwave-save-xml-routine-info ()
   (if idlwave-xml-routine-info-file
       (with-temp-file idlwave-xml-system-rinfo-converted-file
-	(insert 
+	(insert
 	 (concat ";; *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
-;; IDLWAVE Routine Information File (IDLWAVE version " idlwave-mode-version ") 
-;; Automatically generated from source file: 
+;; IDLWAVE Routine Information File (IDLWAVE version " idlwave-mode-version ")
+;; Automatically generated from source file:
 ;;  " idlwave-xml-routine-info-file "
 ;; on " (current-time-string) "
 ;; " (format "%d routines, %d classes, %d sysvars, %d exec commands"
-	     (length idlwave-system-routines) 
-	     (length idlwave-system-class-info) 
-	     (length idlwave-system-variables-alist) 
+	     (length idlwave-system-routines)
+	     (length idlwave-system-class-info)
+	     (length idlwave-system-variables-alist)
 	     (length idlwave-executive-commands-alist)) "
 ;; Do not edit."))
 	(insert (format "\n(setq idlwave-xml-routine-info-file \n    \"%s\")"
@@ -555,11 +551,11 @@ Cache to disk for quick recovery."
 (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 
+    (mapconcat
      (lambda (x)
        (while (string-match name x)
 	 (setq x (replace-match "%s" t t x)))
-       (if class 
+       (if class
 	   (while (string-match class x)
 	     (setq x (replace-match "%s" t t x))))
        x)
@@ -620,8 +616,8 @@ Cache to disk for quick recovery."
 		  (put 'set-props 'matched t)
 		  set-props)
 		 (t nil)))
-	  (setq methods-entry 
-		(nconc (idlwave-xml-create-rinfo-list pelem class extra-kwds) 
+	  (setq methods-entry
+		(nconc (idlwave-xml-create-rinfo-list pelem class extra-kwds)
 		       methods-entry)))
 	 (t)))
       (setq params (cdr params)))
@@ -631,8 +627,8 @@ Cache to disk for quick recovery."
     ;;  (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 
+    (setq class-entry
+	  (if inherits
 	      (list class (append '(inherits) inherits) (list 'link link))
 	    (list class (list 'link link))))
     (cons class-entry methods-entry)))
@@ -670,8 +666,8 @@ Cache to disk for quick recovery."
 		(while
 		    (string-match "\\[, /?\\({X *| *Y *| *Z}\\)?\\([A-Z0-9]+\\)[]=]" syntax pos)
 		  (if (match-string 1 syntax)
-		      (loop for x in '("X" "Y" "Z") do
-			    (push (concat x (match-string 2 syntax)) graphics-kws))
+		      (cl-loop for x in '("X" "Y" "Z") do
+			       (push (concat x (match-string 2 syntax)) graphics-kws))
 		    (push (match-string 2 syntax) graphics-kws))
 		  (setq pos (match-end 0)))
 		(message "Parsing Graphics Keywords for %s: %d found" name (length graphics-kws)))
@@ -681,7 +677,8 @@ Cache to disk for quick recovery."
 		  (aref syntax-vec (cond
 				    ((or
 				      (string-match "^exec" type)
-				      (string= (substring name 0 1) ".")) 2)
+				      (string= (substring name 0 1) "."))
+				     2)
 				    ((string-match "^pro" type) 0)
 				    ((string-match "^fun" type) 1)
 				    (t 0))))))
@@ -689,23 +686,23 @@ Cache to disk for quick recovery."
 	 ((eq ptype 'KEYWORD)
 	  (setq kwd (cdr (assq 'name props))
 		klink (cdr (assq 'link props)))
-	  (if (and link-dir klink 
+	  (if (and link-dir klink
 		   (not (string= (file-name-directory klink) link-dir)))
 	      (setq klink (concat link-dir klink)))
 	  (if (string-match "\\s-*(.*?Only)" kwd)
 	      (setq kwd (replace-match "" t t kwd)))
 	  (if (string-match "^\\[XY\\(Z?\\)\\]" kwd)
-	      (progn 
-		(setq pref-list 
+	      (progn
+		(setq pref-list
 		      (if (match-string 1 kwd) '("X" "Y" "Z") '("X" "Y"))
 		      kwd (substring kwd (match-end 0)))
-		(loop for x in pref-list do
-		      (push (list (concat x kwd) klink) kwds)))
+		(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))
@@ -722,13 +719,14 @@ Cache to disk for quick recovery."
       (if graphics-kws
 	  (setq kwds (nconc kwds (idlwave-graphics-keywords graphics-kws))))
       (setq kwds (idlwave-rinfo-group-keywords kwds link))
-      (loop for idx from 0 to 1 do	;add a procedure and function if needed
-	    (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)))
+      (cl-loop for idx from 0 to 1 do ;add a procedure and function if needed
+	       (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)))
 
 (defvar idlwave-graphics-keywords-links-alist nil)
@@ -755,10 +753,10 @@ Cache to disk for quick recovery."
 			  (setq kwd (substring kwd (match-end 0)))
 			  (setq kwds (mapcar (lambda (x) (concat x kwd)) '("X" "Y" "Z"))))
 		      (setq kwds (list kwd)))
-		    (loop for kwd in kwds do
-			  (unless (assoc kwd idlwave-graphics-keywords-links-alist)
-			    (push (cons kwd (concat gkwfile anchor))
-				  idlwave-graphics-keywords-links-alist)))))))))))
+		    (cl-loop for kwd in kwds do
+			     (unless (assoc kwd idlwave-graphics-keywords-links-alist)
+			       (push (cons kwd (concat gkwfile anchor))
+				     idlwave-graphics-keywords-links-alist)))))))))))
   ;; find the keywords and links
   (mapcar
    (lambda (kwd)
@@ -792,11 +790,11 @@ Cache to disk for quick recovery."
   ;; Clean up the syntax of routines which are actually aliases by
   ;; removing the "OR" from the statements
   (let (syntax entry)
-    (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)))))))
+    (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-alias-path (file alias-list content-path &optional class-dir)
   "Search for the HTML help file FILE in the help content.
@@ -814,59 +812,59 @@ force directory search."
 	(cond
 	 ;; Directly on the alias list
 	 ((and
-	   (setq alias (assoc-ignore-case file alias-list))
-	   (file-exists-p (setq linkfile 
+	   (setq alias (assoc-string file alias-list 'ignore-case))
+	   (file-exists-p (setq linkfile
 				(expand-file-name (cdr alias) content-path)))))
-	 
+
 	 ;; Sitting on content path already
 	 ((file-exists-p (setq linkfile (expand-file-name file content-path))))
-	 
+
 	 ;; Leading ../'s
-	 ((and (string-match "^\\(\.\./\\)+" file)
-	       (file-exists-p 
-		(setq linkfile 
-		      (expand-file-name 
-		       (replace-match "" t t file) 
+	 ((and (string-match "^\\(\\.\\./\\)+" file)
+	       (file-exists-p
+		(setq linkfile
+		      (expand-file-name
+		       (replace-match "" t t file)
 		       content-path)))))
 	  ;(message "Found extra ../: %s" file))
 
 	 ;; With the optional class directory passed in
 	 ((and class-dir
-	       (file-exists-p 
+	       (file-exists-p
 		(setq linkfile
 		      (expand-file-name (concat class-dir file)
 					content-path)))))
 	  ;(message "Found via class: %s" file))
 
 	 ;; Under Alphabetized Reference Directory
-	 ((file-exists-p 
-	   (setq linkfile 
-		 (expand-file-name 	   
-		  (concat "Reference Material" 
+	 ((file-exists-p
+	   (setq linkfile
+		 (expand-file-name
+		  (concat "Reference Material"
 			  "/" (upcase (substring file 0 1)) "/" file)
 		  content-path))))
 	  ;(message "Found alphabetically under Reference Material: %s" file))
-	 
+
 	 ;; Dir from root name alias (e.g. CLASS_METHOD.html -> CLASS.html)
 	 ((let ((lfroot
-		 (replace-regexp-in-string 
-		  "_+[^_]*\.htm\\(l?\\)" ".htm\\1" file)))
+		 (replace-regexp-in-string
+		  "_+[^_]*\\.htm\\(l?\\)" ".htm\\1" file)))
 	    (and (not (string= file lfroot))
-		 (setq alias (assoc-ignore-case lfroot alias-list))
-		 (file-exists-p 
-		  (setq linkfile 
-			(expand-file-name 	   
+		 (setq alias (assoc-string lfroot alias-list 'ignore-case))
+		 (file-exists-p
+		  (setq linkfile
+			(expand-file-name
 			 (concat (file-name-directory (cdr alias)) file)
 			 content-path))))))
 	  ;(message "Found using root name: %s" file))
 
 	 ;; Didn't find it... try a brute-force directory search
-	 (t 
+	 (t
 	  (message "searching for %s" file)
-	  (if (setq linkfile 
-		    (idlwave-recursive-find-file 
-		     content-path 
-		     (replace-regexp-in-string "\.html$" ".htm" file)))
+	  (if (setq linkfile
+		    (idlwave-recursive-find-file
+		     content-path
+		     (replace-regexp-in-string "\\.html\\'" ".htm" file)))
 	      (progn
 		(setq linkfile (file-relative-name linkfile content-path))
 		;; Save it as an alias in case it is requested again
@@ -894,29 +892,30 @@ force directory search."
 	      (let* ((link (car (idlwave-split-link-target
 				 (cdr (assoc 'Link elem)))))
 		     (file (file-name-nondirectory link)))
-		(add-to-list 'alias-list (cons file link)))))
+		(cl-pushnew (cons file link) alias-list :test #'equal))))
 
 	  ;; System class info
-	  (mapc 
+	  (mapc
 	   (lambda (x)
-	     (when (setq linkfile 
-			 (idlwave-alias-path 
-			  (nth 1 (assq 'link x)) alias-list content-path))
-	       (setcar (cdr (assq 'link x)) linkfile)))
+	     (let ((linkfile
+		    (idlwave-alias-path
+		     (nth 1 (assq 'link x)) alias-list content-path)))
+	       (when linkfile
+	         (setcar (cdr (assq 'link x)) linkfile))))
 	   idlwave-system-class-info)
-    
+
 	  ;; Main routines
 	  (mapc
 	   (lambda (x)
 	     (let ((class (nth 2 x))
-		   (kwd_blocks (nthcdr 5 x)) 
+		   (kwd_blocks (nthcdr 5 x))
 		   link linkfile class-entry)
 	       (while kwd_blocks
 		 (setq link (car kwd_blocks)
 		       kwd_blocks (cdr kwd_blocks))
 		 (when (and
 			(car link)
-			(string-match "\.htm\[^.\]*$" (car link))
+			(string-match "\\.htm[^.]*\\'" (car link))
 			(setq linkfile
 			     (idlwave-alias-path
 			      (car link) alias-list content-path
@@ -924,16 +923,16 @@ force directory search."
 				       (setq class-entry
 					     (assoc class
 						    idlwave-system-class-info)))
-				  (file-name-directory 
+				  (file-name-directory
 				   (nth 1 (assq 'link class-entry)))))))
 		   (setcar link linkfile)))))
 	   idlwave-system-routines)
-	  
+
 	  ;; Executive commands/special topics
-	  (mapc 
+	  (mapc
 	   (lambda (x)
-	     (let ((alias (assoc-ignore-case (cdr x) alias-list)))
-	       (if alias 
+	     (let ((alias (assoc-string (cdr x) alias-list 'ignore-case)))
+	       (if alias
 		   (setcdr x (cdr alias)))))
 	   (append idlwave-help-special-topic-words
 		   idlwave-executive-commands-alist))
@@ -941,7 +940,7 @@ force directory search."
 	  ;; System variables
 	  (mapc
 	   (lambda (x)
-	     (let* (linkfile 
+	     (let* (linkfile
 		    linkparts
 		    (linkcell (assq 'link x))
 		    (link (cadr linkcell)))
@@ -949,49 +948,50 @@ force directory search."
 		   (setq link (car linkparts)))
 	       (if (setq linkfile
 			 (idlwave-alias-path link alias-list content-path))
-		   (setcdr linkcell (idlwave-substitute-link-target 
+		   (setcdr linkcell (idlwave-substitute-link-target
 				     linkfile (cdr linkparts))))))
 	   idlwave-system-variables-alist)))
     (message "Linking help file info...done")))
 
 (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 
+  ;; This if for, e.g. OPENR/OPENW/OPENU
   (let (alias remove-list new parts all-parts)
-    (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)))))
-    
+    (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)
-    (loop for x in all-parts do
-	  (if (cdr x)
-	      (push (cons (nth 1 x) (car x)) aliases)))
-
-    (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)))
-    (loop for x in remove-list do
-	  (delq x idlwave-system-routines))))
+    (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)
-    (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)))
-    (loop for x in remove-list do
-	  (delq x idlwave-system-variables-alist))))
+    (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.
@@ -1010,7 +1010,7 @@ force directory search."
 	      props (car (cdr pelem)))
 	(cond
 	 ((eq ptype 'FIELD)
-	  (push (cons (cdr (assq 'name props)) 
+	  (push (cons (cdr (assq 'name props))
 		      (cdr
 		       (idlwave-split-link-target (cdr (assq 'link props)))))
 		tags))))
@@ -1025,12 +1025,12 @@ force directory search."
 (defvar idlwave-scanning-lib-dir)
 (defvar idlwave-scanning-lib)
 (defun idlwave-get-routine-info-from-buffers (buffers)
-  "Call `idlwave-get-buffer-routine-info' on idlwave-mode buffers in 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 (eq major-mode 'idlwave-mode)
+	(if (and (derived-mode-p 'idlwave-mode)
 		 buffer-file-name)
 	    ;; yes, this buffer has the right mode.
 	    (progn (setq res (condition-case nil
@@ -1038,7 +1038,7 @@ force directory search."
 			       (error nil)))
 		   (push res routine-lists)))))
     ;; Concatenate the individual lists and return the result
-    (apply 'nconc routine-lists)))
+    (apply #'nconc routine-lists)))
 
 (defun idlwave-get-buffer-routine-info ()
   "Scan the current buffer for routine info.  Return (PRO-LIST FUNC-LIST)."
@@ -1048,11 +1048,11 @@ force directory search."
       (save-restriction
 	(widen)
 	(goto-char (point-min))
-	(while (re-search-forward 
+	(while (re-search-forward
 		"^[ \t]*\\(pro\\|function\\)[ \t]" nil t)
 	  (setq string (buffer-substring-no-properties
 			(match-beginning 0)
-			(progn 
+			(progn
 			  (idlwave-end-of-statement)
 			  (point))))
 	  (setq entry (idlwave-parse-definition string))
@@ -1089,7 +1089,7 @@ force directory search."
 	(push (match-string 1 string) args)))
     ;; Normalize and sort.
     (setq args (nreverse args))
-    (setq keywords (sort keywords (lambda (a b) 
+    (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
@@ -1099,47 +1099,45 @@ force directory search."
 	  class
 	  (cond ((not (boundp 'idlwave-scanning-lib))
 		 (list  'buffer (buffer-file-name)))
-					;		((string= (downcase 
-					;			   (file-name-sans-extension
-					;			    (file-name-nondirectory (buffer-file-name))))
-					;			  (downcase name))
-					;		 (list 'lib))
-					;		(t (cons 'lib (file-name-nondirectory (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 
+	  (concat
 	   (if (string= type "function") "Result = " "")
 	   (if class "Obj ->[%s::]" "")
 	   "%s"
 	   (if args
 	       (concat
 		(if (string= type "function") "(" ", ")
-		(mapconcat 'identity args ", ")
+		(mapconcat #'identity args ", ")
 		(if (string= type "function") ")" ""))))
 	  (if keywords
-	      (cons nil (mapcar 'list keywords)) ;No help file
+	      (cons nil (mapcar #'list keywords)) ;No help file
 	    nil))))
 
 (defun idlwave-update-buffer-routine-info ()
   (let (res)
-    (cond 
+    (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 
+      (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 (eq major-mode 'idlwave-mode)
+      (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 
+    (setq idlwave-buffer-routines
 	  (idlwave-sintern-rinfo-list res 'set))))
 
 ;; Three functions for the file load/save/kill hooks
@@ -1153,7 +1151,7 @@ force directory search."
 (defun idlwave-update-current-buffer-info (why)
   "Update `idlwave-routines' for current buffer.
 Can run from `after-save-hook'."
-  (when (and (eq major-mode 'idlwave-mode)
+  (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
@@ -1167,14 +1165,15 @@ Can run from `after-save-hook'."
 	     (setq routines
 		   (idlwave-sintern-rinfo-list
 		    (idlwave-get-routine-info-from-buffers
-		     (list (current-buffer))) 'set))))
+		     (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) 
+  (let ((list idlwave-buffer-routines)
 	found)
     (while list
       ;; The following test uses eq to make sure it works correctly
@@ -1185,14 +1184,14 @@ Can run from `after-save-hook'."
 	    (setcar list nil)
 	    (setq found t))
 	(if found
-	    ;; End of that section reached. Jump. 
+	    ;; End of that section reached. Jump.
 	    (setq list nil)))
       (setq list (cdr list)))
     (setq idlwave-buffer-routines
 	  (append new (delq nil idlwave-buffer-routines)))))
 
 ;;----------------------------------------------------
-;; User Catalog 
+;; User Catalog
 
 (defun idlwave-create-user-catalog-file (&optional arg)
   "Scan all files on selected dirs of IDL search path for routine information.
@@ -1214,10 +1213,10 @@ as last time - so no widget will pop up."
 	       (> (length idlwave-user-catalog-file) 0)
 	       (file-accessible-directory-p
 		(file-name-directory idlwave-user-catalog-file))
-	       (not (string= "" (file-name-nondirectory 
+	       (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
@@ -1227,23 +1226,23 @@ as last time - so no widget will pop up."
    ;; Expand the directories from library-path and run the widget
    (idlwave-library-path
     (idlwave-display-user-catalog-widget
-     (if idlwave-true-path-alist 
+     (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)) 
+			 (cons x (cdr path-entry))
 		       (list x))))
 		 (idlwave-expand-path idlwave-library-path))
-       (mapcar 'list (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)
+				(lambda () (idlwave-user-catalog-command-hook nil))
 				'hide))))
 
 (defun idlwave-user-catalog-command-hook (&optional arg)
@@ -1288,12 +1287,12 @@ will re-read the catalog."
 		     "-l" (expand-file-name "~/.emacs")
 		     "-l" "idlwave"
 		     "-f" "idlwave-rescan-catalog-directories"))
-	 (process (apply 'start-process "idlcat" 
+	 (process (apply #'start-process "idlcat"
 			 nil emacs args)))
     (setq idlwave-catalog-process process)
-    (set-process-sentinel 
+    (set-process-sentinel
      process
-     (lambda (pro why)
+     (lambda (_pro why)
        (when (string-match "finished" why)
 	 (setq idlwave-routines nil
 	       idlwave-system-routines nil
@@ -1302,7 +1301,7 @@ will re-read the catalog."
 	     (idlwave-update-routine-info '(4))))))
     (message "Background job started to update catalog file")))
 
-(defconst idlwave-user-catalog-widget-help-string 
+(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:
@@ -1337,18 +1336,18 @@ directories and save the routine info.
   (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
+		 :notify #'idlwave-widget-scan-user-lib-files
 		 "Scan & Save")
   (widget-insert "  ")
   (widget-create 'push-button
-		 :notify 'idlwave-delete-user-catalog-file
+		 :notify #'idlwave-delete-user-catalog-file
 		 "Delete File")
   (widget-insert "  ")
   (widget-create 'push-button
-		 :notify 
-		 (lambda (&rest ignore)
+		 :notify
+		 (lambda (&rest _ignore)
                    (let ((path-list (widget-get idlwave-widget :path-dirs)))
                      (dolist (x path-list)
                        (unless (memq 'lib (cdr x))
@@ -1357,8 +1356,8 @@ directories and save the routine info.
 		 "Select All Non-Lib")
   (widget-insert "  ")
   (widget-create 'push-button
-		 :notify 
-		 (lambda (&rest ignore)
+		 :notify
+		 (lambda (&rest _ignore)
                    (let ((path-list (widget-get idlwave-widget :path-dirs)))
                      (dolist (x path-list)
                        (idlwave-path-alist-remove-flag x 'user))
@@ -1366,27 +1365,28 @@ directories and save the routine info.
 		 "Deselect All")
   (widget-insert "  ")
   (widget-create 'push-button
-		 :notify (lambda (&rest ignore)
+		 :notify (lambda (&rest _ignore)
 			   (kill-buffer (current-buffer)))
 		 "Quit")
   (widget-insert "\n\n")
 
   (widget-insert "Select Directories: \n")
-  
+
   (setq idlwave-widget
-	(apply 'widget-create
+	(apply #'widget-create
 	       'checklist
-	       :value  (delq nil (mapcar (lambda (x) 
-					   (if (memq 'user (cdr x)) 
+	       :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 
+	       (mapcar (lambda (x)
+			 (list 'item
 			       (if (memq 'lib (cdr x))
 				   (concat "[LIB] " (car x) )
-				 (car x)))) dirs-list)))
+				 (car x))))
+		       dirs-list)))
   (widget-put idlwave-widget :path-dirs dirs-list)
   (widget-insert "\n")
   (use-local-map widget-keymap)
@@ -1394,14 +1394,14 @@ directories and save the routine info.
   (goto-char (point-min))
   (delete-other-windows))
 
-(defun idlwave-delete-user-catalog-file (&rest ignore)
+(defun idlwave-delete-user-catalog-file (&rest _ignore)
   (if (yes-or-no-p
-       (format "Delete file %s " idlwave-user-catalog-file))
+       (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)
+(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))
@@ -1409,7 +1409,7 @@ directories and save the routine info.
 	 (this-path-alist path-alist)
 	 dir-entry)
     (while (setq dir-entry (pop this-path-alist))
-      (if (member 
+      (if (member
 	   (if (memq 'lib (cdr dir-entry))
 	       (concat "[LIB] " (car dir-entry))
 	     (car dir-entry))
@@ -1418,7 +1418,6 @@ directories and save the routine info.
 	(idlwave-path-alist-remove-flag dir-entry 'user)))
     (idlwave-scan-user-lib-files path-alist)))
 
-(defvar font-lock-mode)
 (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)
@@ -1452,30 +1451,21 @@ directories and save the routine info.
     (message "Creating user catalog file...")
     (kill-buffer "*idlwave-scan.pro*")
     (kill-buffer (get-buffer-create "*IDLWAVE Widget*"))
-    (let ((font-lock-maximum-size 0)
-	  (auto-mode-alist nil))
-      (find-file idlwave-user-catalog-file))
-    (if (and (boundp 'font-lock-mode)
-	     font-lock-mode)
-	(font-lock-mode 0))
-    (erase-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)))
-    (goto-char (point-min))
-    ;; Save the buffer
-    (save-buffer 0)
-    (kill-buffer (current-buffer)))
+    (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)
@@ -1484,10 +1474,10 @@ directories and save the routine info.
   (idlwave-update-routine-info t))
 
 ;;----------------------------------------------------
-;; Library catalogs 
+;; Library catalogs
 
 (defun idlwave-scan-library-catalogs (&optional message-base no-load)
-  "Scan for library catalog files (.idlwave_catalog) and ingest.  
+  "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
@@ -1495,16 +1485,16 @@ 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 
+    (let ((dirs
 	   (if idlwave-library-path
 	       (idlwave-expand-path idlwave-library-path)
-	     (mapcar 'car idlwave-path-alist)))
+	     (mapcar #'car idlwave-path-alist)))
 	  (old-libname "")
 	  dir-entry dir catalog all-routines)
-      (if message-base (message message-base))
+      (if message-base (message "%s" message-base))
       (while (setq dir (pop dirs))
 	(catch 'continue
-	  (when (file-readable-p 
+	  (when (file-readable-p
 		 (setq catalog (expand-file-name ".idlwave_catalog" dir)))
 	    (unless no-load
 	      (setq idlwave-library-catalog-routines nil)
@@ -1512,26 +1502,25 @@ be set to nil to disable library catalog scanning."
 	      (condition-case nil
 		  (load catalog t t t)
 		(error (throw 'continue t)))
-	      (when (and 
-		     message-base 
-		     (not (string= idlwave-library-catalog-libname 
+	      (when (and
+		     message-base
+		     (not (string= idlwave-library-catalog-libname
 				   old-libname)))
-		(message "%s" (concat message-base 
-				      idlwave-library-catalog-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 
+		      (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 (concat message-base "done"))))))
+      (if message-base (message "%sdone" message-base)))))
 
 ;;----------------------------------------------------
 ;; Path Info
@@ -1547,36 +1536,27 @@ be set to nil to disable library catalog scanning."
 (defun idlwave-write-paths ()
   (interactive)
   (when (and idlwave-path-alist idlwave-system-directory)
-    (let ((font-lock-maximum-size 0)
-	  (auto-mode-alist nil))
-      (find-file idlwave-path-file))
-    (if (and (boundp 'font-lock-mode)
-	     font-lock-mode)
-	(font-lock-mode 0))
-    (erase-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")
-    (save-buffer 0)
-    (kill-buffer (current-buffer))))
+    (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-path-alist-add-flag (list-entry flag)
   "Add a flag to the path list entry, if not set."
-  (let ((flags (cdr list-entry)))
-    (add-to-list 'flags flag)
-    (setcdr list-entry flags)))
+  (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."
@@ -1624,10 +1604,10 @@ 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) 
+  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)
@@ -1635,12 +1615,12 @@ pro idlwave_print_info_entry,name,func=func,separator=sep
   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 
+  if meth then begin
       class = strmid(name,0,methsep)
       name  = strmid(name,methsep+2,strlen(name)-1)
-      if nargs gt 0 then begin 
+      if nargs gt 0 then begin
           ;; remove the self argument
           wh = where(args ne 'SELF',nargs)
           if nargs gt 0 then args = args[wh]
@@ -1649,7 +1629,7 @@ pro idlwave_print_info_entry,name,func=func,separator=sep
       ;; No class, just a normal routine.
       class = \"\"
   endelse
-   
+
   ;; Calling sequence
   cs = \"\"
   if func then cs = 'Result = '
@@ -1670,9 +1650,9 @@ pro idlwave_print_info_entry,name,func=func,separator=sep
           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
@@ -1684,19 +1664,19 @@ pro idlwave_routine_info,file
   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 
+  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 
+  endfor
   all = routine_info(/functions)
-  for i=0L,n_elements(all)-1L do begin 
-     if fileQ then begin 
+  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 
+  endfor
   print,'>>>END OF IDLWAVE ROUTINE INFO'
 end
 
@@ -1722,7 +1702,7 @@ pro idlwave_get_class_tags, 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
@@ -1739,11 +1719,11 @@ end
       (erase-buffer)
       (insert idlwave-routine-info.pro)
       (save-buffer 0))
-    (idlwave-shell-send-command 
+    (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" 
+     (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 wait)
     (setq idlwave-idlwave_routine_info-compiled t))
@@ -1769,9 +1749,9 @@ end
 					; 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))
+   (lambda ()
+     (idlwave-shell-routine-info-filter)
+     (idlwave-concatenate-rinfo-lists quiet run-hooks))
    'hide wait))
 
 (defun idlwave-sysvars-reset ()
@@ -1779,7 +1759,7 @@ end
 	   (idlwave-shell-is-running)
 	   idlwave-idlwave_routine_info-compiled)
       (idlwave-shell-send-command "idlwave_get_sysvars"
-				  'idlwave-process-sysvars 'hide)))
+				  #'idlwave-process-sysvars 'hide)))
 
 (defun idlwave-process-sysvars ()
   (idlwave-shell-filter-sysvars)
@@ -1793,27 +1773,28 @@ end
   (let ((text idlwave-shell-command-output)
 	(start 0)
 	(old idlwave-system-variables-alist)
-	var tags type name class link old-entry)
+	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) 
+	    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) 
+	    (cons (list var
+			(cons
+			 'tags
+			 (mapcar (lambda (x)
+				   (cons x
+					 (cdr (assq
+					       (idlwave-sintern-sysvartag x)
 					       (cdr (assq 'tags old-entry))))))
-				 tags)) link)
+				 tags))
+			link)
 		  idlwave-system-variables-alist)))
     ;; Keep the old value if query was not successful
     (setq idlwave-system-variables-alist
diff --git a/idlw-shell.el b/idlw-shell.el
index 016bf42488..7a110fc091 100644
--- a/idlw-shell.el
+++ b/idlw-shell.el
@@ -1,14 +1,14 @@
-;; idlw-shell.el --- run IDL as an inferior process of Emacs.
+;; idlw-shell.el --- run IDL as an inferior process of Emacs.  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-;;   2009  Free Software Foundation, Inc.
+;; Copyright (C) 1999-2024  Free Software Foundation, Inc.
 
-;; Authors: J.D. Smith 
-;;          Carsten Dominik 
-;;          Chris Chase 
+;; Authors: J.D. Smith
+;;          Carsten Dominik
+;;          Chris Chase
 ;; Maintainer: J.D. Smith
 ;; Version: VERSIONTAG
 ;; Keywords: processes
+;; Package: idlwave
 
 ;; This file is part of GNU Emacs.
 
@@ -23,12 +23,11 @@
 ;; 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 <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
-;; This mode is for IDL version 5 or later.  It should work on
-;; Emacs>20.3 or XEmacs>20.4.
+;; 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
@@ -41,14 +40,14 @@
 ;;
 ;; New versions of IDLWAVE, documentation, and more information
 ;; available from:
-;;                 http://github.com/jdtsmith/idlwave
+;;                 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 .emacs file:
+;; lines to your init file:
 ;;
 ;; (autoload 'idlwave-shell "idlw-shell" "IDLWAVE Shell" t)
 ;;
@@ -59,7 +58,7 @@
 ;;   The newest version of this file can be found on the maintainers
 ;;   web site.
 ;;
-;;     http://github.com/jdtsmith/idlwave
+;;     https://github.com/jdtsmith/idlwave
 ;;
 ;; DOCUMENTATION
 ;; =============
@@ -69,15 +68,6 @@
 ;; maintainers webpage (see under SOURCE)
 ;;
 ;;
-;; KNOWN PROBLEMS
-;; ==============
-;;
-;; Under XEmacs the Debug menu in the shell does not display the
-;; keybindings in the prefix map.  There bindings are available anyway - so
-;; it is a bug in XEmacs.
-;; The Debug menu in source buffers *does* display the bindings correctly.
-;;
-;;
 ;; CUSTOMIZATION VARIABLES
 ;; =======================
 ;;
@@ -93,7 +83,7 @@
 (require 'comint)
 (require 'idlwave)
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
 
 (defvar idlwave-shell-have-new-custom nil)
 
@@ -106,41 +96,35 @@
   :group 'idlwave)
 
 (defcustom idlwave-shell-prompt-pattern "^\r? ?IDL> "
-  "*Regexp to match IDL prompt at beginning of a line.
+  "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.
-
-This is a fine thing to set in your `.emacs' file."
-  :group 'idlwave-shell-general-setup
+process buffer."
   :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
+  "Name to be associated with the IDL process.
+The buffer for the process output is made by surrounding this
+name with `*'s."
   :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
+  "Non-nil means, never replace the shell frame with another buffer."
   :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
+  "Non-nil means, IDLWAVE should use a special frame to display shell buffer."
   :type 'boolean)
 
 (defcustom idlwave-shell-frame-parameters
   '((height . 30) (unsplittable . nil))
-  "The frame parameters for a dedicated idlwave-shell frame.
+  "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)))
 
@@ -148,25 +132,22 @@ The default makes the frame splittable, so that completion works correctly."
   "The fraction of the current frame height to allocate to a
 non-dedicated shell buffer window.  Only relevant if
 `idlwave-shell-use-dedicated-frame' is nil"
-  :group 'idlwave-shell-general-setup
   :type '(choice
 	  (const :tag "Default" nil)
 	  (float :tag "Fraction")))
 
 (defcustom idlwave-shell-raise-frame t
-  "*Non-nil means, `idlwave-shell' raises the frame showing the shell window."
-  :group 'idlwave-shell-general-setup
+  "Non-nil means, `idlwave-shell' raises the frame showing the shell window."
   :type 'boolean)
 
 (defcustom idlwave-shell-arrows-do-history t
-  "*Non-nil means UP and DOWN arrows move through command history.
+  "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
+`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)
@@ -175,49 +156,37 @@ t          Arrows force the cursor back to the current command line and
 ;; 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.
+  "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.
-Available on XEmacs and on Emacs 21.x or later.
 At any time you can toggle the display of the toolbar with
-`C-c C-d C-t' (`idlwave-shell-toggle-toolbar')."
-  :group 'idlwave-shell-general-setup
+\\[idlwave-shell-toggle-toolbar]."
   :type 'boolean)
 
 (defcustom idlwave-shell-temp-pro-prefix "/tmp/idltemp"
-  "*The prefix for temporary IDL files used when compiling regions.
+  "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)
 
-(defvar idlwave-shell-fix-inserted-breaks nil
-  "*OBSOLETE VARIABLE, is no longer used.
-
-The documentation of this variable used to be:
-If non-nil then run `idlwave-shell-remove-breaks' to clean up IDL messages.")
-
 (defcustom idlwave-shell-prefix-key "\C-c\C-d"
-  "*The prefix key for the debugging map `idlwave-shell-mode-prefix-map'.
+  "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
+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)
@@ -227,16 +196,12 @@ electric debug mode only when breakpoints are tripped."
   "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
 
-(defvar idlwave-shell-activate-alt-keybindings nil
-  "Obsolete variable.  See `idlwave-shell-debug-modifiers'.")
-
 (defcustom idlwave-shell-use-truename nil
-  "*Non-nil means, use use `file-truename' when looking for buffers.
+  "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.
@@ -245,26 +210,22 @@ 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 `\"'
+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
+  "Hook for customizing `idlwave-shell-mode'."
   :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.
+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")))
@@ -280,14 +241,12 @@ A command like `WINDOW,N,xsize=XX,ysize=YY' is sent to IDL."
   "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"
@@ -296,16 +255,14 @@ 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
+  "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
@@ -316,7 +273,6 @@ the copious shell traffic to be displayed."
 
 (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
@@ -338,18 +294,13 @@ 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"))))
 
-(defvar idlwave-shell-print-expression-function nil
-  "*OBSOLETE VARIABLE, is no longer used.")
-
 (defcustom idlwave-shell-separate-examine-output t
-  "*Non-nil means, put output of examine commands in their own buffer."
-  :group 'idlwave-shell-command-setup
+  "Non-nil means, put output of examine commands in their own buffer."
   :type 'boolean)
 
 (defcustom idlwave-shell-comint-settings
@@ -363,22 +314,19 @@ 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
+  "Non-nil means query the shell for object class on object completions."
   :type 'boolean)
 
 (defcustom idlwave-shell-use-input-mode-magic nil
-  "*Non-nil means, IDLWAVE should check for input mode spells in output.
+  "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
@@ -403,15 +351,15 @@ 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
+  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
+  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
+  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',
@@ -427,28 +375,25 @@ 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
+  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>'
+      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
+  "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
@@ -458,21 +403,18 @@ popup help text on the line."
   :group 'idlwave)
 
 (defcustom idlwave-shell-mark-stop-line t
-  "*Non-nil means, mark the source code line where IDL is currently stopped.
+  "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.
+`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.
-In Emacs 21, the overlay arrow is displayed in a special area and never
-hides any code, so setting this to 'arrow on Emacs 21 sounds like a good idea."
-  :group 'idlwave-shell-highlighting-and-faces
+a face highlighting may be better."
   :type '(choice
 	  (const :tag "No marking" nil)
 	  (const :tag "Use overlay arrow" arrow)
@@ -480,24 +422,21 @@ hides any code, so setting this to 'arrow on Emacs 21 sounds like a good idea."
 	  (const :tag "Face or arrow." t)))
 
 (defcustom idlwave-shell-overlay-arrow ">"
-  "*The overlay arrow to display at source lines where execution halts.
+  "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-use-overlay-arrow'."
-  :group 'idlwave-shell-highlighting-and-faces
+See also `idlwave-shell-mark-stop-line'."
   :type 'string)
 
 (defcustom idlwave-shell-stop-line-face 'highlight
-  "*The face for `idlwave-shell-stop-line-overlay'.
+  "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
+  "The color for the default face or overlay arrow when stopped."
   :type 'string)
 
 (defface idlwave-shell-electric-stop-line
@@ -511,35 +450,29 @@ electric debug mode.")
 
 (defcustom idlwave-shell-electric-stop-line-face
   'idlwave-shell-electric-stop-line
-  "*The face for `idlwave-shell-stop-line-overlay' when in electric debug mode.
+  "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.
+  "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
+`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')."
   :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)))
 
-(defvar idlwave-shell-use-breakpoint-glyph t
-  "Obsolete variable.  See `idlwave-shell-mark-breakpoints'.")
-
 (defcustom idlwave-shell-breakpoint-face 'idlwave-shell-bp
-  "*The face for breakpoint lines in the source code.
+  "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)
@@ -549,15 +482,13 @@ lines which have a breakpoint.  See also `idlwave-shell-mark-breakpoints'."
   (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))
+    "Face for highlighting lines with breakpoints."))
 
 (defcustom idlwave-shell-disabled-breakpoint-face
   'idlwave-shell-disabled-bp
-  "*The face for disabled breakpoint lines in the source code.
+  "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)
@@ -567,22 +498,19 @@ lines which have a breakpoint.  See also `idlwave-shell-mark-breakpoints'."
   (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))
+    "Face for highlighting lines with breakpoints."))
 
 
 (defcustom idlwave-shell-expression-face 'secondary-selection
-  "*The face for `idlwave-shell-expression-overlay'.
+  "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'.
+  "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
@@ -593,7 +521,7 @@ the expression output by IDL."
 
 ;; Other variables
 (defvar idlwave-shell-temp-pro-file nil
-  "Absolute pathname for temporary IDL file for compiling regions")
+  "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.
@@ -603,45 +531,23 @@ 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
+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
-	      (idlwave-shell-make-temp-file idlwave-shell-temp-pro-prefix))))
+	      (make-temp-file idlwave-shell-temp-pro-prefix))))
    ((eq type 'pro)
     (or idlwave-shell-temp-pro-file
 	(setq idlwave-shell-temp-pro-file
-	      (idlwave-shell-make-temp-file idlwave-shell-temp-pro-prefix))))
+	      (make-temp-file idlwave-shell-temp-pro-prefix))))
    (t (error "Wrong argument (idlwave-shell-temp-file): %s"
 	     (symbol-name type)))))
 
 
-(defun idlwave-shell-make-temp-file (prefix)
-  "Create a temporary file."
-  ; Hard coded make-temp-file for Emacs<21
-  (if (fboundp 'make-temp-file)
-      (make-temp-file prefix)
-    (let (file
-	  (temp-file-dir (if (boundp 'temporary-file-directory)
-			     temporary-file-directory
-			   "/tmp")))
-      (while (condition-case ()
-		 (progn
-		   (setq file
-			 (make-temp-name
-			  (expand-file-name prefix temp-file-dir)))
-                   (if (featurep 'xemacs)
-		       (write-region "" nil file nil 'silent nil)
-		     (write-region "" nil file nil 'silent nil 'excl))
-		   nil)
-	       (file-already-exists t))
-	;; the file was somehow created by someone else between
-	;; `make-temp-name' and `write-region', let's try again.
-	nil)
-      file)))
-
+(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
@@ -655,17 +561,11 @@ the directory stack.")
   "Additional info displayed in the mode line.")
 
 (defvar idlwave-shell-default-directory nil
-  "The default directory in the idlwave-shell buffer, of outside use.")
+  "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-...'.")
 
-;; Highlighting uses overlays.  When necessary, require the emulation.
-(if (not (fboundp 'make-overlay))
-    (condition-case nil
-	(require 'overlay)
-      (error nil)))
-
 (defvar idlwave-shell-stop-line-overlay nil
   "The overlay for where IDL is currently stopped.")
 (defvar idlwave-shell-is-stopped nil)
@@ -698,16 +598,14 @@ the directory stack.")
  ((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 (or (featurep 'xemacs)            ; XEmacs can do also ttys
-	    (fboundp 'tty-defined-colors) ; Emacs 21 as well
-	    (display-graphic-p))                ; Window systems always
+  (when (display-graphic-p)
     (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 plus arrow on window systems, 
+  ;; IDLWAVE may decide.  Will use a face plus arrow on window systems,
   ;; just arrow elsewhere
   (if (display-graphic-p)
       (progn
@@ -752,13 +650,13 @@ the directory stack.")
 
 (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 SHOW-IF-ERROR
-REDISPLAY\), where CMD is a string to be sent to IDL and PCMD is
+Each element of the list is list of (CMD PCMD HIDE SHOW-IF-ERROR
+REDISPLAY), where CMD is a string to be sent to IDL and PCMD is
 a post-command to be called after CMD completes.  If HIDE is
 non-nil, hide the output from command CMD.  If SHOW-IF-ERROR is
 non-nil, show the full output if it contains an error.  If
 REDISPLAY is non-nil, clear the current stopped line position if
-no position is recognized (unless it is 'disable, in which case
+no position is recognized (unless it is `disable', in which case
 don't update line position unless an error is found).  PCMD,
 HIDE, and SHOW-IF-ERROR are optional.")
 
@@ -800,30 +698,30 @@ with `*'s."
     "^% Skipped to:"
     "^% Stop encountered:"
     )
-  "*A list of regular expressions matching IDL messages.
+  "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 "\\|")
+  (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.")
+  "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.
+  "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.")
+  "Regular expression matching an IDL breakpoint message line.")
 
 (defconst idlwave-shell-electric-debug-help
   "   ==> IDLWAVE Electric Debug Mode Help <==
@@ -877,12 +775,54 @@ IDL has currently stepped.")
 (defvar idlwave-shell-bp-buffer)
 (defvar idlwave-shell-command-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)
 
-(defun idlwave-shell-mode ()
+(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 "\C-a"     #'comint-bol-or-process-mark)
+    (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-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 map [(shift up)]
+                #'idlwave-shell-noblock-up-or-history)
+    (define-key map [(shift down)]
+                #'idlwave-shell-noblock-down-or-history)
+
+    (define-key map "\C-c " #'idlwave-shell-accumulate)
+    (define-key map "\M-\r"
+                (lambda () (interactive (idlwave-split-line 'noindent))))
+    (define-key map [(shift mouse-3)] #'idlwave-mouse-context-help)
+    map)
+  "Keymap for `idlwave-mode'.")
+
+
+(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)
+
+(define-derived-mode idlwave-shell-mode comint-mode "IDL-Shell"
   "Major mode for interacting with an inferior IDL process.
 
 1. Shell Interaction
@@ -894,7 +834,7 @@ IDL has currently stepped.")
 
    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
+   mostly on the key \\`C-c'.  Command history is also available with
    the arrow keys UP and DOWN.
 
 2. Completion
@@ -906,7 +846,7 @@ IDL has currently stepped.")
 
 3. Routine Info
    ------------
-   `\\[idlwave-routine-info]' displays information about an IDL routine near point,
+   \\[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
@@ -921,7 +861,7 @@ IDL has currently stepped.")
    ---------
    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
+   \\`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.
 
@@ -942,7 +882,7 @@ IDL has currently stepped.")
    \\[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
-   configureable set of custom examine commands using
+   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.
@@ -956,15 +896,15 @@ IDL has currently stepped.")
    -------------------------------
    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, check IDLWAVE's
-   homepage at URL `http://github.com/jdtsmith/idlwave'.
+   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
 
-  (interactive)
   ; Make sure config files and paths, etc. are available.
   (idlwave-setup)
   (unless (file-name-absolute-p idlwave-shell-command-history-file)
@@ -972,22 +912,17 @@ IDL has currently stepped.")
 	  (expand-file-name idlwave-shell-command-history-file
 			    idlwave-config-directory)))
 
-  ;; We don't do `kill-all-local-variables' here, because this is done by
-  ;; comint
   (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)
-  (make-local-variable 'comint-completion-addsuffix)
+  ;; (setq comint-input-ring-size 64)
   (set (make-local-variable 'completion-ignore-case) t)
-  (setq comint-completion-addsuffix '("/" . ""))
+  (set (make-local-variable 'comint-completion-addsuffix) '("/" . ""))
   (setq comint-input-ignoredups t)
   (setq comint-input-sender (function idlwave-shell-sender))
-  
-  (setq major-mode 'idlwave-shell-mode)
-  (setq mode-name "IDL-Shell")
+
   (setq idlwave-shell-mode-line-info nil)
   (setq mode-line-format
 	'(""
@@ -1020,8 +955,8 @@ IDL has currently stepped.")
 		"[ \t\n]*\\'"))
 
   (when idlwave-shell-query-for-class
-      (add-to-list (make-local-variable 'idlwave-determine-class-special)
-		   'idlwave-shell-get-object-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
@@ -1035,12 +970,10 @@ IDL has currently stepped.")
   (setq idlwave-shell-default-directory default-directory)
   (setq idlwave-shell-hide-output nil)
 
-  (add-hook 'kill-buffer-hook 'idlwave-shell-kill-shell-buffer-confirm
+  (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)
-  (use-local-map idlwave-shell-mode-map)
-  (easy-menu-add idlwave-shell-mode-menu idlwave-shell-mode-map)
+  (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
@@ -1049,7 +982,7 @@ IDL has currently stepped.")
 	(set (make-local-variable (car entry)) (cdr entry)))))
 
 
-  (unless (memq 'comint-carriage-motion
+  (unless (memq #'comint-carriage-motion
 		(default-value 'comint-output-filter-functions))
     ;; Strip those pesky ctrl-m's.
     (add-hook 'comint-output-filter-functions
@@ -1063,15 +996,13 @@ IDL has currently stepped.")
 		      (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))
+    (add-hook 'comint-output-filter-functions #'comint-strip-ctrl-m nil 'local))
 
   ;; IDLWAVE syntax, and turn on abbreviations
-  (setq local-abbrev-table idlwave-mode-abbrev-table)
-  (set-syntax-table idlwave-mode-syntax-table)
   (set (make-local-variable 'comment-start) ";")
   (setq abbrev-mode t)
 
-  (add-hook 'post-command-hook 'idlwave-command-hook nil t)
+  (add-hook 'post-command-hook #'idlwave-command-hook nil t)
 
   ;; Read the command history?
   (when (and idlwave-shell-save-command-history
@@ -1091,10 +1022,9 @@ IDL has currently stepped.")
   (idlwave-shell-send-command
    (format "!MORE=0 & defsysv,'!idlwave_version','%s',1" idlwave-mode-version)
    nil 'hide)
-  (run-mode-hooks 'idlwave-shell-mode-hook)
   ;; Read the paths, and save if they changed
   (idlwave-shell-send-command idlwave-shell-path-query
-			      'idlwave-shell-get-path-info
+			      #'idlwave-shell-get-path-info
 			      'hide))
 
 (defvar idlwave-system-directory)
@@ -1131,7 +1061,7 @@ IDL has currently stepped.")
       (setq idlwave-path-alist old-path-alist))))
 
 (if (not (fboundp 'idl-shell))
-    (fset 'idl-shell 'idlwave-shell))
+    (defalias 'idl-shell #'idlwave-shell))
 
 (defvar idlwave-shell-idl-wframe nil
   "Frame for displaying the IDL shell window.")
@@ -1155,8 +1085,7 @@ Will typically only apply if the buffer isn't visible."
 	(setq idlwave-shell-display-wframe
 	      (if (eq (selected-frame) idlwave-shell-idl-wframe)
 		  (or
-		   (let ((flist (frames-on-display-list))
-			 (frame (selected-frame)))
+		   (let ((flist (frames-on-display-list)))
 		     (catch 'exit
 		       (while flist
 			 (if (not (eq (car flist)
@@ -1170,19 +1099,19 @@ Will typically only apply if the buffer isn't visible."
   "Return the frame to be used for the shell buffer."
   (if idlwave-shell-use-dedicated-frame
       (setq idlwave-shell-idl-wframe
-	    (cond 
-	     ((frame-live-p idlwave-shell-idl-wframe) 
+	    (cond
+	     ((frame-live-p idlwave-shell-idl-wframe)
 	      idlwave-shell-idl-wframe)
 
 	     ((let ((buf (get-buffer (idlwave-shell-buffer))) win)
 		(and (buffer-live-p buf)
 		     (setq win (get-buffer-window buf))
 		     (window-frame win))))
-	     
+
 	     (t (make-frame idlwave-shell-frame-parameters))))))
 
 ;;;###autoload
-(defun idlwave-shell (&optional arg quick)
+(defun idlwave-shell (&optional arg _quick)
   "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.
@@ -1208,7 +1137,7 @@ See also the variable `idlwave-shell-prompt-pattern'.
 	(and idlwave-shell-use-dedicated-frame
 	     (setq idlwave-shell-idl-wframe (selected-frame)))
 	(add-hook 'idlwave-shell-sentinel-hook
-		  'save-buffers-kill-emacs t))
+		  #'save-buffers-kill-emacs t))
 
     ;; A non-nil arg means, we want a dedicated frame.  This will last
     ;; for the current editing session.
@@ -1218,7 +1147,7 @@ See also the variable `idlwave-shell-prompt-pattern'.
     ;; 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
+	     (buf (apply #'make-comint
 			 idlwave-shell-process-name prg nil
 			 (if (stringp idlwave-shell-command-line-options)
 			     (idlwave-split-string
@@ -1226,8 +1155,8 @@ See also the variable `idlwave-shell-prompt-pattern'.
 			   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-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
@@ -1263,7 +1192,7 @@ See also the variable `idlwave-shell-prompt-pattern'.
 
 (defun idlwave-shell-hide-p (type &optional list)
   "Whether to hide this type of command.
-Return either nil or 'hide."
+Return either nil or `hide'."
   (let ((list (or list idlwave-shell-show-commands)))
     (if (listp list)
       (if (not (memq type list)) 'hide))))
@@ -1282,7 +1211,7 @@ Return either nil or 'hide."
 					     show-if-error redisplay)
   "Send a command to the IDL process.
 
-\(CMD PCMD HIDE SHOW-IF-ERROR REDISPLAY\) are placed at the
+\(CMD PCMD HIDE SHOW-IF-ERROR REDISPLAY) 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.
@@ -1291,21 +1220,21 @@ 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
+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
+`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
+\(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.
 
-If REDISPLAY is 'disable, disable line redisplay for all but
+If REDISPLAY is `disable', disable line redisplay for all but
 errors.  If REDISPLAY is otherwise non-nil, clear the current
 line position as state is scanned if no stop line message is
 recognized."
@@ -1351,8 +1280,8 @@ recognized."
 	    ;; IDL ready for command, execute it
 	    (let* ((lcmd (car idlwave-shell-pending-commands))
 		   (cmd (car lcmd))
-		   (pcmd (nth 1 lcmd))
-		   (hide (nth 2 lcmd)))
+		   ;; (pcmd (nth 1 lcmd))
+		   ) ;; (hide (nth 2 lcmd))
 	      ;; If this is an executive command, reset the stack pointer
 	      (if (eq (string-to-char cmd) ?.)
 		  (setq idlwave-shell-calling-stack-index 0))
@@ -1365,9 +1294,9 @@ recognized."
 	      (set-marker comint-last-input-end (point))
 	      (comint-simple-send proc cmd)
 	      (setq idlwave-shell-ready nil)
-	      
+
 	      ;; If waiting, accept all output now
-	      (when (equal preempt 'wait) 
+	      (when (equal preempt 'wait)
 		(while (not idlwave-shell-ready)
 		  (when (not (accept-process-output proc 6)) ; long wait
 		    (setq idlwave-shell-pending-commands nil)
@@ -1380,10 +1309,11 @@ recognized."
 Disables line display after state scanning."
   (let (result)
     ;; Only return when you've received the output
-    (idlwave-shell-send-command 
-     cmd 
-     '(progn (idlwave-shell-strip-input)
-	     (setq result idlwave-shell-command-output))
+    (idlwave-shell-send-command
+     cmd
+     (lambda ()
+       (idlwave-shell-strip-input)
+       (setq result idlwave-shell-command-output))
      'hide 'wait nil 'disable)
     ;; (with-current-buffer ;; DEBUGXXX
     ;; 	(get-buffer-create "*idlwave-shell-output*")
@@ -1415,10 +1345,7 @@ See also the variable `idlwave-shell-input-mode-spells'."
     (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
-    (if (fboundp 'start-itimer)
-	(start-itimer "IDLWAVE Char Mode" 'idlwave-shell-char-mode-loop 0.5
-		      nil nil t 'no-error)
-      (run-at-time 0.5 nil 'idlwave-shell-char-mode-loop 'no-error)))))
+    (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)
@@ -1426,7 +1353,7 @@ See also the variable `idlwave-shell-input-mode-spells'."
 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 `C-g'.  The loop also exits automatically
+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)
 
@@ -1441,7 +1368,8 @@ when the IDL prompt gets displayed again after the current IDL command."
 	(funcall errf "No IDL program seems to be waiting for input"))
 
     ;; OK, start the loop
-    (message "Character mode on:  Sending single chars (`C-g' to exit)")
+    (message (substitute-command-keys
+              "Character mode on:  Sending single chars (\\[keyboard-quit] to exit)"))
     (message
      (catch 'exit
        (while t
@@ -1478,29 +1406,29 @@ Move normally inside of blocks, unless NOBLOCK-MOVE is non-nil."
 	 (proc-pos (if proc (marker-position (process-mark proc))))
 	 (arg (or arg 1))
 	 (arg (if up arg (- arg))))
-    
+
     (if (eq t idlwave-shell-arrows-do-history) (goto-char proc-pos))
     (if (and proc
 	     idlwave-shell-arrows-do-history
 	     (or noblock-move
-		 (if up
-		     (= (line-number-at-pos) (line-number-at-pos proc-pos))
-		   (= (line-number-at-pos) (line-number-at-pos (point-max))))))
+		 (= (line-end-position)
+		    (save-excursion
+		      (goto-char (if up proc-pos (point-max)))
+		      (line-end-position)))))
 	(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."
+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."
+Otherwise just go down one line."
   (interactive "p")
   (idlwave-shell-move-or-history nil arg))
-
 (defun idlwave-shell-noblock-up-or-history (&optional arg)
   (interactive "p")
   (idlwave-shell-move-or-history t arg 'noblock))
@@ -1510,12 +1438,8 @@ Move normally inside of blocks, unless NOBLOCK-MOVE is non-nil."
   (idlwave-shell-move-or-history nil arg 'noblock))
 
 
-;; Newer versions of comint.el changed the name of comint-filter to
-;; comint-output-filter.
-(defun idlwave-shell-comint-filter (process string) nil)
-(if (fboundp 'comint-output-filter)
-    (fset 'idlwave-shell-comint-filter (symbol-function 'comint-output-filter))
-  (fset 'idlwave-shell-comint-filter (symbol-function 'comint-filter)))
+(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."
@@ -1532,15 +1456,14 @@ Move normally inside of blocks, unless NOBLOCK-MOVE is non-nil."
   "Send the command, stripping newlines after non-quoted
 ampersands beforehand."
   (if (string-match "&\\s-*\n" string)
-      (save-excursion
-	(set-buffer (get-buffer-create idlwave-shell-command-buffer))
+      (with-current-buffer (get-buffer-create idlwave-shell-command-buffer)
 	(if (not (eq major-mode 'idlwave-mode)) (idlwave-mode))
 	(erase-buffer)
 	(insert string)
 	(goto-char (point-min))
 	(while (and (re-search-forward "&\\s-*\n" nil t)
 		    (progn (goto-char (match-beginning 0))
-			   (not  (or 
+			   (not  (or
 				  (idlwave-in-comment)
 				  (idlwave-in-quote)))))
 	  (goto-char (match-end 0))
@@ -1576,119 +1499,114 @@ command queue."
   (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
+	;; Ring the bell if necessary
+	(while (setq p (string-match "\C-G" string))
+	  (ding)
+	  (aset string p ?\C-j ))
+	(if (and idlwave-shell-current-command
+		 (nth 2 idlwave-shell-current-command))
+	    ;; We're hiding output
+	    (with-current-buffer
+		(get-buffer-create idlwave-shell-hidden-output-buffer)
+	      (goto-char (point-max))
+	      (insert string))
+	  ;; Not hiding, just put in the shell buffer
+	  (comint-output-filter proc string))
+
+	;; Watch for magic prompt after a newline - need to
+	;; accumulate the current line since it may not be sent
+	;; all at once.
+	(if (string-match "\n" string)
 	    (progn
-	      ;; Ring the bell if necessary
-	      (while (setq p (string-match "\C-G" string))
-		(ding)
-		(aset string p ?\C-j ))
-	      (if (and idlwave-shell-current-command
-		       (nth 2 idlwave-shell-current-command)) 
-		  ;; We're hiding output
-		  (with-current-buffer 
-		      (get-buffer-create idlwave-shell-hidden-output-buffer)
+	      (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
+	(if (setq idlwave-shell-ready
+		  (string-match idlwave-shell-prompt-pattern
+				idlwave-shell-accumulation))
+	    (let ((pcmd (nth 1 idlwave-shell-current-command))
+		  (hide (nth 2 idlwave-shell-current-command))
+		  (show-if-error (nth 3 idlwave-shell-current-command))
+		  (redisplay (nth 4 idlwave-shell-current-command)))
+
+	      ;; Gather the command output
+	      (if hide
+		  ;; Hidden output
+		  (with-current-buffer idlwave-shell-hidden-output-buffer
+		    (goto-char (point-min))
+		    ;; Remove pesky C-M's from text
+		    (while (re-search-forward "\r+$" nil t)
+		      (replace-match "" t t))
+		    (setq full-output (buffer-string))
 		    (goto-char (point-max))
-		    (insert string))
-		;; Not hiding, just put in the shell buffer
-		(idlwave-shell-comint-filter proc string))
-
-	      ;; Watch for magic prompt after a newline - need to
-	      ;; accumulate the current line since it may not be sent
-	      ;; all at once.
-	      (if (string-match "\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 
-				     (progn (string-match "\\(.*[\n\r]+\\)*" 
-							  string)
-	 				    (match-end 0)))))
-		(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
-	      (if (setq idlwave-shell-ready
-			(string-match idlwave-shell-prompt-pattern
-				      idlwave-shell-accumulation))
-		  (let ((pcmd (nth 1 idlwave-shell-current-command))
-			(hide (nth 2 idlwave-shell-current-command))
-			(show-if-error (nth 3 idlwave-shell-current-command))
-			(redisplay (nth 4 idlwave-shell-current-command)))
-		    
-		    ;; Gather the command output
-		    (if hide
-			;; Hidden output
-			(with-current-buffer idlwave-shell-hidden-output-buffer
-			  (goto-char (point-min))
-			  ;; Remove pesky C-M's from text
-			  (while (re-search-forward "\r+$" nil t)
-			    (replace-match "" t t))
-			  (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)))
-			  (erase-buffer))
-		      ;; In-shell output
-		      (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) 
-				 (point))
-			       comint-last-input-end))))
-
-		    ;; Scan for state (any errors?)
-		    (idlwave-shell-scan-for-state redisplay)
-
-		    ;; Conditionally show some (or all) hidden output
-		    (when hide
-		      (if (and show-if-error
-			       (eq idlwave-shell-current-state 'error))
-			  ;; Show full output if it contains an error
-			  (idlwave-shell-comint-filter proc full-output)
-			(if (eq hide 'mostly)
-			    ;; Filter % lines, and show anything that remains
-			    (let ((filtered
-				   (idlwave-shell-filter-hidden-output 
-				    full-output)))
-			      (if filtered
-				  (idlwave-shell-comint-filter proc 
-							       filtered))))))
-
-		    ;; We've fully processed all output of this
-		    ;; command now: reset accumulation to clear the
-		    ;; way for next command (which may be in the
-		    ;; post-command hook!)  Leave command-output, and
-		    ;; set completed-command, which the
-		    ;; post-command-hook may need to analyze.
-		    (setq idlwave-shell-accumulation nil
-			  idlwave-shell-completed-command 
-			  idlwave-shell-current-command
-			  idlwave-shell-current-command nil)
-		    
-		  
-		    ;; Call the post-command hook, if any.
-		    (if pcmd
-			(if (listp pcmd) (eval pcmd) (funcall pcmd)))
-		    
-		    (setq idlwave-shell-command-output nil)
-		    
-		    ;; Send any pending commands
-		    (idlwave-shell-send-command)))
-	      (store-match-data data))))))
+		    (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)))
+		    (erase-buffer))
+		;; In-shell output
+		(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)
+			   (point))
+			 comint-last-input-end))))
+
+	      ;; Scan for state (any errors?)
+	      (idlwave-shell-scan-for-state redisplay)
+
+	      ;; Conditionally show some (or all) hidden output
+	      (when hide
+		(if (and show-if-error
+			 (eq idlwave-shell-current-state 'error))
+		    ;; Show full output if it contains an error
+		    (comint-output-filter proc full-output)
+		  (if (eq hide 'mostly)
+		      ;; Filter % lines, and show anything that remains
+		      (let ((filtered
+			     (idlwave-shell-filter-hidden-output
+			      full-output)))
+			(if filtered
+			    (comint-output-filter proc filtered))))))
+
+	      ;; We've fully processed all output of this
+	      ;; command now: reset accumulation to clear the
+	      ;; way for next command (which may be in the
+	      ;; post-command hook!)  Leave command-output, and
+	      ;; set completed-command, which the
+	      ;; post-command-hook may need to analyze.
+	      (setq idlwave-shell-accumulation nil
+		    idlwave-shell-completed-command
+		    idlwave-shell-current-command
+		    idlwave-shell-current-command nil)
+
+
+	      ;; Call the post-command hook, if any.
+	      (if pcmd
+		  (if (functionp pcmd) (funcall pcmd) (eval pcmd t)))
+
+	      (setq idlwave-shell-command-output nil)
+
+	      ;; Send any pending commands
+	      (idlwave-shell-send-command)))
+	(store-match-data data))))
 
 (defun idlwave-shell-sentinel (process event)
   "The sentinel function for the IDLWAVE shell process."
@@ -1726,8 +1644,8 @@ command queue."
 ;; 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.  
+  "^% 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.")
 
@@ -1735,16 +1653,16 @@ number.")
   "^% .*\\(?:\n[^%].*\\)*\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]+\\s-*.*\\)\n"
+(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 
+(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 
+  (concat
    "\\("                                 ; program name group (1)
    "\\$MAIN\\$\\|"                   	 ; main level routine
    "\\<[a-zA-Z][a-zA-Z0-9_$:]*"          ; start with a letter followed by [..]
@@ -1761,7 +1679,7 @@ number.")
    "\\(\n[ \t]*[^\t\n]+\\)*"             ; continuation line(s) file name (6)
    "\\)"                                 ; end line number group (5)
    )
-  "*A regular expression to parse out the file name and line number.
+  "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.
@@ -1778,10 +1696,10 @@ 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
+`error', `halt', or `breakpoint', which describes the status, or nil
 for none of the above.  If REDISPLAY is non-nil, clear the line
 position if no recognized message is found, unless it is
-'disable, in which case no redisplay occurs except for errors."
+`disable', in which case no redisplay occurs except for errors."
   (let (trace)
 
     (cond
@@ -1854,7 +1772,7 @@ position if no recognized message is found, unless it is
 	(if bp
 	    (let ((cmd (idlwave-shell-bp-get bp 'cmd)))
 	      (if cmd ;; Execute any breakpoint command
-		  (if (listp cmd) (eval cmd) (funcall cmd))))
+		  (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)))
@@ -1869,7 +1787,7 @@ position if no recognized message is found, unless it is
 
      ;; Otherwise, no particular state: remove line display if requested
      (t (setq idlwave-shell-current-state nil)
-	(if redisplay 
+	(if redisplay
 	    (idlwave-shell-display-line nil))))))
 
 
@@ -1932,7 +1850,7 @@ This has some small chance of selecting the incorrect file, but
 there's no way around it.  FILE-PIECES is a list of file
 portions."
   (idlwave-shell-check-file-spaces-recurs (cdr file-pieces) (car file-pieces)))
-		     
+
 (defun idlwave-shell-check-file-spaces-recurs (file-pieces file)
   "Helper recursive function for check-file-spaces."
   (if (null file-pieces) ; we've reached a leaf
@@ -1940,7 +1858,7 @@ portions."
     (let ((list '(nil t)) newfile); not a leaf, recurs over both options
       (while (and
 	      (not (setq newfile
-			 (idlwave-shell-check-file-spaces-recurs 
+			 (idlwave-shell-check-file-spaces-recurs
 			  (cdr file-pieces)
 			  (concat file (if (car list) " ") (car file-pieces)))))
 	      (setq list (cdr list))))
@@ -1951,7 +1869,7 @@ portions."
 IDL can convert a single space to a newline, so we must check all options."
   (let ((start 0) file-pieces)
     ;; We scan no further than to the next "^%" line
-    (if (string-match "\n%" file) 
+    (if (string-match "\n%" file)
 	(setq file (substring file 0 (match-beginning 0))))
     ;; Take out the line breaks (newline followed by two spaces)
     (while (string-match "[\t]*\n  " file start)
@@ -2002,7 +1920,7 @@ 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"
+     (apply #'format "window,%d,xs=%d,ys=%d"
 	    n idlwave-shell-graphics-window-size)
      nil (idlwave-shell-hide-p 'misc 'show-if-error))))
 
@@ -2013,7 +1931,7 @@ This command queries IDL with the command bound to
 directory."
   (interactive)
   (idlwave-shell-send-command idlwave-shell-dirstack-query
-			      'idlwave-shell-filter-directory
+			      #'idlwave-shell-filter-directory
 			      'hide 'wait))
 
 (defun idlwave-shell-escape-main-program ()
@@ -2029,13 +1947,13 @@ session.  Using .skip and .out, we can escape the routine."
       ;; In a $MAIN$ routine
       (setq skiplines
 	    (- (string-to-number
-		(idlwave-shell-command 
+		(idlwave-shell-command
 		 (concat "print,file_lines('" file "')")))
 	       line))
-      (while (and 
+      (while (and
 	    (> skiplines 0)
 	    (string-match "% Can't continue from this point"
-			  (idlwave-shell-command 
+			  (idlwave-shell-command
 			   (concat ".skip " (number-to-string skiplines)))))
 	(setq skiplines (1- skiplines)))
       (when (>= skiplines 0)
@@ -2044,17 +1962,17 @@ session.  Using .skip and .out, we can escape the routine."
 	  (idlwave-shell-command ".return"))
 	(idlwave-shell-send-command "help,/trace" nil 'hide)))))
 
-(defun idlwave-shell-retall (&optional arg)
+(defun idlwave-shell-retall ()
   "Return from the entire calling stack."
-  (interactive "P")
+  (interactive)
   (save-selected-window
     (idlwave-shell-send-command "retall" nil ;'idlwave-shell-escape-main-program
 				(if (idlwave-shell-hide-p 'misc) 'mostly)
 				nil 'show-if-error 'redisplay)))
 
-(defun idlwave-shell-closeall (&optional arg)
+(defun idlwave-shell-closeall ()
   "Close all open files."
-  (interactive "P")
+  (interactive)
   (idlwave-shell-send-command "close,/all" nil
 			      (idlwave-shell-hide-p 'misc) nil t))
 
@@ -2095,14 +2013,14 @@ HEAP_GC, /VERBOSE"
     (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))
+    (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 ()
-  "Function which parses the special output from idlwave_routine_info.pro."
+  "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)
@@ -2142,13 +2060,14 @@ HEAP_GC, /VERBOSE"
 	    key (nth 4 specs)
 	    keys (if (and (stringp key)
 			  (not (string-match "\\` *\\'" key)))
-		     (mapcar 'list
+		     (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))
+			   (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"
@@ -2237,27 +2156,27 @@ Change the default directory for the process buffer to concur."
       (idlwave-shell-send-command
        (concat "if obj_valid(" expression ") then print,obj_class("
 	       expression ")")
-       'idlwave-shell-parse-object-class
+       #'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-ignore-case idlwave-shell-get-object-class
-				  (idlwave-class-alist))))
+	       (not (assoc-string idlwave-shell-get-object-class
+				  (idlwave-class-alist)
+				  'ignore-case)))
 	  (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]\\(" 
+    (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 
+	(setq idlwave-shell-get-object-class
 	      (match-string 1 idlwave-shell-command-output)))))
 
 (defvar idlwave-sint-sysvars nil)
-(add-hook 'idlwave-load-hook
-	  (lambda () (idlwave-new-sintern-type 'execcomm)))
+(idlwave-new-sintern-type execcomm)
 
 (defun idlwave-shell-executive-command ()
   "Return the name of the current executive command, if any."
@@ -2269,16 +2188,16 @@ Change the default directory for the process buffer to concur."
 
 (defun idlwave-shell-filename-string ()
   "Return t if in a string and after what could be a file name."
-  (let ((limit (save-excursion (beginning-of-line) (point))))
+  (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
-      (memq (preceding-char) '(?\' ?\")))))
+      (and (memq (preceding-char) '(?\' ?\")) t))))
 
 (defun idlwave-shell-batch-command ()
-  "Return t if we're in a batch command statement like @foo"
-  (let ((limit (save-excursion (beginning-of-line) (point))))
+  "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)
@@ -2286,7 +2205,7 @@ Change the default directory for the process buffer to concur."
       (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"
+  "Return t if we're in a shell command statement like \"$ls\"."
   (save-excursion
     (idlwave-beginning-of-statement)
     (looking-at "\\$")))
@@ -2309,18 +2228,18 @@ overlays."
 (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))
+   (let ((csi idlwave-shell-calling-stack-index))
+     (lambda ()
+       ;; scanning for the state will reset the stack level - restore it
+       (setq idlwave-shell-calling-stack-index csi)
+       ;; 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)))
+	 (stack (delq nil (mapcar #'idlwave-shell-parse-line lines)))
 	 (nmax (1- (length stack)))
 	 (nmin 0) message)
     (cond
@@ -2353,14 +2272,14 @@ overlays."
 (defun idlwave-shell-stack-up ()
   "Display the source code one step up the calling stack."
   (interactive)
-  (incf idlwave-shell-calling-stack-index)
-;  (message "scsi-up: %d" idlwave-shell-calling-stack-index)
+  (cl-incf idlwave-shell-calling-stack-index)
+  ;; (message "scsi-up: %d" 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)
-;  (message "scsi-down: %d" idlwave-shell-calling-stack-index)
-  (decf idlwave-shell-calling-stack-index)
+  ;; (message "scsi-down: %d" idlwave-shell-calling-stack-index)
+  (cl-decf idlwave-shell-calling-stack-index)
   (idlwave-shell-display-level-in-calling-stack 'hide))
 
 (defun idlwave-shell-goto-frame (&optional frame)
@@ -2404,8 +2323,8 @@ is used.  Does nothing if the resulting frame is nil."
 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
+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
@@ -2423,8 +2342,8 @@ matter what the settings of that variable."
 	;; fixme: errors are dangerous in shell filters.  IDL LAMBDA
 	;; functions are not stored as code, so just silently ignore
 	;; these errors.
-	(unless (string-match-p "^IDL\$LAMBDA" (caddr frame))
-	  (error "invalid frame - unable to access file: %s" (car frame)))
+	(unless (string-match-p "^IDL\\$LAMBDA" (caddr frame))
+	  (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.
@@ -2464,9 +2383,9 @@ matter what the settings of that variable."
                                    idlwave-shell-electric-stop-line-face
                                  idlwave-shell-stop-line-face))
 		  (move-overlay idlwave-shell-stop-line-overlay
-				(point) (save-excursion (end-of-line) (point))
+				(point) (line-end-position)
 				(current-buffer))))
-	    ;; Always use the arrow 
+	    ;; Always use the arrow
 	    (if idlwave-shell-mark-stop-line
 		(setq overlay-arrow-string idlwave-shell-overlay-arrow))
 	    (or overlay-arrow-position  ; create the marker if necessary
@@ -2608,7 +2527,7 @@ failure of a command.  For example, this is called from
   (interactive)
   (idlwave-shell-stop-line-pending)
   (idlwave-shell-send-command ".c" (unless no-show
-				     '(idlwave-shell-redisplay 'hide))
+				     (lambda () (idlwave-shell-redisplay 'hide)))
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
 
@@ -2616,7 +2535,7 @@ failure of a command.  For example, this is called from
   "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)
+  (idlwave-shell-send-command ".go" (lambda () (idlwave-shell-redisplay 'hide))
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
 
@@ -2624,7 +2543,7 @@ failure of a command.  For example, this is called from
   "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)
+  (idlwave-shell-send-command ".return" (lambda () (idlwave-shell-redisplay 'hide))
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
 
@@ -2632,7 +2551,7 @@ failure of a command.  For example, this is called from
   "Run .SKIP (skip one line, then step)."
   (interactive)
   (idlwave-shell-stop-line-pending)
-  (idlwave-shell-send-command ".skip" '(idlwave-shell-redisplay 'hide)
+  (idlwave-shell-send-command ".skip" (lambda () (idlwave-shell-redisplay 'hide))
 			      (if (idlwave-shell-hide-p 'debug) 'mostly)
 			      nil t))
 
@@ -2657,9 +2576,7 @@ If in the IDL shell buffer, returns `idlwave-shell-pc-frame'."
     (list (idlwave-shell-file-name (buffer-file-name))
           (save-restriction
             (widen)
-            (save-excursion
-              (beginning-of-line)
-              (1+ (count-lines 1 (point))))))))
+            (1+ (count-lines 1 (line-beginning-position)))))))
 
 (defun idlwave-shell-current-module ()
   "Return the name of the module for the current file.
@@ -2689,7 +2606,7 @@ stopped at a breakpoint."
 (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
+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)
@@ -2712,7 +2629,7 @@ 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 (idlwave-xor (not disabled) (eq enable 'enable))
+      (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))
@@ -2739,7 +2656,7 @@ If ENABLE is non-nil, enable them instead."
 (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
+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)))
@@ -2769,7 +2686,7 @@ Assumes that `idlwave-shell-sources-alist' contains an entry for that module."
     (if (or (not source-file)
 	    (not (file-regular-p source-file))
 	    (not (setq buf
-		       (or (idlwave-get-buffer-visiting source-file)
+                       (or (find-buffer-visiting source-file)
 			   (find-file-noselect source-file)))))
 	(progn
 	  (message "The source file for module %s is probably not compiled"
@@ -2842,10 +2759,9 @@ Runs to the last statement and then steps 1 statement.  Use the .out command."
 	 (bp-alist idlwave-shell-bp-alist)
 	 (orig-func (if (> dir 0) '> '<))
 	 (closer-func (if (> dir 0) '< '>))
-	 bp got-bp bp-line cur-line)
+	 bp bp-line cur-line)
     (while (setq bp (pop bp-alist))
       (when (string= file (car (car bp)))
-	(setq got-bp 1)
 	(setq cur-line (nth 1 (car bp)))
 	(if (and
 	     (funcall orig-func cur-line orig-bp-line)
@@ -2862,58 +2778,34 @@ Runs to the last statement and then steps 1 statement.  Use the .out command."
   (interactive "P")
   (idlwave-shell-print arg 'help))
 
-(defmacro idlwave-shell-mouse-examine (help &optional ev)
-  "Create a function for generic examination of expressions."
-  `(lambda (event)
-     "Expansion function for expression examination."
-     (interactive "e")
-     (let* ((drag-track (fboundp 'mouse-drag-track))
-	    (transient-mark-mode t)
-	    (zmacs-regions t)
-	    (tracker (if (featurep 'xemacs)
-			 (if (fboundp
-			      'default-mouse-track-event-is-with-button)
-			     'idlwave-xemacs-hack-mouse-track
-			   'mouse-track)
-		       ;; Emacs 22 no longer completes the drag with
-		       ;; mouse-drag-region, without an additional
-		       ;; event.  mouse-drag-track does so.
-		       (if drag-track 'mouse-drag-track 'mouse-drag-region))))
-       (funcall tracker event)
-       (idlwave-shell-print (if (idlwave-region-active-p) '(4) nil)
-			    ,help ,ev))))
-
-;; Begin terrible hack section -- XEmacs tests for button2 explicitly
-;; on drag events, calling drag-n-drop code if detected.  Ughhh...
-(defun idlwave-default-mouse-track-event-is-with-button (event n)
-  t)
-
-(defun idlwave-xemacs-hack-mouse-track (event)
-  (if (featurep 'xemacs)
-      (let ((oldfunc (symbol-function
-		      'default-mouse-track-event-is-with-button)))
-	(unwind-protect
-	    (progn
-	      (fset 'default-mouse-track-event-is-with-button
-		    'idlwave-default-mouse-track-event-is-with-button)
-	      (mouse-track event))
-	  (fset 'default-mouse-track-event-is-with-button oldfunc)))))
+(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")
-  (funcall (idlwave-shell-mouse-examine nil) event))
+  (idlwave-shell--mouse-examine event nil))
 
 (defun idlwave-shell-mouse-help (event)
   "Print value of variable at the mouse position, with `help'."
   (interactive "e")
-  (funcall (idlwave-shell-mouse-examine 'help) event))
+  (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")
-  (funcall (idlwave-shell-mouse-examine nil event) event))
+  (idlwave-shell--mouse-examine event nil event))
 
 (defmacro idlwave-shell-examine (help)
   "Create a function for key-driven expression examination."
@@ -2974,16 +2866,16 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key."
       (cond
        ((equal arg '(16))
 	(setq expr (read-string "Expression: ")))
-       ((and (or arg (idlwave-region-active-p))
+       ((and (or arg (region-active-p))
 	     (< (- (region-end) (region-beginning)) 2000))
 	(setq beg (region-beginning)
 	      end (region-end)))
        (t
-	(idlwave-with-special-syntax
+	(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 indentifier.
+	     ;; this is at the end of an identifier.
 	     (if (looking-at "\\>")
 		 (backward-sexp))
 	   (backward-sexp))
@@ -3012,9 +2904,9 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key."
 	(move-overlay idlwave-shell-expression-overlay beg end
 		      (current-buffer))
 	(add-hook 'pre-command-hook
-		  'idlwave-shell-delete-expression-overlay))
+		  #'idlwave-shell-delete-expression-overlay))
       (add-hook 'pre-command-hook
-		'idlwave-shell-delete-output-overlay)
+		#'idlwave-shell-delete-output-overlay)
 
       ;; Remove empty or comment-only lines
       (while (string-match "\n[ \t]*\\(;.*\\)?\r*\n" expr)
@@ -3046,7 +2938,7 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key."
 ;; 			   "Print")
 			(idlwave-popup-select
 			 ev
-			 (mapcar 'car idlwave-shell-examine-alist)
+			 (mapcar #'car idlwave-shell-examine-alist)
 			 "Examine with"))
 		      idlwave-shell-examine-alist))))
 	      (setq help (cdr help-cons))
@@ -3074,16 +2966,15 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key."
 	;;(idlwave-shell-recenter-shell-window)
 	(idlwave-shell-send-command
 	 cmd
-	 'idlwave-shell-check-compiled-and-display
+	 #'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)
-
+(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."
@@ -3097,17 +2988,17 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key."
   "Strip the input from command output."
   (when idlwave-shell-completed-command
     (let ((cmd (car idlwave-shell-completed-command)))
-      (if (string-match idlwave-shell-prompt-pattern 
+      (if (string-match idlwave-shell-prompt-pattern
 			idlwave-shell-command-output)
-	  (setq idlwave-shell-command-output 
+	  (setq idlwave-shell-command-output
 		(substring idlwave-shell-command-output (match-end 0))))
-      (when (eq t (compare-strings 
+      (when (eq t (compare-strings
 		   idlwave-shell-command-output 0 (length cmd) cmd 0 nil))
-	(setq idlwave-shell-command-output 
-	      (substring idlwave-shell-command-output 
+	(setq idlwave-shell-command-output
+	      (substring idlwave-shell-command-output
 			 (length cmd)))
       (if (string-match "[ \t]*[\r\n]*" idlwave-shell-command-output)
-	  (setq idlwave-shell-command-output 
+	  (setq idlwave-shell-command-output
 		(substring idlwave-shell-command-output (match-end 0))))))))
 
 (defun idlwave-shell-examine-display ()
@@ -3136,7 +3027,7 @@ from `idlwave-shell-examine-alist' via mini-buffer shortcut key."
 			     end (point-max))))
 	    (setq beg (point-min)
 		  end (point-max)))
-	  
+
 	  (setq str (buffer-substring beg end))
 	  (delete-region (point-min) (point-max))
 	  (insert str)
@@ -3246,7 +3137,7 @@ versions of IDL."
 	 (string-match "\\.\\'" pre)))             ;; structure member
 
        ;; Skip over strings
-       ((and (string-match "\\([\"\']\\)[^\1]*$" pre)
+       ((and (string-match "\\([\"']\\)[^\1]*$" pre)
 	     (string-match (concat "^[^" (match-string 1 pre) "]*"
 				   (match-string 1 pre)) post))
 	(setq start (+ start (match-end 0))))
@@ -3264,7 +3155,7 @@ versions of IDL."
 		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) 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)
@@ -3279,7 +3170,7 @@ versions of IDL."
 (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
+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
@@ -3302,43 +3193,41 @@ size(___,/DIMENSIONS)"
 	 (process-mark (if process (process-mark process)))
 	 output-begin output-end)
     (with-current-buffer buffer
-      (save-excursion 
+      (save-excursion
 	(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)
 			    idlwave-shell-buffer-height-frac)
     (if (and idlwave-shell-output-overlay process-mark)
-	(move-overlay idlwave-shell-output-overlay 
+	(move-overlay idlwave-shell-output-overlay
 		      output-begin output-end buffer))))
 
 (defun idlwave-shell-delete-output-overlay ()
-  (unless (or (eq this-command 'idlwave-shell-mouse-nop)
-	      (eq this-command 'handle-switch-frame))
+  (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)))
+    (remove-hook 'pre-command-hook #'idlwave-shell-delete-output-overlay)))
 
 (defun idlwave-shell-delete-expression-overlay ()
-  (unless (or (eq this-command 'idlwave-shell-mouse-nop)
-	      (eq this-command 'handle-switch-frame))
+  (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)))
+    (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\)\)
+A breakpoint is a cons cell \((file line) . \((index module) data))
 
 The car is the `frame' for the breakpoint:
 file - full path file name.
@@ -3349,18 +3238,17 @@ 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
+data - Data associated with the breakpoint by `idlwave-shell' currently
 contains four items:
 
-count - number of times to execute breakpoint. When count reaches 0
+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
+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.")
 
 ;;;###autoload
@@ -3389,13 +3277,13 @@ If there is a prefix argument, display IDL process."
 		   (idlwave-look-at "\\<end\\>")))
 	    (insert "\nend\n"))
 	(save-buffer 0)))
-  (idlwave-shell-send-command (concat ".run \""
+    (idlwave-shell-send-command (concat ".run \""
 					idlwave-shell-temp-pro-file "\"")
-			      nil
+				nil
 				(if (idlwave-shell-hide-p 'run) 'mostly)
 				nil t)
     (if n
-      (idlwave-display-buffer (idlwave-shell-buffer)
+	(idlwave-display-buffer (idlwave-shell-buffer)
 				nil (idlwave-shell-shell-frame)
 				idlwave-shell-buffer-height-frac))))
 
@@ -3408,15 +3296,14 @@ Does not work for a region with multiline blocks - use
   (idlwave-shell-send-command (buffer-substring beg end))
   (if n
       (idlwave-display-buffer (idlwave-shell-buffer)
-			      nil (idlwave-shell-shell-frame) 
+			      nil (idlwave-shell-shell-frame)
 			      idlwave-shell-buffer-height-frac)))
 
 (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 (idlwave-get-buffer-visiting
-		      idlwave-shell-temp-pro-file)))
+          (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))
@@ -3426,14 +3313,14 @@ Does not work for a region with multiline blocks - use
 	  (delete-file idlwave-shell-temp-rinfo-save-file)
 	(error nil))))
 
-(defun idlwave-display-buffer (buf not-this-window-p &optional frame 
+(defun idlwave-display-buffer (buf not-this-window-p &optional frame
 				   buffer-height-frac)
   "Display a buffer in a requested (optional) FRAME.
 Resize to no more than BUFFER-HEIGHT-FRAC of the frame buffer if set."
   (save-selected-window
     (let ((win (display-buffer buf not-this-window-p frame)))
       (if buffer-height-frac
-	  (set-window-text-height win (round (* (frame-height frame) 
+	  (set-window-text-height win (round (* (frame-height frame)
 						buffer-height-frac))))
       win)))
 
@@ -3449,17 +3336,17 @@ Resize to no more than BUFFER-HEIGHT-FRAC of the frame buffer if set."
 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)))
+			      (lambda ()
+				(idlwave-shell-filter-bp 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."
+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)))
@@ -3524,12 +3411,12 @@ the breakpoint overlays."
 		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 
+	      (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)
@@ -3539,9 +3426,10 @@ the breakpoint overlays."
 			      count nil condition disabled))))))
       (setq idlwave-shell-bp-alist (cdr idlwave-shell-bp-alist))
       ;; Update breakpoint data
-      (if (eq bp-re bp-re54)
-	  (mapc 'idlwave-shell-update-bp old-bp-alist)
-	(mapc 'idlwave-shell-update-bp-command-only old-bp-alist))))
+      (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
@@ -3601,8 +3489,8 @@ 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))
+   (lambda ()
+     (idlwave-shell-filter-bp no-show)
      (setq idlwave-shell-old-bp idlwave-shell-bp-alist))
    'hide)
 
@@ -3632,9 +3520,9 @@ specified.  If NO-SHOW is non-nil, don't do any updating."
 	     (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))))
+     (lambda ()
+	(if (idlwave-shell-set-bp-check bp)
+	    (idlwave-shell-set-bp-adjust bp no-show)))
      ;; hide output?
      (idlwave-shell-hide-p 'breakpoint)
      'preempt t)))
@@ -3643,11 +3531,11 @@ specified.  If NO-SHOW is non-nil, don't do any updating."
   "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)))
+   (lambda ()
+     (idlwave-shell-filter-bp 'no-show)
+     (idlwave-shell-new-bp bp)
+     (unless no-show
+       (idlwave-shell-update-bp-overlays)))
    'hide
    'preempt))
 
@@ -3672,11 +3560,11 @@ Returns nil if frame not found."
 
 (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 than
+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))
+  (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))))
@@ -3701,9 +3589,8 @@ considered the new breakpoint if the file name of frame matches."
 (defvar idlwave-shell-bp-glyph)
 
 (defvar idlwave-shell-debug-line-map (make-sparse-keymap))
-(define-key idlwave-shell-debug-line-map
-  (if (featurep 'xemacs) [button3] [mouse-3])
-  'idlwave-shell-mouse-active-bp)
+(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.
@@ -3713,24 +3600,24 @@ Existing overlays are recycled, in order to minimize consumption."
 	  (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 win)
+	  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)))
-	      (add-to-list 'old-buffers (overlay-buffer ov))
+	      (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))
+		(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 (progn (end-of-line 1) (point)))
+          (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))
@@ -3761,7 +3648,7 @@ Existing overlays are recycled, in order to minimize consumption."
 			     (if help-list
 				 (concat
 				  " - "
-				  (mapconcat 'identity help-list ", ")))
+				  (mapconcat #'identity help-list ", ")))
 			     (if (and (not count) (not condition))
 				 " (use mouse-3 for breakpoint actions)")))
 		 (full-type (if disabled
@@ -3802,8 +3689,8 @@ Existing overlays are recycled, in order to minimize consumption."
 (defun idlwave-shell-make-new-bp-overlay (&optional type disabled)
   "Make a new overlay for highlighting breakpoints.
 
-This stuff is strongly dependant upon the version of Emacs.  If TYPE
-is passed, make an overlay of that type ('bp or 'bp-cond, currently
+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))
@@ -3812,60 +3699,33 @@ only for glyphs)."
 	(face (if disabled
 		  idlwave-shell-disabled-breakpoint-face
 		idlwave-shell-breakpoint-face)))
-    (if (featurep 'xemacs)
-	;; This is XEmacs
-	(progn
-	  (when idlwave-shell-breakpoint-popup-menu
-	    (set-extent-property ov 'mouse-face 'highlight)
-	    (set-extent-property ov 'keymap idlwave-shell-debug-line-map))
-
-	  (cond
-	   ;; tty's cannot display glyphs
-	   ((eq (console-type) 'tty)
-	    (set-extent-property ov 'face face))
-
-	   ;; use the glyph
-	   (use-glyph
-	    (let ((glyph (cdr (assq type idlwave-shell-bp-glyph))))
-	      (if disabled (setq glyph (car glyph)) (setq glyph (nth 1 glyph)))
-	      (set-extent-property ov 'begin-glyph glyph)
-	      (set-extent-property ov 'begin-glyph-layout 'outside-margin)))
-
-	   ;; use the face
-	   (idlwave-shell-mark-breakpoints
-	    (set-extent-property ov 'face face))
-
-	   ;; no marking
-	   (t nil))
-	  (set-extent-priority ov -1))  ; make stop line face prevail
-      ;; This is Emacs
-      (when idlwave-shell-breakpoint-popup-menu
-	(overlay-put ov 'mouse-face 'highlight)
-	(overlay-put ov 'keymap idlwave-shell-debug-line-map))
-      (cond
-       ((display-graphic-p)
-	(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)))
+    (when idlwave-shell-breakpoint-popup-menu
+      (overlay-put ov 'mouse-face 'highlight)
+      (overlay-put ov 'keymap idlwave-shell-debug-line-map))
+    (cond
+     ((display-graphic-p)
+      (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)
@@ -3916,9 +3776,9 @@ only for glyphs)."
 	 (t
 	  (message "Unimplemented: %s" select))))))
 
-(defun idlwave-shell-edit-default-command-line (arg)
+(defun idlwave-shell-edit-default-command-line ()
   "Edit the current execute command."
-  (interactive "P")
+  (interactive)
   (setq idlwave-shell-command-line-to-execute
 	(read-string "IDL> " idlwave-shell-command-line-to-execute)))
 
@@ -3931,13 +3791,13 @@ Also with prefix arg, ask for the command.  You can also use the command
    ((equal arg '(16))
     (setq idlwave-shell-command-line-to-execute nil))
    ((or (null idlwave-shell-command-line-to-execute) (equal arg '(4)))
-    (idlwave-shell-edit-default-command-line nil)))
+    (idlwave-shell-edit-default-command-line)))
   ;;(idlwave-shell-reset 'hidden)
-  (idlwave-shell-send-command 
+  (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)))
+   (lambda () (idlwave-shell-redisplay 'hide))))
 
 ;;;###autoload
 (defun idlwave-shell-save-and-run ()
@@ -3964,7 +3824,7 @@ one of the save-and-.. commands."
   (interactive)
   (idlwave-shell-save-and-action 'batch))
 
-(defvar idlwave-shell-master-file nil 
+(defvar idlwave-shell-master-file nil
   "File local variable to compile instead of this file.
 Useful for e.g. top level routines which @include others.")
 (make-variable-buffer-local 'idlwave-shell-master-file)
@@ -3984,15 +3844,15 @@ file-local-variable idlwave-shell-master-file is set, act on it instead."
   (setq overlay-arrow-string nil)
   (let (buf)
     (cond
-     ((eq major-mode 'idlwave-mode)
+     ((derived-mode-p 'idlwave-mode)
       (save-buffer)
-      (setq idlwave-shell-last-save-and-action-file 
-	    (if idlwave-shell-master-file 
-		(expand-file-name idlwave-shell-master-file 
+      (setq idlwave-shell-last-save-and-action-file
+	    (if idlwave-shell-master-file
+		(expand-file-name idlwave-shell-master-file
 				  (file-name-directory (buffer-file-name)))
 	      (buffer-file-name))))
      (idlwave-shell-last-save-and-action-file
-      (if (setq buf (idlwave-get-buffer-visiting
+      (if (setq buf (find-buffer-visiting
 		     idlwave-shell-last-save-and-action-file))
 	  (with-current-buffer buf
 	    (save-buffer))))
@@ -4008,8 +3868,10 @@ file-local-variable idlwave-shell-master-file is set, act on it instead."
 		 "\""
 		 idlwave-shell-last-save-and-action-file
 		 "\"")
-	 `(idlwave-shell-maybe-update-routine-info nil
-	   ,idlwave-shell-last-save-and-action-file)
+	 (let ((lsaf idlwave-shell-last-save-and-action-file))
+	  (lambda ()
+	    (idlwave-shell-maybe-update-routine-info
+	     nil lsaf)))
 	 (if (idlwave-shell-hide-p 'run) 'mostly) nil t)
 	(idlwave-shell-bp-query))
     (let ((msg (format "No such file %s"
@@ -4017,13 +3879,13 @@ file-local-variable idlwave-shell-master-file is set, act on it instead."
       (setq idlwave-shell-last-save-and-action-file nil)
       (error msg))))
 
-(defun idlwave-shell-set-master-file () 
+(defun idlwave-shell-set-master-file ()
   "Set the master file locally for this file"
   (interactive)
   (if (eq major-mode 'idlwave-mode)
       (let* ((master (read-file-name "Select IDL Master file: " nil nil t))
-	     (master-rel (file-relative-name 
-			  master 
+	     (master-rel (file-relative-name
+			  master
 			  (file-name-directory (buffer-file-name)))))
 	(when (file-regular-p master)
 	  (setq idlwave-shell-master-file master-rel)
@@ -4049,22 +3911,22 @@ Elements of the alist have the form:
 
 (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."
+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)
+       (lambda () (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)
+    (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)))
+				(match-beginning 1) (match-end 1)))
     (if old
 	(setcdr old (list (idlwave-shell-file-name filename) filename))
       (setq idlwave-shell-sources-alist
@@ -4078,7 +3940,7 @@ Query as a function if TYPE set to something beside 'pro."
 Queries IDL using the string in `idlwave-shell-sources-query'."
   (interactive)
   (idlwave-shell-send-command idlwave-shell-sources-query
-			      'idlwave-shell-sources-filter
+			      #'idlwave-shell-sources-filter
 			      'hide))
 
 (defun idlwave-shell-sources-filter ()
@@ -4102,8 +3964,7 @@ of the form:
                   (append
                    ;; compiled procedures
                    (progn
-                     (beginning-of-line)
-                     (narrow-to-region cpro (point))
+                     (narrow-to-region cpro (line-beginning-position))
                      (goto-char (point-min))
                      (idlwave-shell-sources-grep))
                    ;; compiled functions
@@ -4138,10 +3999,10 @@ of the form:
   (interactive)
   (idlwave-shell-send-command
    idlwave-shell-bp-query
-   '(progn
+   (lambda ()
       (idlwave-shell-filter-bp)
-      (mapcar (lambda (x) (idlwave-shell-clear-bp x 'no-query))
-	      idlwave-shell-bp-alist)
+      (mapc (lambda (x) (idlwave-shell-clear-bp x 'no-query))
+	    idlwave-shell-bp-alist)
       (idlwave-shell-bp-query))
    'hide))
 
@@ -4189,7 +4050,7 @@ of the form:
 (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 (eq major-mode 'idlwave-shell-mode)
+  (let ((def-dir (if (derived-mode-p 'idlwave-shell-mode)
 		     default-directory
 		   idlwave-shell-default-directory)))
     (if idlwave-shell-use-truename
@@ -4198,89 +4059,47 @@ Otherwise, just expand the file name."
 
 ;; Keybindings ------------------------------------------------------------
 
-(defvar idlwave-shell-mode-map (copy-keymap comint-mode-map)
-  "Keymap for `idlwave-mode'.")
-(defvar idlwave-shell-electric-debug-mode-map (make-sparse-keymap))
+
+(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))
-(fset 'idlwave-shell-mode-prefix-map idlwave-shell-mode-prefix-map)
+(defalias 'idlwave-shell-mode-prefix-map idlwave-shell-mode-prefix-map)
 (defvar idlwave-mode-prefix-map (make-sparse-keymap))
-(fset 'idlwave-mode-prefix-map idlwave-mode-prefix-map)
+(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-shell-mode-map "\M-?" 'comint-dynamic-list-completions)
-;(define-key idlwave-shell-mode-map "\t" 'comint-dynamic-complete)
-
-(define-key idlwave-shell-mode-map "\C-w"     'comint-kill-region)
-(define-key idlwave-shell-mode-map "\C-a"     'comint-bol-or-process-mark)
-(define-key idlwave-shell-mode-map "\t"       'idlwave-shell-complete)
-(define-key idlwave-shell-mode-map "\M-\t"    'idlwave-shell-complete)
-(define-key idlwave-shell-mode-map "\C-c\C-s" 'idlwave-shell)
-(define-key idlwave-shell-mode-map "\C-c?"    'idlwave-routine-info)
-(define-key idlwave-shell-mode-map "\C-g"     'idlwave-keyboard-quit)
-(define-key idlwave-shell-mode-map "\M-?"     'idlwave-context-help)
-(define-key idlwave-shell-mode-map [(control meta ?\?)]
-  'idlwave-help-with-topic)
-(define-key idlwave-shell-mode-map "\C-c\C-i" 'idlwave-update-routine-info)
-(define-key idlwave-shell-mode-map "\C-c\C-y" 'idlwave-shell-char-mode-loop)
-(define-key idlwave-shell-mode-map "\C-c\C-x" 'idlwave-shell-send-char)
-(define-key idlwave-shell-mode-map "\C-c="    'idlwave-resolve)
-(define-key idlwave-shell-mode-map "\C-c\C-v" 'idlwave-find-module)
-(define-key idlwave-shell-mode-map "\C-c\C-k" 'idlwave-kill-autoloaded-buffers)
-(define-key idlwave-shell-mode-map idlwave-shell-prefix-key
-  'idlwave-shell-debug-map)
-(define-key idlwave-shell-mode-map [(up)]  'idlwave-shell-up-or-history)
-(define-key idlwave-shell-mode-map [(down)] 'idlwave-shell-down-or-history)
-
-(define-key idlwave-shell-mode-map [(shift up)]  
-  'idlwave-shell-noblock-up-or-history)
-(define-key idlwave-shell-mode-map [(shift down)] 
-  'idlwave-shell-noblock-down-or-history)
-
-(define-key idlwave-shell-mode-map "\C-c " 'idlwave-shell-accumulate)
-(define-key idlwave-shell-mode-map "\M-\r" 
-  (lambda () (interactive (idlwave-split-line 'noindent))))
-
-
-(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
- (if (featurep 'xemacs)
-     [(shift button2)]
-   [(shift down-mouse-2)])
- 'idlwave-shell-mouse-print)
-(idlwave-shell-define-key-both
- (if (featurep 'xemacs)
-     [(control meta button2)]
-   [(control meta down-mouse-2)])
-  'idlwave-shell-mouse-help)
-(idlwave-shell-define-key-both
- (if (featurep 'xemacs)
-     [(control shift button2)]
-   [(control shift down-mouse-2)])
- 'idlwave-shell-examine-select)
-;; Add this one from the idlwave-mode-map
-(define-key idlwave-shell-mode-map
-  (if (featurep 'xemacs)
-      [(shift button3)]
-    [(shift mouse-3)])
-  'idlwave-mouse-context-help)
-
-;; For Emacs, we need to turn off the button release events.
-(defun idlwave-shell-mouse-nop (event)
-  (interactive "e"))
-(unless (featurep 'xemacs)
-  (idlwave-shell-define-key-both
-   [(shift mouse-2)] 'idlwave-shell-mouse-nop)
-  (idlwave-shell-define-key-both
-   [(shift control mouse-2)] 'idlwave-shell-mouse-nop)
-  (idlwave-shell-define-key-both
-   [(control meta mouse-2)] 'idlwave-shell-mouse-nop))
+(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.
@@ -4325,15 +4144,11 @@ Otherwise, just expand the file name."
 	  ([(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)
+	  ([(        ?\[)]  ?\[  idlwave-shell-goto-previous-bp t t)
+	  ([(        ?\])]  ?\]  idlwave-shell-goto-next-bp t t)
 	  ([(control ?f)]   ?f   idlwave-shell-window)))
-       (mod (cond ((and idlwave-shell-debug-modifiers
-			(listp idlwave-shell-debug-modifiers)
-			(not (equal '() idlwave-shell-debug-modifiers)))
-		   idlwave-shell-debug-modifiers)
-		  (idlwave-shell-activate-alt-keybindings
-		   '(alt))))
+       (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)
@@ -4364,29 +4179,10 @@ Otherwise, just expand the file name."
 	(define-key idlwave-shell-electric-debug-mode-map (char-to-string c2)
 	  cmd))))
 
-;; A few extras in the electric debug map
-(define-key idlwave-shell-electric-debug-mode-map " " 'idlwave-shell-step)
-(define-key idlwave-shell-electric-debug-mode-map "+" 'idlwave-shell-stack-up)
-(define-key idlwave-shell-electric-debug-mode-map "=" 'idlwave-shell-stack-up)
-(define-key idlwave-shell-electric-debug-mode-map "-"
-  'idlwave-shell-stack-down)
-(define-key idlwave-shell-electric-debug-mode-map "_"
-  'idlwave-shell-stack-down)
-(define-key idlwave-shell-electric-debug-mode-map "e"
-  '(lambda () (interactive) (idlwave-shell-print '(16))))
-(define-key idlwave-shell-electric-debug-mode-map "q" 'idlwave-shell-retall)
-(define-key idlwave-shell-electric-debug-mode-map "t"
-  '(lambda () (interactive) (idlwave-shell-send-command "help,/TRACE")))
-(define-key idlwave-shell-electric-debug-mode-map [(control ??)]
-  'idlwave-shell-electric-debug-help)
-(define-key idlwave-shell-electric-debug-mode-map "x"
-  '(lambda (arg) (interactive "P")
-     (idlwave-shell-print arg nil nil t)))
-
 
 ; Enter the prefix map in two places.
-(fset 'idlwave-debug-map       idlwave-mode-prefix-map)
-(fset 'idlwave-shell-debug-map idlwave-shell-mode-prefix-map)
+(defalias 'idlwave-debug-map       idlwave-mode-prefix-map)
+(defalias 'idlwave-shell-debug-map idlwave-shell-mode-prefix-map)
 
 ;; The Electric Debug Minor Mode --------------------------------------------
 
@@ -4403,54 +4199,40 @@ Otherwise, just expand the file name."
     (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-read-only nil)
 
 (define-minor-mode idlwave-shell-electric-debug-mode
-  "Toggle Electric Debug mode.
-With no argument, this command toggles the mode.
-Non-null prefix argument turns on the mode.
-Null prefix argument turns off the mode.
-
-When Electric Debug mode is enabled, the many debugging commands are
-available as single key sequences."
-nil
-" *Debugging*"
-idlwave-shell-electric-debug-mode-map)
-
-(add-hook
- 'idlwave-shell-electric-debug-mode-on-hook
- (lambda ()
-   (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))))
-
-(add-hook
- 'idlwave-shell-electric-debug-mode-off-hook
- (lambda ()
-   ;; 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)
-     )))
-
-;; easy-mmode defines electric-debug-mode for us, so we need to advise it.
-(defadvice idlwave-shell-electric-debug-mode (after print-enter activate)
-  "Print out an entrance message."
-  (when 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"))
-  (force-mode-line-update))
+   (t
+    ;; Return to previous read-only state
+    (setq buffer-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)
@@ -4459,7 +4241,7 @@ idlwave-shell-electric-debug-mode-map)
       (while (setq buf (pop buffers))
 	(when (buffer-live-p buf)
 	  (set-buffer buf)
-	  (when (and (eq major-mode 'idlwave-mode)
+	  (when (and (derived-mode-p 'idlwave-mode)
 		     buffer-file-name
 		     idlwave-shell-electric-debug-mode)
 	    (idlwave-shell-electric-debug-mode 0))))))
@@ -4484,51 +4266,51 @@ idlwave-shell-electric-debug-mode-map)
     ["Electric Debug Mode"
      idlwave-shell-electric-debug-mode
      :style toggle :selected idlwave-shell-electric-debug-mode
-     :included (eq major-mode 'idlwave-mode) :keys "C-c C-d C-v"]
+     :included (derived-mode-p 'idlwave-mode) :keys "C-c C-d C-v"]
     "--"
     ("Compile & Run"
      ["Save and .RUN" idlwave-shell-save-and-run
-      (or (eq major-mode 'idlwave-mode)
+      (or (derived-mode-p 'idlwave-mode)
 	  idlwave-shell-last-save-and-action-file)]
      ["Save and .COMPILE" idlwave-shell-save-and-compile
-      (or (eq major-mode 'idlwave-mode)
+      (or (derived-mode-p 'idlwave-mode)
 	  idlwave-shell-last-save-and-action-file)]
      ["Save and @Batch" idlwave-shell-save-and-batch
-      (or (eq major-mode 'idlwave-mode)
+      (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
-      (eq major-mode 'idlwave-mode)]
+      (derived-mode-p 'idlwave-mode)]
      ["Evaluate Region" idlwave-shell-evaluate-region
-      (eq major-mode 'idlwave-mode)]
+      (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 (eq major-mode 'idlwave-mode)]
+      :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 (eq major-mode 'idlwave-mode)]
+       :active (derived-mode-p 'idlwave-mode)]
       ["Set Condition Breakpoint"
        (idlwave-shell-break-here '(4))
-       :active (eq major-mode 'idlwave-mode)])
+       :active (derived-mode-p 'idlwave-mode)])
      ["Break in Module" idlwave-shell-break-in
-      :keys "C-c C-d C-i" :active (eq major-mode 'idlwave-mode)]
+      :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 (eq major-mode 'idlwave-mode)]
+      :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 (eq major-mode 'idlwave-mode)]
+      :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 (eq major-mode 'idlwave-mode)]
+      :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"
@@ -4540,7 +4322,7 @@ idlwave-shell-electric-debug-mode-map)
      ["... 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 (eq major-mode 'idlwave-mode)])
+      :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]
@@ -4607,31 +4389,22 @@ idlwave-shell-electric-debug-mode-map)
     ["Update Working Dir" idlwave-shell-resync-dirs t]
     ["Save Path Info"
      (idlwave-shell-send-command idlwave-shell-path-query
-				 'idlwave-shell-get-path-info
+				 #'idlwave-shell-get-path-info
 				 'hide)
      t]
-    ["Set Master File" (idlwave-shell-set-master-file) 
+    ["Set Master File" (idlwave-shell-set-master-file)
      :active (eq major-mode 'idlwave-mode)]
     ["Reset IDL" idlwave-shell-reset t]
     "--"
     ["Toggle Toolbar" idlwave-shell-toggle-toolbar t]
     ["Exit IDL" idlwave-shell-quit t]))
 
-(if (or (featurep 'easymenu) (load "easymenu" t))
-    (progn
-      (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)
-      (save-current-buffer
-	(dolist (buf (buffer-list))
-          (set-buffer buf)
-          (if (eq major-mode 'idlwave-mode)
-              (progn
-                (easy-menu-remove idlwave-mode-debug-menu)
-                (easy-menu-add idlwave-mode-debug-menu)))))))
+(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 -------------------------------------------------------
 
@@ -4773,16 +4546,7 @@ static char * file[] = {
 \"              \"};"))) im-cons im)
 
   (while (setq im-cons (pop image-alist))
-    (setq im (cond ((and (featurep 'xemacs)
-			 (featurep 'xpm))
-		    (list
-		     (let ((data (cdr im-cons)))
-		       (string-match "#FFFF00000000" data)
-		       (setq data (replace-match "#8F8F8F8F8F8F" t t data))
-		       (make-glyph data))
-		     (make-glyph (cdr im-cons))))
-		   ((and (not (featurep 'xemacs))
-			 (fboundp 'image-type-available-p)
+    (setq im (cond ((and (fboundp 'image-type-available-p)
 			 (image-type-available-p 'xpm))
 		    (list 'image :type 'xpm :data (cdr im-cons)
 			  :ascent 'center))
@@ -4804,7 +4568,6 @@ static char * file[] = {
   (idlwave-toolbar-toggle))
 
 (if idlwave-shell-use-toolbar
-    (add-hook 'idlwave-shell-mode-hook 'idlwave-toolbar-add-everywhere))
+    (add-hook 'idlwave-shell-mode-hook #'idlwave-toolbar-add-everywhere))
 
-;; arch-tag: 20c2e8ce-0709-41d8-a5b6-bb039148440a
 ;;; idlw-shell.el ends here
diff --git a/idlw-toolbar.el b/idlw-toolbar.el
index eda5dc5f8f..51732b4cf1 100644
--- a/idlw-toolbar.el
+++ b/idlw-toolbar.el
@@ -1,11 +1,11 @@
-;;; idlw-toolbar.el --- a debugging toolbar for IDLWAVE
-;; Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 
-;;               2009, 2010  Free Software Foundation
+;;; idlw-toolbar.el --- a debugging toolbar for IDLWAVE  -*- lexical-binding: t; -*-
+;; Copyright (c) 1999-2024  Free Software Foundation
 ;; Author: Carsten Dominik <dominik _AT_ astro.uva.nl>
 ;; Maintainer: J.D. Smith <jdtsmith _AT_ gmail.com>
 ;; Version: VERSIONTAG
 ;; Date: $Date: 2006/08/22 05:15:26 $
 ;; Keywords: processes
+;; Package: idlwave
 
 ;; This file is part of GNU Emacs.
 
@@ -20,39 +20,31 @@
 ;; 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 <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
-;; This file implements a debugging toolbar for IDLWAVE.  It requires
-;; Emacs or XEmacs with toolbar and xpm support.
+;; This file implements a debugging toolbar for IDLWAVE.
+;; It requires toolbar and xpm support.
 
 ;; New versions of IDLWAVE, documentation, and more information
 ;; available from:
-;;                 http://github.com/jdtsmith/idlwave
+;;                 https://github.com/jdtsmith/idlwave
 
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
-
 (defun idlwave-toolbar-make-button (image)
-  (if (featurep 'xemacs)
-      (toolbar-make-button-list image)
-    (list 'image :type 'xpm :data image)))
+  (list 'image :type 'xpm :data image))
 
 (defvar idlwave-toolbar)
 (defvar default-toolbar)
 (defvar idlwave-toolbar-is-possible)
 
-(if (not (or (and (featurep 'xemacs)                ; This is XEmacs
-		  (featurep 'xpm)                   ; need xpm
-		  (featurep 'toolbar))              ; ... and the toolbar
-	     (and (not (featurep 'xemacs))          ; This is Emacs
-		  (boundp 'tool-bar-button-margin)   ; need toolbar
-		  (fboundp 'image-type-available-p) ; need image stuff
-		  (image-type-available-p 'xpm))    ; need xpm
-	     ))
+(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
@@ -363,7 +355,7 @@ static char * file[] = {
 \"                            \",
 \"                            \",
 \"                            \"};")
-  "The edit-cmd icon")
+  "The edit-cmd icon.")
 
 (defvar idlwave-toolbar-run-icon
   (idlwave-toolbar-make-button
@@ -439,7 +431,7 @@ static char * file[] = {
 \"                            \",
 \"                            \",
 \"                            \"};")
-  "The Cont icon.")	  
+  "The Cont icon.")
 
 (defvar idlwave-toolbar-to-here-icon
   (idlwave-toolbar-make-button
@@ -807,7 +799,7 @@ static char * file[] = {
      "Goto Next Error"]
     [idlwave-toolbar-stop-at-icon
      idlwave-shell-break-here
-     (eq major-mode 'idlwave-mode)
+     (derived-mode-p 'idlwave-mode)
      "Break"
      "Set Breakpoint at selected position"]
     [idlwave-toolbar-clear-at-icon
@@ -822,7 +814,7 @@ static char * file[] = {
      "Clear all Breakpoints"]
     [idlwave-toolbar-stop-beginning-icon
      idlwave-shell-break-this-module
-     (eq major-mode 'idlwave-mode)
+     (derived-mode-p 'idlwave-mode)
      "BreakRoutine"
      "Stop at beginning of enclosing Routine"]
     [idlwave-toolbar-stop-in-icon
@@ -847,7 +839,7 @@ static char * file[] = {
      "Continue Current Program"]
     [idlwave-toolbar-to-here-icon
      idlwave-shell-to-here
-     (eq major-mode 'idlwave-mode)
+     (derived-mode-p 'idlwave-mode)
      "Here"
      "Continue to Here (cursor position)"]
     [idlwave-toolbar-step-over-icon
@@ -887,32 +879,19 @@ static char * file[] = {
      "Reset IDL (RETALL & CLOSE,/ALL and more)"]
     [idlwave-toolbar-electric-debug-icon
      idlwave-shell-electric-debug-mode
-     (eq major-mode 'idlwave-mode)
+     (derived-mode-p 'idlwave-mode)
      "Electric"
      "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)
+	  #'idlwave-toolbar-remove-everywhere)
 );; End can define toolbar
 
-(defun idlwave-toolbar-add ()
-  "Add the IDLWAVE toolbar if appropriate."
-  (if (and (featurep 'xemacs)    ; This is a noop on Emacs
-	   (boundp 'idlwave-toolbar-is-possible)
-	   (or (eq major-mode 'idlwave-mode)
-	       (eq major-mode 'idlwave-shell-mode)))
-      (set-specifier default-toolbar (cons (current-buffer)
-					   idlwave-toolbar))))
-
-(defun idlwave-toolbar-remove ()
-  "Add the IDLWAVE toolbar if appropriate."
-  (if (and (featurep 'xemacs)    ; This is a noop on Emacs
-	   (boundp 'idlwave-toolbar-is-possible)
-	   (or (eq major-mode 'idlwave-mode)
-	       (eq major-mode 'idlwave-shell-mode)))
-      (remove-specifier default-toolbar (current-buffer))))
+(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)
@@ -921,58 +900,41 @@ static char * file[] = {
   "Add the toolbar in all appropriate buffers."
   (when (boundp 'idlwave-toolbar-is-possible)
 
-    ;; First make sure new buffers will get the toolbar
-    (add-hook 'idlwave-mode-hook 'idlwave-toolbar-add)
     ;; Then add it to all existing buffers
-    (if (featurep 'xemacs)
-	;; For XEmacs, map over all buffers to add toolbar
-	(save-excursion
-	  (mapcar (lambda (buf)
-		    (set-buffer buf)
-		    (idlwave-toolbar-add))
-		  (buffer-list)))
-      ;; 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))
-		     (name (aref x 3))
-		     (help (aref x 4))
-		     (key (vector 'tool-bar func))
-		     (def (list 'menu-item
-				name
-				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)))
+    ;; 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))
+		   (name (aref x 3))
+		   (help (aref x 4))
+		   (key (vector 'tool-bar func))
+		   (def (list 'menu-item
+			      name
+			      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
-    (remove-hook 'idlwave-mode-hook 'idlwave-toolbar-add)
     ;; Then remove it in all existing buffers.
-    (if (featurep 'xemacs)
-	;; For XEmacs, map over all buffers to remove toolbar
-	(save-excursion
-	  (mapcar (lambda (buf)
-		    (set-buffer buf)
-		    (idlwave-toolbar-remove))
-		  (buffer-list)))
-      ;; 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))
+    ;; 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)
@@ -980,14 +942,10 @@ static char * file[] = {
   (if idlwave-toolbar-visible
       (or force-on (idlwave-toolbar-remove-everywhere))
     (idlwave-toolbar-add-everywhere))
-  ;; Now make sure this
-  (if (featurep 'xemacs)
-      nil ; no action necessary, toolbar gets updated automatically
-    ;; On Emacs, redraw the frame to make sure the Toolbar is updated.
-    (redraw-frame (selected-frame))))
+  ;; On Emacs, redraw the frame to make sure the Toolbar is updated.
+  (redraw-frame))
 
 (provide 'idlw-toolbar)
 (provide 'idlwave-toolbar)
 
-;; arch-tag: ec9a3717-c44c-4716-9bda-cdacbe5ddb62
 ;;; idlw-toolbar.el ends here
diff --git a/idlw-variables.el b/idlw-variables.el
index 6f6114b27f..449dde7eaf 100644
--- a/idlw-variables.el
+++ b/idlw-variables.el
@@ -1,9 +1,9 @@
-;; IDLWAVE variables, customizations, and constants
+;; IDLWAVE variables, customizations, and constants  -*- lexical-binding: t; -*-
 (defgroup idlwave nil
   "Major mode for editing IDL .pro files."
   :tag "IDLWAVE"
-  :link '(url-link :tag "Home Page" 
-		   "http://github.com/jdtsmith/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")
@@ -13,41 +13,37 @@
 
 
 ;;----------------------------------------------------
-;; Indentation behavior
+;;;; 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.
+  "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.
+  "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.
+  "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.
+  "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.
+  "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
@@ -57,11 +53,10 @@ 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.
+  "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:
@@ -81,104 +76,92 @@ would yield:
      ], $
      c, d $
      )))"
-  :group 'idlwave-code-formatting
   :type 'boolean)
 
 (defcustom idlwave-indent-parens-nested nil
-  "*Non-nil means, indent continuation lines with parens by nesting
+  "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
+  "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
+  "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
+  "If non-nil then use last match on line for `idlwave-hang-indent-regexp'."
   :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
+  "If non-nil then auto fill will only operate on comment lines."
   :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 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 `+'.
+  "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
+  "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)
+  :type 'regexp)
 
 (defcustom idlwave-begin-line-comment nil
-  "*A comment anchored at the beginning of line.
+  "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))
+		 regexp))
 
 (defcustom idlwave-code-comment ";;[^;]"
-  "*A comment that starts with this regular expression on a line by
+  "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
+;;;; 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.
+  "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.
+  "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
@@ -191,34 +174,31 @@ 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.
+  "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
+`current' Scan only the current buffer, but no other buffers."
   :type '(choice
 	  (const :tag "No buffer" nil)
 	  (const :tag "All buffers" t)
-	  (const :tag "Current buffer only" 'current)))
+	  (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.
+  "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.
+  "Controls under what circumstances routine info is updated automatically.
 Possible values:
 nil       Never
 t         All available
@@ -227,7 +207,6 @@ t         All available
            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)
@@ -236,69 +215,65 @@ t         All available
 	       (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.
+  "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 MacOS (OS9).  Not needed under UNIX.
+  "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 Windows and MacOS
-\(pre-OSX), the IDLWAVE shell does not work.  In this case, this
+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
-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'."
-  :group 'idlwave-routine-info
+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'."
   :type '(repeat (directory)))
 
 (defcustom idlwave-system-directory ""
-  "The IDL system directory for Windows and MacOS.  Not needed under
+  "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 
-  (convert-standard-filename "~/.idlwave")
-  "*Directory for configuration files and user-library catalog."
-  :group 'idlwave-routine-info
+(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
   :type 'file)
 
 (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' 
+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.  
+  "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)
 
+;;;; Completion
 (defgroup idlwave-completion nil
   "Completion options for IDLWAVE mode."
   :prefix "idlwave"
@@ -322,7 +297,7 @@ used to force a write."
 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. 
+methods.
 This alist should therefore have entries for `routine' (normal
 functions and procedures, i.e. non-methods), `keyword', `class', and
 `method'.  Plausible values are
@@ -350,50 +325,45 @@ 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'.
+  "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.
+  "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.
+  "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.
+  "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
+  :group 'idlwave-routine-info          ;FIXME: Is this the right group?
   :type 'boolean)
 
 (defcustom idlwave-keyword-class-inheritance '("^[gs]etproperty$" "^init$")
@@ -403,16 +373,16 @@ 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
+  :group 'idlwave-routine-info          ;FIXME: Is this the right group?
   :type '(repeat (regexp :tag "Match method:")))
-  
+
 (defcustom idlwave-complete-structure-tags t
   "Whether to complete structure tags in source and shell."
-  :group 'idlwave-routine-info
+  :group 'idlwave-routine-info          ;FIXME: Is this the right group?
   :type 'boolean)
 
 (defcustom idlwave-completion-show-classes 1
-  "*Number of classes to show when completing object methods and keywords.
+  "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:
@@ -420,21 +390,14 @@ 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 completion 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."
-  :group 'idlwave-completion
+indicate the maximum number of classes to display."
   :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.
+  "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)
@@ -474,11 +437,10 @@ should contain at least two elements: (method-default . VALUE) and
 specify if the class should be found during method and keyword
 completion, respectively.
 
-The alist may have additional entries specifying exceptions from the 
+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    "))
@@ -491,17 +453,17 @@ method, add an entry (\"INIT\" . t).  The method name must be ALL-CAPS."
 		 (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 `->'.
+  "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 
+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]'
+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
@@ -512,72 +474,64 @@ 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.
+  "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
+  "Non-nil means, resize the Routine-info *Help* window to fit the content."
   :type 'boolean)
 
 (defcustom idlwave-keyword-completion-adds-equal t
-  "*Non-nil means, completion automatically adds `=' after completed keywords."
-  :group 'idlwave-completion
+  "Non-nil means, completion automatically adds `=' after completed keywords."
   :type 'boolean)
 
 (defcustom idlwave-function-completion-adds-paren t
-  "*Non-nil means, completion automatically adds `(' after completed function.
+  "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.
+  "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)
 
 ;;----------------------------------------------------
-;; Abbrev and action
+;;;; Abbrev and action
 (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.
+  "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
+  "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'.
+  "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'.
@@ -588,62 +542,54 @@ Keys are bound and made into actions calling `idlwave-surround' with
 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
+  "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)
-	  (const :tag "Keep space near `='" 'keep)))
+	  (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
+  "Non-nil means point blinks to block beginning for `idlwave-show-begin'."
   :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
+  "Non-nil means expand generic END to ENDIF/ENDELSE/ENDWHILE etc."
   :type 'boolean)
 
 (defcustom idlwave-reindent-end t
-  "*Non-nil means re-indent line after END was typed."
-  :group 'idlwave-abbrev-and-indent-action
+  "Non-nil means re-indent line after END was typed."
   :type 'boolean)
 
 (defcustom idlwave-abbrev-move t
-  "*Non-nil means the abbrev hook can move point.
+  "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
+See `idlwave-modify-abbrev'."
   :type 'boolean)
 
 (defcustom idlwave-abbrev-change-case nil
-  "*Non-nil means all abbrevs will be forced to either upper or lower case.
+  "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 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.
+  "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.
@@ -663,21 +609,22 @@ Has effect only if in abbrev-mode."
 ;; Example actions:
 ;;
 ;;  Capitalize system vars
-;;   (idlwave-action-and-binding idlwave-sysvar '(capitalize-word 1) t)
+;;   (idlwave-action-and-binding idlwave-sysvar
+;;                               (lambda (_) (capitalize-word 1)) t)
 ;;
 ;;  Capitalize procedure name
 ;;   (idlwave-action-and-binding "\\<\\(pro\\|function\\)\\>[ \t]*\\<"
-;;                           '(capitalize-word 1) t)
+;;                               (lambda (_) (capitalize-word 1)) t)
 ;;
 ;;  Capitalize common block name
 ;;   (idlwave-action-and-binding "\\<common\\>[ \t]+\\<"
-;;                           '(capitalize-word 1) t)
+;;                               (lambda (_) (capitalize-word 1)) t)
 ;;  Capitalize label
 ;;   (idlwave-action-and-binding (concat "^[ \t]*" idlwave-label)
-;;                           '(capitalize-word -1) t)
+;;                               (lambda (_) (capitalize-word 1)) t)
 
 (defvar idlwave-indent-action-table nil
-  "*Associated array containing action lists of search string (car),
+  "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.
@@ -687,7 +634,7 @@ 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),
+  "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.
@@ -697,7 +644,7 @@ binding is requested.
 See help on `idlwave-action-and-binding' for examples.")
 
 ;;----------------------------------------------------
-;; Documentation header and history keyword 
+;;;; Documentation header and history keyword
 (defgroup idlwave-documentation nil
   "Options for documenting IDLWAVE files."
   :group 'idlwave)
@@ -765,80 +712,72 @@ See help on `idlwave-action-and-binding' for examples.")
 ;
 ;-
 ")
-  "*A list (PATHNAME STRING) specifying the doc-header template to use for
+  "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.
+  "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
+  "The hook function used to update the timestamp of a function."
   :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.
+  "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
+  "Regexp matching the start of a document library header."
   :type 'regexp)
 
 (defcustom idlwave-doclib-end "^;+-"
-  "*Regexp matching the end of a document library header."
-  :group 'idlwave-documentation
+  "Regexp matching the end of a document library header."
   :type 'regexp)
 
 ;;----------------------------------------------------
-;; External Programs
+;;;; 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.
+  "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.
+  "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
+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)
+	  (repeat (string :value ""))))
 
 (defcustom idlwave-help-application "idlhelp"
-  "*The external application providing reference help for programming.
+  "The external application providing reference help for programming.
 Obsolete, if the IDL Assistant is being used for help."
-  :group 'idlwave-external-programs
   :type 'string)
 
 ;;----------------------------------------------------
-;; Help 
+;;;; Help
 (defgroup idlwave-online-help nil
   "Online Help options for IDLWAVE mode."
   :group 'idlwave)
@@ -846,46 +785,39 @@ Obsolete, if the IDL Assistant is being used for help."
 (defcustom idlwave-html-help-pre-v6 nil
   "Whether pre or post-v6.0 IDL help documents are being used.
 OBSOLETE.  The full link anchor is now stored."
-  :group 'idlwave-online-help
   :type 'boolean)
 
 (defcustom idlwave-html-system-help-location  nil
-  "The directory, relative to idlwave-system-directory, where the
-idl HTML help files live, for IDL 7.0 and later.  By default,
+  "The directory, relative to `idlwave-system-directory', where the
+IDL HTML help files live, for IDL 7.0 and later.  By default,
 this location is discovered automatically from the installation.
 This location, if found, is used in preference to the old
-idlwave-html-help-location.  Note that IDL v6.3-v7.0 used
-help/online_help."
-  :group 'idlwave-online-help
+`idlwave-html-help-location'.  Note that IDL v6.3-v7.0 used
+\"help/online_help\"."
   :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 (see idlwave-html-system-help-location)."
-  :group 'idlwave-online-help
+  "The directory where the \"idl_html_help/\" dir lives.
+OBSOLETE (see `idlwave-html-system-help-location')."
   :type 'directory)
 
 (defcustom idlwave-help-browser-function browse-url-browser-function
-  "Function to use to display html help.
+  "Function to use to display HTML help.
 Defaults to `browse-url-browser-function', which see."
-  :group 'idlwave-online-help
   :type 'function)
 
 (defcustom idlwave-help-browser-generic-program browse-url-generic-program
-  "Program to run if using browse-url-generic-program."
-  :group 'idlwave-online-help
-  :type 'string)
-
-(defvar browse-url-generic-args)
+  "Program to run if using `browse-url-generic-program'."
+  :type '(choice (const nil) string))
 
+;; FIXME: 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."
-  :group 'idlwave-online-help
   :type 'string)
 
 (defcustom idlwave-help-browser-is-local nil
@@ -895,12 +827,10 @@ 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."
-  :group 'idlwave-online-help
   :type 'boolean)
 
 (defcustom idlwave-help-use-dedicated-frame t
-  "*Non-nil means, use a separate frame for Online Help if possible."
-  :group 'idlwave-online-help
+  "Non-nil means, use a separate frame for Online Help if possible."
   :type 'boolean)
 
 (defcustom idlwave-help-frame-parameters
@@ -909,14 +839,12 @@ must be explicitly set non-nil in order for the variable
 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."
-  :group 'idlwave-online-help
   :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."
-  :group 'idlwave-online-help
   :type 'integer)
 
 (defcustom idlwave-extra-help-function 'idlwave-help-with-source
@@ -944,47 +872,42 @@ 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."
-  :group 'idlwave-online-help
   :type 'symbol)
 
 (defcustom idlwave-help-fontify-source-code t
-  "*Non-nil means, fontify source code displayed as help like normal code."
-  :group 'idlwave-online-help
+  "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.
+  "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."
-  :group 'idlwave-online-help
   :type 'boolean)
 
 (defcustom idlwave-help-doclib-name "name"
-  "*A regexp for the heading word to search for in doclib headers
+  "A regexp for the heading word to search for in doclib headers
 which specifies the `name' section.  Can be used for localization
 support."
-  :group 'idlwave-online-help
-  :type 'string)
+  :type 'regexp)
 
 (defcustom idlwave-help-doclib-keyword "KEYWORD"
-  "*A regexp for the heading word to search for in doclib headers
+  "A regexp for the heading word to search for in doclib headers
 which specifies the `keywords' section.  Can be used for localization
 support."
-  :group 'idlwave-online-help
-  :type 'string)
+  :type 'regexp)
 
 ;;----------------------------------------------------
-;; Shell
+;;;; Shell
 (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
+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"
@@ -996,7 +919,7 @@ are `control', `meta', `super', `hyper', `alt', and `shift'."
 	       (const shift)))
 
 (defcustom idlwave-shell-automatic-start nil
-  "*If non-nil attempt invoke `idlwave-shell' if not already running.
+  "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
@@ -1004,18 +927,17 @@ IDL process is made."
 
 
 ;;----------------------------------------------------
-;; Miscellaneous variables
+;;;; 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
+  "Non-nil displays a startup message when `idlwave-mode' is first called."
   :type 'boolean)
 
-(defcustom idlwave-default-font-lock-items 
+(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.
@@ -1024,17 +946,15 @@ 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
-fixme                FIXME: Warning in comments (on XEmacs only v. 21.0 and up)
-class-arrows         Object Arrows with class property"
-  :group 'idlwave-misc
+`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"
   :type '(set
 	  :inline t :greedy t
 	  (const :tag "Procedure and Function definitions" pros-and-functions)
@@ -1047,18 +967,17 @@ class-arrows         Object Arrows with class property"
 	  (const :tag "Common Blocks"                     common-blocks)
 	  (const :tag "Keyword Parameters"                keyword-parameters)
 	  (const :tag "System Variables"                  system-variables)
-	  (const :tag "FIXME: Warning"                    fixme)
 	  (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." "24.4")
 
 (defvar idlwave-experimental nil
   "Non-nil means turn on a few experimental features.
@@ -1072,30 +991,30 @@ As a user, you should not set this to t.")
 
 ;;; Non customization variables
 
-;;; font-lock mode - Additions by Phil Williams, Ulrik Dickow and
-;;; Simon Marshall <simon_at_gnu.ai.mit.edu>
-;;; and Carsten Dominik...
+;; 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?       
+;; 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 
+  ;; To update this regexp, update the list of keywords and
   ;; evaluate the form.
-  	;; (insert 
+  	;; (insert
   	;;  (prin1-to-string
-  	;;   (concat 
+  	;;   (concat
   	;;    "\\<\\("
-  	;;    (regexp-opt 
+  	;;    (regexp-opt
   	;;     '("||" "&&" "and" "or" "xor" "not"
-  	;;       "eq" "ge" "gt" "le" "lt" "ne" 
+  	;;       "eq" "ge" "gt" "le" "lt" "ne"
   	;;       "for" "do" "endfor" "foreach" "endforeach"
-  	;;       "if" "then" "endif" "else" "endelse" 
+  	;;       "if" "then" "endif" "else" "endelse"
   	;;       "case" "of" "endcase"
   	;;       "switch" "break" "continue" "endswitch"
   	;;       "begin" "end"
   	;;       "repeat" "until" "endrep"
-  	;;       "while" "endwhile" 
+  	;;       "while" "endwhile"
   	;;       "goto" "return"
   	;;       "inherits" "mod"
   	;;       "compile_opt" "forward_function"
@@ -1104,98 +1023,101 @@ As a user, you should not set this to t.")
 
   "\\<\\(\\(?:&&\\|and\\|b\\(?:egin\\|reak\\)\\|c\\(?:ase\\|o\\(?:mpile_opt\\|ntinue\\)\\)\\|do\\|e\\(?:lse\\|nd\\(?:case\\|else\\|for\\(?:each\\)?\\|if\\|rep\\|switch\\|while\\)?\\|q\\)\\|for\\(?:each\\|ward_function\\)?\\|g\\(?:oto\\|[et]\\)\\|i\\(?:f\\|nherits\\)\\|l[et]\\|mod\\|n\\(?:e\\|ot\\)\\|o\\(?:n_\\(?:\\(?:io\\)?error\\)\\|[fr]\\)\\|re\\(?:peat\\|turn\\)\\|switch\\|then\\|until\\|while\\|xor\\|||\\)\\)\\>")
 
-(let* (;; 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
-	   (goto-char (match-end 0))  ; needed for XEmacs, could be nil 
-	   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-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 preceeding 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))))
+(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)
+    (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
+    (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."))
 
@@ -1210,30 +1132,27 @@ As a user, you should not set this to t.")
 
 (defvar idlwave-font-lock-defaults
   '((idlwave-font-lock-keywords
-     idlwave-font-lock-keywords-1 
+     idlwave-font-lock-keywords-1
      idlwave-font-lock-keywords-2
      idlwave-font-lock-keywords-3)
-    nil t 
-    ((?$ . "w") (?_ . "w") (?. . "w") (?| . "w") (?& . "w")) 
+    nil t
+    ((?$ . "w") (?_ . "w") (?. . "w") (?| . "w") (?& . "w"))
     beginning-of-line))
 
-(put 'idlwave-mode 'font-lock-defaults 
-     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.")
 
-(defconst idlwave-begin-block-reg 
+(defconst idlwave-begin-block-reg
   "\\<\\(pro\\|function\\|begin\\|case\\|switch\\)\\>"
-  "Regular expression to find the beginning of a block. 
+  "Regular expression to find the beginning of a block.
 The case does not matter. The search skips matches in comments.")
 
 (defconst idlwave-profun-reg "^\\s-*\\(pro\\|function\\)\\>")
 
 (defconst idlwave-begin-unit-reg (concat idlwave-profun-reg "\\|\\`")
-  "Regular expression to find the beginning of a unit. 
+  "Regular expression to find the beginning of a unit.
 The case does not matter.")
 
 (defconst idlwave-end-unit-reg "^\\s-*\\(pro\\|function\\)\\>\\|\\'"
@@ -1246,7 +1165,7 @@ case does not matter. The search skips matches in comments.")
 
 (defconst idlwave-end-block-reg
   "\\<end\\(\\|case\\|switch\\|else\\|for\\|foreach\\|if\\|rep\\|while\\)\\>"
-  "Regular expression to find the end of a block. 
+  "Regular expression to find the end of a block.
 The case does not matter. The search skips matches found in
 comments.")
 
@@ -1307,17 +1226,20 @@ blocks starting with a BEGIN statement.  The matches must have associations
    '(goto . ("goto\\>" nil))
    '(case . ("case\\>" nil))
    '(switch . ("switch\\>" nil))
-   (cons 'call (list (concat "\\(" idlwave-variable "\\) *= *" 
+   (cons 'call (list (concat "\\(" idlwave-variable "\\) *= *"
 			     "\\(" idlwave-method-call "\\s *\\)?"
 			     idlwave-identifier
-			     "\\s *(") nil))
-   (cons 'call (list (concat 
+			     "\\s *(")
+		     nil))
+   (cons 'call (list (concat
 		      "\\(" idlwave-method-call "\\s *\\)?"
-		      idlwave-identifier 
-		      "\\( *\\($\\|\\$\\)\\|\\s *,\\)") nil))
-   (cons 'assign (list (concat 
-			"\\(" idlwave-variable "\\) *=") nil)))
-  
+		      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
@@ -1331,24 +1253,19 @@ 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-fill-function 'auto-fill-function
-  "IDL mode auto fill function.")
-
 (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 ?\ 
+(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 "VERSIONTAG")
+\\[idlwave-split-line] to begin a continuation line.  Normally $.")
 
 (provide 'idlw-variables)
 (provide 'idlwave-variables)
diff --git a/idlwave.el b/idlwave.el
index face890f91..1a2d93ac78 100644
--- a/idlwave.el
+++ b/idlwave.el
@@ -1,13 +1,12 @@
-;; idlwave.el --- IDL editing mode for GNU Emacs
+;;; idlwave.el --- IDL editing mode for GNU Emacs  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;;   2008, 2009, 2010, 2011, 2012, 2013  Free Software Foundation, Inc.
+;; Copyright (C) 1999-2024  Free Software Foundation, Inc.
 
 ;; Authors: J.D. Smith <jdsmith _AT_ alum.mit.edu>
 ;;          Carsten Dominik <dominik _AT_ science.uva.nl>
 ;;          Chris Chase <chase _AT_ att.com>
 ;; Maintainer: J.D. Smith <jdsmith _AT_ alum.mit.edu>
-;; Version: VERSIONTAG
+;; Version: 6.5
 ;; Keywords: languages
 
 ;; This file is part of GNU Emacs.
@@ -23,21 +22,21 @@
 ;; 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 <http://www.gnu.org/licenses/>.
+;; 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.  
+;; bundled with IDL.
 
 ;; See the mode description ("C-h m" in idlwave-mode or "C-h f
-;; idlwave-mode") for features, key bindings, and info.  
+;; idlwave-mode") for features, key bindings, and info.
 ;;
 ;; New versions of IDLWAVE, documentation, and more information
 ;; available from:
-;;                 http://github.com/jdtsmith/idlwave
+;;                 https://github.com/jdtsmith/idlwave
 ;;
 ;; INSTALLATION
 ;; ============
@@ -57,7 +56,7 @@
 ;; The newest version of IDLWAVE is available from the maintainer's
 ;; Webpage:
 ;;
-;;   http://github.com/jdtsmith/idlwave
+;;   https://github.com/jdtsmith/idlwave
 ;;
 ;; DOCUMENTATION
 ;; =============
@@ -67,7 +66,7 @@
 ;; printable version of the documentation is available from the
 ;; maintainers webpage (see SOURCE).
 ;;
-;; 
+;;
 ;; ACKNOWLEDGMENTS
 ;; ===============
 ;;
@@ -121,11 +120,11 @@
 ;;
 ;;   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
+;;   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, 
+;;   using a temporary function in `post-command-hook' - not pretty,
 ;;   but it works.
 ;;
 ;;   Tabs and spaces are treated equally as whitespace when filling a
@@ -147,7 +146,7 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
 (require 'idlw-help)
 (require 'idlw-variables)
 (require 'idlw-routine)
@@ -170,10 +169,15 @@
 (defvar imenu-extract-index-name-function)
 (defvar imenu-prev-index-position-function)
 
+(defconst idlwave-mode-version
+  (if (fboundp 'package-get-version)
+      (package-get-version)
+    "VERSIONTAG"))
+
 
 ;;;###autoload
-(defun idlwave-mode ()
-  "Major mode for editing IDL source files (version VERSIONTAG).
+(define-derived-mode idlwave-mode prog-mode "IDLWAVE"
+  "Major mode for editing IDL source files.
 
 The main features of this mode are
 
@@ -198,7 +202,7 @@ The main features of this mode are
    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
-   \\[idlwave-auto-fill-mode] to toggle auto-fill mode for these
+   \\[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.
 
@@ -240,7 +244,7 @@ The main features of this mode are
 5. Code Templates and Abbreviations
    --------------------------------
    Many Abbreviations are predefined to expand to code fragments and templates.
-   The abbreviations start generally with a `\\`.  Some examples:
+   The abbreviations start generally with a `\\'.  Some examples:
 
    \\pr        PROCEDURE template
    \\fu        FUNCTION template
@@ -252,7 +256,7 @@ The main features of this mode are
    \\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.
 
@@ -273,7 +277,6 @@ The main features of this mode are
 
 8. Hooks
    -----
-   Loading idlwave.el runs `idlwave-load-hook'.
    Turning on `idlwave-mode' runs `idlwave-mode-hook'.
 
 9. Documentation and Customization
@@ -281,7 +284,8 @@ The main features of this mode are
    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 homepage at URL `http://github.com/jdtsmith/idlwave'.
+   documentation, check IDLWAVE's website at URL
+   `https://github.com/jdtsmith/idlwave'.
    IDLWAVE has customize support - see the group `idlwave'.
 
 10.Keybindings
@@ -291,78 +295,64 @@ The main features of this mode are
    followed by the key sequence to see what the key sequence does.
 
 \\{idlwave-mode-map}"
+  :abbrev-table idlwave-mode-abbrev-table
 
-  (interactive)
-  (kill-all-local-variables)
-  
   (if idlwave-startup-message
       (message "Emacs IDLWAVE mode version %s." idlwave-mode-version))
   (setq idlwave-startup-message nil)
-  
-  (setq local-abbrev-table idlwave-mode-abbrev-table)
-  (set-syntax-table idlwave-mode-syntax-table)
-  
-  (set (make-local-variable 'indent-line-function) 'idlwave-indent-and-action)
-  
-  (make-local-variable idlwave-comment-indent-function)
-  (set idlwave-comment-indent-function 'idlwave-comment-hook)
-  
+
+  (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)
-  
-  (use-local-map idlwave-mode-map)
-
-  (when (featurep 'easymenu)
-    (easy-menu-add idlwave-mode-menu idlwave-mode-map)
-    (easy-menu-add idlwave-mode-debug-menu idlwave-mode-map))
 
-  (setq mode-name "IDLWAVE")
-  (setq major-mode 'idlwave-mode)
   (setq abbrev-mode t)
-  
-  (set (make-local-variable idlwave-fill-function) 'idlwave-auto-fill)
+
+  (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) 
+  (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 (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")))
-  
+      (add-to-list 'tag-table-alist '("\\.pro\\'" . "IDLTAGS")))
+
   ;; Font-lock additions
-  ;; Following line is for Emacs - XEmacs uses the corresponding property
-  ;; on the `idlwave-mode' symbol.
   (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-mark-block-function)
+       #'idlwave-mark-subprogram)
   (set (make-local-variable 'font-lock-fontify-region-function)
-       'idlwave-font-lock-fontify-region)
+       #'idlwave-font-lock-fontify-region)
 
   ;; Imenu setup
-  (set (make-local-variable 'imenu-create-index-function)
-       'imenu-default-create-index-function)
+  ;; (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)
+       #'idlwave-unit-name)
   (set (make-local-variable 'imenu-prev-index-position-function)
-       'idlwave-prev-index-position)
+       #'idlwave-prev-index-position)
 
   ;; defun movement
   (set (make-local-variable 'beginning-of-defun-function)
-       'idlwave-beginning-of-subprogram)
+       #'idlwave-beginning-of-subprogram)
   (set (make-local-variable 'end-of-defun-function)
-       'idlwave-end-of-subprogram)  
+       #'idlwave-end-of-subprogram)
 
   ;; HideShow setup
   (add-to-list 'hs-special-modes-alist
@@ -373,44 +363,42 @@ The main features of this mode are
 		     '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)
+  (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)
+  (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)
-
-  ;; Run the mode hook
-  (run-mode-hooks 'idlwave-mode-hook))
+  (idlwave-new-buffer-update))
 
 ;; Special module
 (if idlwave-complete-structure-tags
-	(require 'idlw-complete-structtag))
+    ;; FIXME: This `require' causes a cyclic load during byte-compilation.
+    nil ;; (require 'idlw-complete-structtag)
+  )
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist (cons (purecopy "\\.pro\\'")  'idlwave-mode))
-(eval-after-load "speedbar" '(speedbar-add-supported-extension ".pro"))
+(declare-function speedbar-add-supported-extension "speedbar" (extension))
+(with-eval-after-load "speedbar" (speedbar-add-supported-extension ".pro"))
 
-(defvar idlwave-command-hook nil
-  "If non-nil, a list that can be evaluated using `eval'.
-It is evaluated in the lisp function `idlwave-command-hook' which is
+(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-hook' and
+Evaluates a non-nil value of the *variable* `idlwave--command-function' and
 sets the variable to zero afterwards."
-  (and idlwave-command-hook
-       (listp idlwave-command-hook)
-       (condition-case nil
-	   (eval idlwave-command-hook)
-	 (error nil)))
-  (setq idlwave-command-hook nil))
+  (and idlwave--command-function
+       (with-demoted-errors "idlwave-command-hook: %S"
+	 (funcall (prog1 idlwave--command-function
+	            (setq idlwave--command-function nil))))))
 
 (defvar idlwave-setup-done nil)
 (defun idlwave-setup ()
@@ -418,16 +406,16 @@ sets the variable to zero afterwards."
   (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 
+    (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
+     (expand-file-name
       idlwave-xml-system-rinfo-converted-file
       idlwave-config-directory)
-     idlwave-path-file (expand-file-name 
-			idlwave-path-file 
+     idlwave-path-file (expand-file-name
+			idlwave-path-file
 			idlwave-config-directory))
     ;; Check and setup help location
     (idlwave-read-paths)  ; we may need these early
@@ -437,7 +425,7 @@ sets the variable to zero afterwards."
 
 ;;----------------------------------------------------
 ;; Fontification
-;; 
+;;
 (defun idlwave-font-lock-fontify-region (beg end &optional verbose)
   "Fontify continuation lines correctly."
   (let (pos)
@@ -461,8 +449,8 @@ sets the variable to zero afterwards."
        ((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) 
+	(let ((limit (save-excursion
+		       (idlwave-beginning-of-statement)
 		       (point))))
 	  (cond
 	   ((re-search-backward ":[ \t]*\\=" limit t)
@@ -499,13 +487,13 @@ If prefix ARG < 0 then move forward to enclosing block end."
   "Go to the beginning of the current block."
   (interactive)
   (idlwave-block-jump-out -1 'nomark)
-  (forward-word 1))
+  (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 1))
+  (backward-word-strictly 1))
 
 (defun idlwave-forward-block (&optional arg)
   "Move across next nested block."
@@ -531,7 +519,7 @@ Returns non-nil if successful."
         (let ((eos (save-excursion
                      (idlwave-block-jump-out -1 'nomark)
                      (point))))
-          (if (setq status (idlwave-find-key 
+          (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.")))
@@ -539,7 +527,7 @@ Returns non-nil if successful."
       (let ((eos (save-excursion
                    (idlwave-block-jump-out 1 'nomark)
                    (point))))
-        (if (setq status (idlwave-find-key 
+        (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."))))
@@ -558,7 +546,7 @@ possibility of unbalanced blocks."
   (let* ((here (point))
          (case-fold-search t)
          (limit (if (>= dir 0) (point-max) (point-min)))
-         (block-limit (if (>= dir 0) 
+         (block-limit (if (>= dir 0)
 			  idlwave-begin-block-reg
 			idlwave-end-block-reg))
          found
@@ -569,29 +557,28 @@ possibility of unbalanced blocks."
 			       (idlwave-find-key
 				idlwave-begin-unit-reg dir t limit)
 			     (end-of-line)
-			     (idlwave-find-key 
+			     (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 1))
+          (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 1)))))
+      (if (>= dir 0) (forward-word-strictly 1)))))
 
 (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 (not (idlwave-quoted))
-      (if
-	  (save-excursion
-	    (backward-word 1)
-	    (backward-char 1)
-	    (looking-at "[ \t\n\f]"))
-	  (idlwave-show-begin))))
+  (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.
@@ -602,11 +589,11 @@ Also checks if the correct END statement has been used."
   ;;(backward-char 1)
   (let* ((pos (point-marker))
 	 (last-abbrev-marker (copy-marker last-abbrev-location))
-	 (eol-pos (save-excursion (end-of-line) (point)))
+         (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-check-abbrev 0 t)
+    (when (and (idlwave-modify-abbrev 0 t)
 	       idlwave-show-block)
       (save-excursion
 	;; Move inside current block
@@ -618,7 +605,7 @@ Also checks if the correct END statement has been used."
 	(if (> end-pos eol-pos)
 	    (setq end-pos pos))
 	(goto-char end-pos)
-	(setq end (buffer-substring 
+	(setq end (buffer-substring
 		   (progn
 		     (skip-chars-backward "a-zA-Z")
 		     (point))
@@ -640,7 +627,7 @@ Also checks if the correct END statement has been used."
 	    (sit-for 1))
 	   (t
 	    (beep)
-	    (message "Warning: Shouldn't this be \"%s\" instead of \"%s\"?" 
+	    (message "Warning: Shouldn't this be \"%s\" instead of \"%s\"?"
 		     end1 end)
 	    (sit-for 1))))))))
 
@@ -719,7 +706,7 @@ With ARG, enforce query for the class of object methods."
     (if (string-match "\\(pro\\|function\\)[ \t]+\\(\\(.*\\)::\\)?\\(.*\\)"
 		      resolve)
 	(setq type (match-string 1 resolve)
-	      class (if (match-beginning 2) 
+	      class (if (match-beginning 2)
 			(match-string 3 resolve)
 		      nil)
 	      name (match-string 4 resolve)))
@@ -728,18 +715,19 @@ With ARG, enforce query for the class of object methods."
 
     (cond
      ((null class)
-      (idlwave-shell-send-command 
+      (idlwave-shell-send-command
        (format "resolve_routine,'%s'%s" (downcase name) kwd)
-       'idlwave-update-routine-info
+       #'idlwave-update-routine-info
        nil t))
      (t
-      (idlwave-shell-send-command 
+      (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))))))
+       (lambda ()
+	 (idlwave-shell-send-command
+	  (format "resolve_routine,'%s__%s'%s"
+	          (downcase class) (downcase name) kwd)
+	  #'idlwave-update-routine-info
+	  nil t)))))))
 
 ;;----------------------------------------------------
 ;; Statements/substatements
@@ -760,10 +748,10 @@ Point is placed at the beginning of the line whether or not this is an
 actual statement."
   (interactive)
   (cond
-   ((eq major-mode 'idlwave-shell-mode)
+   ((derived-mode-p 'idlwave-shell-mode)
     (if (re-search-backward idlwave-shell-prompt-pattern nil t)
 	(goto-char (match-end 0))))
-   (t	
+   (t
     (if (save-excursion (forward-line -1) (idlwave-is-continuation-line))
 	(idlwave-previous-statement)
       (beginning-of-line)))))
@@ -847,7 +835,7 @@ If there is no label point is not moved and nil is returned."
   ;; - 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. 
+  ;; parser.
   (let* ((start (point))
 	 (eos (or eos (save-excursion (idlwave-end-of-statement) (point))))
 	 (end (idlwave-find-key ":" 1 'nomark eos)))
@@ -897,7 +885,7 @@ substatement."
     ;; If a continuation line starts here, move to next line
     (when (looking-at "[ \t]*\\$\\([ \t]*\\(;\\|$\\)\\)")
       (beginning-of-line 2))
-    (while 
+    (while
 	(and (not (eobp))
 	     (or (looking-at idlwave-comment-line-start-skip) ;comment only
 		 (looking-at "[ \t]*$"))) ; blank
@@ -919,11 +907,9 @@ Assumes that point is at the beginning of the unit as found by
   (forward-sexp 2)
   (forward-sexp -1)
   (let ((begin (point)))
-    (re-search-forward 
+    (re-search-forward
      "[a-zA-Z_][a-zA-Z0-9$_]+\\(::[a-zA-Z_][a-zA-Z0-9$_]+\\)?")
-    (if (fboundp 'buffer-substring-no-properties)
-        (buffer-substring-no-properties begin (point))
-      (buffer-substring begin (point)))))
+    (buffer-substring-no-properties begin (point))))
 
 ;;----------------------------------------------------
 ;; Comments/strings
@@ -960,14 +946,10 @@ blank lines."
       ;; skip blank lines
       (skip-chars-forward " \t\n")
       (if (looking-at (concat "[ \t]*\\(" comment-start "+\\)"))
-	  (if (fboundp 'uncomment-region)
-	      (uncomment-region beg end)
-	    (comment-region beg end
-			    (- (length (buffer-substring
-					(match-beginning 1)
-					(match-end 1))))))
+          (uncomment-region beg end)
 	(comment-region beg end)))))
 
+
 (defun idlwave-skip-multi-commands (&optional lim)
   "Skip past multiple commands on a line (or multiple lines) (with `&')."
   (let ((save-point (point)))
@@ -984,7 +966,7 @@ blank lines."
 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 (progn (end-of-line) (point)))
+  (let ((eos (line-end-position))
         (data (match-data))
         found)
     ;; Look for first comment delimiter not in a string
@@ -1002,27 +984,23 @@ Returns point if comment found and nil otherwise."
   "Find and return the beginning and end position of a commented paragraph.
 End is calculated as distance from end of buffer, to accommodate
 additions from filling."
-  (let (pre diff fill-prefix-reg bcl start end)
+  (let (pre fill-prefix-reg bcl start end) ;; diff
     (beginning-of-line)
     (setq bcl (point))
-    (re-search-forward
-     (concat "^[ \t]*" comment-start "+")
-     (save-excursion (end-of-line) (point))
-     t)
+    (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 (save-excursion
-				      (beginning-of-line) (point))
-				    (point))))
-	   "[^;]"))
-	
-    ;; Mark the beginning and end of the paragraph
+        (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))
@@ -1104,7 +1082,7 @@ Point is expected just before the opening `{' of the struct definition."
   (let* ((borders (idlwave-struct-borders))
 	 (end (cdr borders))
 	 (case-fold-search t))
-    (re-search-forward (concat "\\(^[ \t]*\\|[,{][ \t]*\\)" tag "[ \t]*:") 
+    (re-search-forward (concat "\\(^[ \t]*\\|[,{][ \t]*\\)" tag "[ \t]*:")
 		       end t)))
 
 (defun idlwave-struct-inherits ()
@@ -1119,7 +1097,7 @@ Point is expected just before the opening `{' of the struct definition."
       (goto-char beg)
       (save-restriction
 	(narrow-to-region beg end)
-	(while (re-search-forward 
+	(while (re-search-forward
 		(concat "[{,]"  ;leading comma/brace
 			idlwave-struct-skip ; 4 groups
 			"inherits"    ; The INHERITS tag
@@ -1159,9 +1137,9 @@ we search only backward."
 		  (concat "\\<" (regexp-quote (downcase var)) "\\>" ws)
 		"\\(\\)")
 	      "=" ws "\\({\\)"
-	      (if name 
+	      (if name
 		  (if (stringp name)
-		      (concat ws "\\(\\<" (downcase name) "\\)[^a-zA-Z0-9_$]") 
+		      (concat ws "\\(\\<" (downcase name) "\\)[^a-zA-Z0-9_$]")
 		    ;; Just a generic name
 		    (concat ws "\\<\\([a-zA-Z_0-9$]+\\)" ws ","))
 		""))))
@@ -1189,7 +1167,7 @@ class/struct definition."
 	  (progn
 	    ;; For everything there
 	    (setq end-lim (save-excursion (idlwave-end-of-subprogram) (point)))
-	    (while (setq name 
+	    (while (setq name
 			 (idlwave-find-structure-definition nil t end-lim))
 	      (funcall all-hook name)))
 	(idlwave-find-structure-definition nil (or alt-class class))))))
@@ -1198,13 +1176,13 @@ class/struct definition."
   (let (list entry)
     (if idlwave-class-info
 	(if idlwave-class-reset
-	    (setq 	    
+	    (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 
+	     (delq nil (mapcar
+			(lambda (x)
+			  (let ((filebuf
+				 (idlwave-class-file-or-buffer
 				  (or (cdr (assq 'found-in x)) (car x)))))
 			    (if (cdr filebuf)
 				nil
@@ -1226,7 +1204,8 @@ class/struct definition."
 	 (file (idlwave-routine-source-file
 		(nth 3 (idlwave-rinfo-assoc pro 'pro nil
 					    (idlwave-routines))))))
-    (cons file (if file (idlwave-get-buffer-visiting file)))))
+    (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."
@@ -1246,16 +1225,16 @@ class/struct definition."
 	  ;; Read the file in temporarily
 	  (set-buffer (get-buffer-create " *IDLWAVE-tmp*"))
 	  (erase-buffer)
-	  (unless (eq major-mode 'idlwave-mode)
+	  (unless (derived-mode-p 'idlwave-mode)
 	    (idlwave-mode))
 	  (insert-file-contents file))
 	(save-excursion
 	  (goto-char 1)
-	  (idlwave-find-class-definition class 
+	  (idlwave-find-class-definition class
 	   ;; Scan all of the structures found there
 	   (lambda (name)
 	     (let* ((this-class (idlwave-sintern-class name))
-		    (entry 
+		    (entry
 		     (list this-class
 			   (cons 'tags (idlwave-struct-tags))
 			   (cons 'inherits (idlwave-struct-inherits)))))
@@ -1279,9 +1258,9 @@ class/struct definition."
 (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           
+      (apply #'append (mapcar #'idlwave-class-tags
+			      (cons class (idlwave-all-class-inherits class))))
+    (error
      (idlwave-class-tag-reset)
      (error "%s" (error-message-string err)))))
 
@@ -1310,8 +1289,7 @@ The list is cached in `idlwave-class-info' for faster access."
 				   inherits))
 	    (if (> (cdr cl) 999)
 	      (error
-	       "Class scan: inheritance depth exceeded. Circular inheritance?")
-	      ))
+               "Class scan: inheritance depth exceeded.  Circular inheritance?")))
 	  (setq all-inherits (nreverse rtn))
 	  (nconc info (list (cons 'all-inherits all-inherits)))
 	  all-inherits))))))
@@ -1326,8 +1304,8 @@ associated TAG, if any."
        (setq cl (pop sclasses))
        (let ((tags (idlwave-class-tags cl)))
 	 (while tags
-	   (if (eq t (compare-strings tag 0 nil (car tags) 0 nil t))
-	     (throw 'exit cl))	       
+	   (if (string-equal-ignore-case tag (car tags))
+	     (throw 'exit cl))
 	   (setq tags (cdr tags))))))))
 
 (defun idlwave-explicit-class-listed (info)
@@ -1362,7 +1340,7 @@ INFO is as returned by `idlwave-what-function' or `-procedure'."
 		(save-excursion
 		  (cond
 		   ;; Beginning of file
-		   ((prog1 
+		   ((prog1
 			(idlwave-previous-statement)
 		      (setq beg-prev-pos (point)))
 		    0)
@@ -1372,7 +1350,7 @@ INFO is as returned by `idlwave-what-function' or `-procedure'."
 		       idlwave-main-block-indent))
 		   ;; Begin block
 		   ((idlwave-look-at idlwave-begin-block-reg t)
-		    (+ (idlwave-min-current-statement-indent) 
+		    (+ (idlwave-min-current-statement-indent)
 		       idlwave-block-indent))
 		   ;; End Block
 		   ((idlwave-look-at idlwave-end-block-reg t)
@@ -1383,7 +1361,7 @@ INFO is as returned by `idlwave-what-function' or `-procedure'."
 		      (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
@@ -1398,8 +1376,8 @@ INFO is as returned by `idlwave-what-function' or `-procedure'."
 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-*\\=" 
+    (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))
@@ -1409,7 +1387,7 @@ With prefix ARG non-nil, indent the entire sub-statement."
   (when (and (not arg) current-prefix-arg)
     (setq arg current-prefix-arg)
     (setq current-prefix-arg nil))
-  (if arg 
+  (if arg
       (idlwave-indent-statement)
     (idlwave-indent-line t)))
 
@@ -1438,10 +1416,10 @@ If the optional argument EXPAND is non-nil then the actions in
         ;; Before indenting, run action routines.
         ;;
         (if (and expand idlwave-do-actions)
-            (mapc 'idlwave-do-action idlwave-indent-expand-table))
+            (mapc #'idlwave-do-action idlwave-indent-expand-table))
         ;;
         (if idlwave-do-actions
-            (mapc 'idlwave-do-action idlwave-indent-action-table))
+            (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.
@@ -1461,10 +1439,7 @@ If the optional argument EXPAND is non-nil then the actions in
         ;; Adjust parallel comment
 	(end-of-line)
 	(if (idlwave-in-comment)
-	    ;; Emacs 21 is too smart with fill-column on comment indent
-	    (let ((fill-column (if (fboundp 'comment-indent-new-line)
-				   (1- (frame-width))
-				 fill-column)))
+            (let ((fill-column (1- (frame-width))))
 	      (indent-for-comment)))))
     (goto-char mloc)
     ;; Get rid of marker
@@ -1527,7 +1502,7 @@ is non-nil."
 	    (if (not (member (char-before) '(?\  ?\t)))
 		(insert " "))
             (insert idlwave-continuation-char)
-	    (if (null noindent) 
+	    (if (null noindent)
 		(newline-and-indent)
 	      (newline))))
       (indent-new-comment-line))
@@ -1543,18 +1518,19 @@ is non-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 name to be called with `funcall' 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
+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 (listp action-routine)
-          (eval (append action-routine '('is-action)))
-        (funcall action-routine 'is-action)))))
+      (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.
@@ -1595,7 +1571,7 @@ Inserts spaces before markers at point."
 
 (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 
+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.
@@ -1635,24 +1611,24 @@ routine definitions, and parenthetical groupings, are treated separately."
            (end-reg (progn (beginning-of-line) (point)))
 	   (beg-last-statement (save-excursion (idlwave-previous-statement)
 					       (point)))
-           (beg-reg (progn (idlwave-start-of-substatement 'pre) 
+           (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 
+      (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\\)?\\)\\>" . 
+			  ("\\<\\(repeat\\|end\\(rep\\)?\\)\\>" .
 			   "[ \t]*until")
 			  ("\\<case\\>" . "[ \t]*of")))
 	      match cont-re)
 	  (goto-char end-reg)
-	  (and 
+	  (and
 	   (setq cont-re
 		 (catch 'exit
 		   (while (setq match (car matchers))
@@ -1661,7 +1637,7 @@ routine definitions, and parenthetical groupings, are treated separately."
 		     (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-current-indent)
 	       (+ idlwave-block-indent idlwave-end-offset))
 	  (idlwave-current-indent)))
 
@@ -1687,7 +1663,7 @@ routine definitions, and parenthetical groupings, are treated separately."
 	      (let* ((end-reg end-reg)
 		     (close-exp (progn
 				  (goto-char end-reg)
-				  (skip-chars-forward " \t") 
+				  (skip-chars-forward " \t")
 				  (looking-at "\\s)")))
 		     indent-cons)
 		(catch 'loop
@@ -1721,12 +1697,12 @@ routine definitions, and parenthetical groupings, are treated separately."
 		   (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)) 
+		       (if (null (idlwave-what-function beg-reg))
 			   (throw 'assign t))))
 		   (unless (or
 			    (idlwave-in-quote)
@@ -1757,7 +1733,7 @@ Return value is the beginning of the match or (in case of failure) nil."
   (let ((case-fold-search t)
 	(search-func (if (> dir 0) 're-search-forward 're-search-backward))
 	found)
-    (idlwave-with-special-syntax
+    (with-syntax-table idlwave-find-symbol-syntax-table
      (save-excursion
        (catch 'exit
 	 (while (funcall search-func key-re limit t)
@@ -1785,7 +1761,7 @@ Return value is the beginning of the match or (in case of failure) nil."
 		  (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 min (idlwave-current-indent))))))
 
 (defun idlwave-current-statement-indent (&optional last-line)
@@ -1855,7 +1831,7 @@ ignored."
         ;; 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
-        ;; the first paragraph line and thus will not affect the
+        ;; first paragraph line and thus will not affect the
         ;; indentation.
         ;;
         ;; First check to see if indentation is based on hanging indent.
@@ -1872,19 +1848,17 @@ ignored."
               (setq indent hang)
               (beginning-of-line)
               (while (> (point) start)
-                (re-search-forward comment-start-skip
-                                   (save-excursion (end-of-line) (point))
-                                   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 ?\ ))))
+                (re-search-forward comment-start-skip (line-end-position) t)
+                (let ((diff (- indent (current-column))))
+                  (when (> diff 0)
+                    (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
@@ -1896,13 +1870,9 @@ ignored."
             (setq indent
                   (min indent
                        (progn
-                         (re-search-forward
-                          comment-start-skip
-                          (save-excursion (end-of-line) (point))
-                          t)
+                         (re-search-forward comment-start-skip (line-end-position) t)
                          (current-column))))
-            (forward-line -1))
-          )
+            (forward-line -1)))
         (setq fill-prefix (concat fill-prefix
                                   (make-string (- indent pre)
                                                ?\ )))
@@ -1910,13 +1880,10 @@ ignored."
         (setq first-indent
               (max
                (progn
-                 (re-search-forward
-                  comment-start-skip
-                  (save-excursion (end-of-line) (point))
-                  t)
+                 (re-search-forward comment-start-skip (line-end-position) t)
                  (current-column))
                indent))
-	
+
         ;; try to keep point at its original place
         (goto-char here)
 
@@ -1925,17 +1892,17 @@ ignored."
         ;; 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))
+          (let ((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)))
@@ -1951,21 +1918,15 @@ If not found returns nil."
   (if idlwave-use-last-hang-indent
       (save-excursion
         (end-of-line)
-        (if (re-search-backward
-             idlwave-hang-indent-regexp
-             (save-excursion (beginning-of-line) (point))
-             t)
+        (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
-           (save-excursion (end-of-line) (point))
-           t)
+      (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.  
+  "Called to break lines in auto fill mode.
 Only fills non-comment lines if `idlwave-fill-comment-line-only'
 is nil (it is t by default).  Places a continuation character at
 the end of the line if not in a comment.  Splits strings with IDL
@@ -2003,21 +1964,17 @@ non-nil."
 		  (let ((here (- (point-max) (point)))
 			(indent
 			 (save-excursion
-			   (goto-char 
+			   (goto-char
 			    (car (idlwave-commented-paragraph-beg-end)))
 			   (idlwave-calc-hanging-indent))))
-		    (if indent
-			(progn
-			  ;; Remove whitespace between comment delimiter and
-			  ;; text, insert spaces for appropriate indentation.
-			  (beginning-of-line)
-			  (re-search-forward
-			   comment-start-skip
-			   (save-excursion (end-of-line) (point)) t)
-			  (delete-horizontal-space)
-			  (idlwave-indent-to indent)
-			  (goto-char (- (point-max) here)))
-		      )))
+		    (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)
@@ -2064,26 +2021,13 @@ non-nil."
 	      (idlwave-indent-line))
 	    )))))
 
-(defun idlwave-auto-fill-mode (arg)
-  "Toggle auto-fill mode for IDL mode.
-With arg, turn auto-fill mode on if arg is positive.
-In auto-fill mode, inserting a space at a column beyond `fill-column'
-automatically breaks the line at a previous space."
-  (interactive "P")
-  (prog1 (set idlwave-fill-function
-              (if (if (null arg)
-                      (not (symbol-value idlwave-fill-function))
-                    (> (prefix-numeric-value arg) 0))
-                  'idlwave-auto-fill
-                nil))
-    ;; update mode-line
-    (set-buffer-modified-p (buffer-modified-p))))
+(define-obsolete-function-alias 'idlwave-auto-fill-mode #'auto-fill-mode "28.1")
 
 ;;----------------------------------------------------
 ;; Space padding
 
-(defun idlwave-expand-equal (&optional before after is-action)
-  "Pad '=' with spaces.
+(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
@@ -2107,25 +2051,25 @@ IS-ACTION is ignored.
 
 See `idlwave-surround'."
   (if idlwave-surround-by-blank
-      (let 
+      (let
 	  ((non-an-ops "\\(##\\|\\*\\|\\+\\|-\\|/\\|<\\|>\\|\\^\\)\\=")
-	   (an-ops 
+	   (an-ops
 	    "\\s-\\(AND\\|EQ\\|GE\\|GT\\|LE\\|LT\\|MOD\\|NE\\|OR\\|XOR\\)\\=")
 	   (len 1))
-	
-	(save-excursion 
+
+	(save-excursion
 	  (let ((case-fold-search t))
 	    (backward-char)
-	    (if (or 
+	    (if (or
 		 (re-search-backward non-an-ops nil t)
 		 ;; Why doesn't ##? work for both?
-		 (re-search-backward "\\(#\\)\\=" nil t)) 
+		 (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)  
+
+	(if (eq t idlwave-pad-keyword)
 	    ;; Everything gets padded equally
 	    (idlwave-surround before after len)
 	  ;; Treating keywords/for variables specially...
@@ -2136,15 +2080,15 @@ See `idlwave-surround'."
 			(skip-chars-backward "= \t")
 			(nth 2 (idlwave-where)))))
 	    (cond ((or (memq what '(function-keyword procedure-keyword))
-		       (memq (caar st) '(for pdef))) 
-		   (cond 
+		       (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-surround (&optional before after length is-action)
+(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
@@ -2196,7 +2140,7 @@ The function does nothing if any of the following conditions is true:
 	(next-char (char-after (point)))
 	(method-invoke (and gtr (eq prev-char ?-)))
 	(len (if method-invoke 2 1)))
-    (unless  (eq next-char ?=)
+    (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))))
 
@@ -2262,7 +2206,7 @@ NOMARK is non-nil."
   (insert (current-time-string))
   (insert ", " (user-full-name))
   (if (boundp 'user-mail-address)
-      (insert " <" user-mail-address ">") 
+      (insert " <" user-mail-address ">")
     (insert " <" (user-login-name) "@" (system-name) ">"))
   ;; Remove extra spaces from line
   (idlwave-fill-paragraph)
@@ -2288,7 +2232,7 @@ location on mark ring so that the user can return to previous point."
 	     (setq end (match-end 0)))
 	(progn
 	  (goto-char beg)
-	  (if (re-search-forward 
+	  (if (re-search-forward
 	       (concat idlwave-doc-modifications-keyword ":")
 	       end t)
 	      (end-of-line)
@@ -2308,7 +2252,7 @@ The marks are pushed."
         (here (point)))
     (goto-char (point-max))
     (if (re-search-backward idlwave-doclib-start nil t)
-        (progn 
+        (progn
 	  (setq beg (progn (beginning-of-line) (point)))
 	  (if (re-search-forward idlwave-doclib-end nil t)
 	      (progn
@@ -2319,7 +2263,7 @@ The marks are pushed."
 	  (goto-char here)))))
 
 ;;----------------------------------------------------
-;; Information on surrounding context 
+;; Information on surrounding context
 ;; (see also idlw-routine for local routine context)
 
 (defun idlwave-statement-type ()
@@ -2348,10 +2292,10 @@ Blank or comment-only lines following regular continuation lines (with
 `$') count as continuations too."
   (let (p)
     (save-excursion
-      (or 
+      (or
        (idlwave-look-at "\\<\\$")
        (catch 'loop
-	 (while (and (looking-at "^[ \t]*\\(;.*\\)?$") 
+	 (while (and (looking-at "^[ \t]*\\(;.*\\)?$")
 		     (eq (forward-line -1) 0))
 	   (if (setq p (idlwave-look-at "\\<\\$")) (throw 'loop p))))))))
 
@@ -2370,7 +2314,8 @@ Blank or comment-only lines following regular continuation lines (with
 (defun idlwave-quoted ()
   "Return t if point is in a comment or quoted string.
 Returns nil otherwise."
-  (or (idlwave-in-comment) (idlwave-in-quote)))
+  ;; 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
@@ -2386,7 +2331,7 @@ constants - a double quote followed by an octal digit."
     ;; 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 (progn (end-of-line) (point)))
+           (eol (line-end-position))
            (bq (progn (beginning-of-line) (point)))
            (endq (point))
            (data (match-data))
@@ -2431,7 +2376,8 @@ constants - a double quote followed by an octal digit."
    (save-excursion
      (forward-char)
      (re-search-backward (concat "\\(" idlwave-idl-keywords
-                                 "\\|[[(*+-/=,^><]\\)\\s-*\\*") limit t))))
+                                 "\\|[-[(*+/=,^><]\\)\\s-*\\*")
+                         limit t))))
 
 (defun idlwave-in-comment ()
   "Return t if point is inside a comment, nil otherwise."
@@ -2467,8 +2413,8 @@ constants - a double quote followed by an octal digit."
       (mapc (lambda (name)
 	      (if (file-directory-p (concat dir "/" name)) ;directory
 		  (when (not (string= (substring name 0 1) "."))
-		    (setq found 
-			  (idlwave-recursive-find-file 
+		    (setq found
+			  (idlwave-recursive-find-file
 			   (concat dir "/" name) file))
 		    (if found (throw 'found found)))
 		(if (string= name file)
@@ -2502,20 +2448,13 @@ constants - a double quote followed by an octal digit."
       (when (file-directory-p dir)
 	(setq files (nreverse (directory-files dir t "[^.]")))
 	(while (setq file (pop files))
-	  (if (file-directory-p file) 
+	  (if (file-directory-p file)
 	      (push (file-name-as-directory file) path)))
 	(push dir path1)))
     path1))
 
-(defun idlwave-get-buffer-visiting (file)
-  ;; Return the buffer currently visiting FILE
-  (cond
-   ((boundp 'find-file-compare-truenames) ; XEmacs
-    (let ((find-file-compare-truenames t))
-      (get-file-buffer file)))
-   ((fboundp 'find-buffer-visiting)       ; Emacs
-    (find-buffer-visiting file))
-   (t (error "This should not happen (idlwave-get-buffer-visiting)"))))
+(define-obsolete-function-alias 'idlwave-get-buffer-visiting
+  #'find-buffer-visiting "28.1")
 
 ;;----------------------------------------------------
 ;;  Utility: string
@@ -2558,9 +2497,8 @@ If PATTERN is omitted, it defaults to \"[ \\f\\t\\n\\r\\v]+\"."
 
 (defun idlwave-local-value (var &optional buffer)
   "Return the value of VAR in BUFFER, but only if VAR is local to BUFFER."
-  (with-current-buffer (or buffer (current-buffer))
-    (and (local-variable-p var (current-buffer))
-	 (symbol-value var))))
+  (when (local-variable-p var buffer)
+    (buffer-local-value var (or buffer (current-buffer)))))
 
 (defun idlwave-members-only (list club)
   "Return list of all elements in LIST which are also in CLUB."
@@ -2581,26 +2519,18 @@ If PATTERN is omitted, it defaults to \"[ \\f\\t\\n\\r\\v]+\"."
       (setq list (cdr list)))
     (nreverse rtn)))
 
-(defun idlwave-uniquify (list)
-  (let ((ht (make-hash-table :size (length list) :test 'equal)))
-    (delq nil 
-	  (mapcar (lambda (x)
-		    (unless (gethash x ht) 
-		      (puthash x t ht)
-		      x))
-		  list))))
+(define-obsolete-function-alias 'idlwave-uniquify #'seq-uniq "28.1")
 
 (defun idlwave-count-eq (elt list)
   "How often is ELT in LIST?"
-  (length (delq nil (mapcar (lambda (x) (eq x elt)) 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?"
-  (length (delq nil (mapcar (lambda (x) (eq (car x) elt)) alist))))
+  (seq-count (lambda (x) (eq (car x) elt)) alist))
 
-(defmacro idlwave-xor (a b)
-  `(and (or ,a ,b)
-	(not (and ,a ,b))))
+(define-obsolete-function-alias 'idlwave-xor #'xor "27.1")
 
 (defun idlwave-all-assq (key list)
   "Return a list of all associations of Key in LIST."
@@ -2639,7 +2569,7 @@ If PATTERN is omitted, it defaults to \"[ \\f\\t\\n\\r\\v]+\"."
 (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 
+  (cond
    ((null file) nil)
    ((file-name-absolute-p file) file)
    (t (idlwave-locate-lib-file file))))
@@ -2647,11 +2577,7 @@ If PATTERN is omitted, it defaults to \"[ \\f\\t\\n\\r\\v]+\"."
 ;;----------------------------------------------------
 ;; Utility: misc
 
-(defun idlwave-region-active-p ()
-  "Should we operate on an active region?"
-  (if (fboundp 'use-region-p)
-      (use-region-p)
-    (region-active-p)))
+(define-obsolete-function-alias 'idlwave-region-active-p #'use-region-p "23.1")
 
 (defun idlwave-hard-tab ()
   "Insert TAB in buffer in current position."
@@ -2675,7 +2601,7 @@ If successful, leaves point after the match, otherwise, does not move point."
 	       (if cont (idlwave-end-of-statement) (end-of-line))
 	       (point)))
         found)
-    (idlwave-with-special-syntax
+    (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))))
@@ -2701,19 +2627,19 @@ force class query for object methods."
 	 (this-buffer (equal arg '(4)))
 	 (module (idlwave-fix-module-if-obj_new (idlwave-what-module)))
 	 (default (if module
-		      (concat (idlwave-make-full-name 
+		      (concat (idlwave-make-full-name
 			       (nth 2 module) (car module))
 			      (if (eq (nth 1 module) 'pro) "<p>" "<f>"))
 		    "none"))
-	 (list 
-	  (idlwave-uniquify
+	 (list
+	  (seq-uniq
 	   (delq nil
-		 (mapcar (lambda (x) 
+		 (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 
+			      (concat (idlwave-make-full-name
 				       (nth 2 x) (car x))
 				      (if (eq (nth 1 x) 'pro) "<p>" "<f>")))))
 			 (if this-buffer
@@ -2722,8 +2648,8 @@ force class query for object methods."
 	 (name (idlwave-completing-read
 		(if (or (not this-buffer)
 			(assoc default list))
-		    (format "Module (Default %s): " default)
-		  (format "Module in this file: "))
+		    (format-prompt "Module" default)
+		  "Module in this file: ")
 		list))
 	 type class)
     (if (string-match "\\`\\s-*\\'" name)
@@ -2742,10 +2668,10 @@ force class query for object methods."
 		     (t t)))
     (idlwave-do-find-module name type class nil this-buffer)))
 
-(defun idlwave-do-find-module (name type class 
+(defun idlwave-do-find-module (name type class
 				    &optional force-source this-buffer)
   (let ((name1 (idlwave-make-full-name class name))
-	source buf1 entry 
+	source buf1 entry
 	(buf (current-buffer))
 	(pos (point))
 	file name2)
@@ -2755,11 +2681,11 @@ force class query for object methods."
 	  name2 (if (nth 2 entry)
 		    (idlwave-make-full-name (nth 2 entry) name)
 		  name1))
-    (if source	
+    (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 
+      (setq file
+	    (idlwave-expand-lib-file-name
 	     (if class
 		 (format "%s__define.pro" (downcase class))
 	       (format "%s.pro" (downcase name))))))
@@ -2767,14 +2693,14 @@ force class query for object methods."
      ((or (null name) (equal name ""))
       (error "Abort"))
      ((eq (car source) 'system)
-      (error "Source code for system routine %s is not available" 
+      (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 
+	(setq buf1
 	      (idlwave-find-file-noselect file 'find))
 	(pop-to-buffer buf1 t))
       (goto-char (point-max))
@@ -2784,7 +2710,7 @@ force class query for object methods."
 		     (cond ((eq type 'fun) "function")
 			   ((eq type 'pro) "pro")
 			   (t "\\(pro\\|function\\)"))
-		     "\\>[ \t]+" 
+		     "\\>[ \t]+"
 		     (regexp-quote (downcase name2))
 		     "[^a-zA-Z0-9_$]")
 	     nil t)
@@ -2839,13 +2765,10 @@ the routine definition itself."
       (select-window olh-window)
       (idlwave-help-quit))
     (when (window-live-p ri-window)
-      (delete-window ri-window))))
+      (quit-window nil ri-window))))
 
 ;;----------------------------------------------------
-;; Widget/Interaction 
-
-(defun idlwave-pset (item)
-  (set 'rtn item)) ;; dynamically scoped
+;; Widget/Interaction
 
 (defun idlwave-popup-select (ev list title &optional sort)
   "Select an item in LIST with a popup menu.
@@ -2856,54 +2779,21 @@ sort the list before displaying."
     (cond ((null list))
 	  ((= 1 (length list))
 	   (setq rtn (car list)))
-	  ((featurep 'xemacs)
-	   (if sort (setq list (sort list (lambda (a b) 
-					    (string< (upcase a) (upcase b))))))
-	   (setq menu
-		 (append (list title)
-			 (mapcar (lambda (x) (vector x (list 'idlwave-pset
-							     x)))
-				 list)))
-	   (setq menu (idlwave-split-menu-xemacs menu maxpopup))
-	   (let ((resp (get-popup-menu-response menu)))
-             (funcall (event-function resp) (event-object resp))))
 	  (t
-	   (if sort (setq list (sort list (lambda (a b) 
+	   (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-emacs menu maxpopup))
+	   (setq menu (idlwave-split-menu menu maxpopup))
 	   (setq rtn (x-popup-menu ev menu))))
     rtn))
 
-(defun idlwave-split-menu-xemacs (menu N)
-  "Split the MENU into submenus of maximum length N."
-  (if (<= (length menu) (1+ N))
-      ;; No splitting needed
-      menu
-    (let* ((title (car menu))
-	   (entries (cdr menu))
-	   (menu (list title))
-	   (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))
-	(setq nextmenu (cons (format "%s...%s"
-				     (aref (car nextmenu) 0)
-				     (aref (nth (1- cnt) nextmenu) 0))
-			     nextmenu))
-	(setq menu (cons nextmenu menu)
-	      nextmenu nil
-	      cnt 0))
-      (nreverse menu))))
+(define-obsolete-function-alias 'idlwave-split-menu-emacs
+  #'idlwave-split-menu "28.1")
 
-(defun idlwave-split-menu-emacs (menu N)
+(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
@@ -2942,8 +2832,7 @@ 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 (if (fboundp 'fit-window-to-buffer)
-				    '(fit-window-to-buffer)))
+         (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)))
@@ -2955,15 +2844,14 @@ If these don't exist, a letter in the string is automatically selected."
     ;; Display prompt and wait for quick reply
     (message "%s[%s]" prompt
              (mapconcat (lambda(x) (char-to-string (car x)))
-                        keys-alist ""))
+                        keys-alist))
     (if (sit-for delay)
         ;; No quick reply: Show help
         (save-window-excursion
           (with-output-to-temp-buffer "*Completions*"
-            (mapcar (lambda(x)
-                      (princ (nth 1 x))
-                      (princ "\n"))
-                    keys-alist))            
+	    (dolist (x keys-alist)
+	      (princ (nth 1 x))
+	      (princ "\n")))
           (setq char (read-char)))
       (setq char (read-char)))
     (message nil)
@@ -3028,7 +2916,7 @@ 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 (idlwave-get-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)))
@@ -3064,8 +2952,8 @@ Buffers containing unsaved changes require confirmation before they are killed."
 (defun idlwave-count-outlawed-buffers (tag)
   "How many outlawed buffers have tag TAG?"
   (length (delq nil
-		(mapcar 
-		 (lambda (x) (eq (cdr x) tag)) 
+		(mapcar
+		 (lambda (x) (eq (cdr x) tag))
 		 idlwave-outlawed-buffers))))
 
 (defun idlwave-do-kill-autoloaded-buffers (&rest reasons)
@@ -3078,10 +2966,10 @@ Buffers containing unsaved changes require confirmation before they are killed."
 	  (and (or (memq t reasons)
 		   (memq (cdr entry) reasons))
 	       (kill-buffer (car entry))
-	       (incf cnt)
-	       (setq idlwave-outlawed-buffers 
+	       (cl-incf cnt)
+	       (setq idlwave-outlawed-buffers
 		     (delq entry idlwave-outlawed-buffers)))
-	(setq idlwave-outlawed-buffers 
+	(setq idlwave-outlawed-buffers
 	      (delq entry idlwave-outlawed-buffers))))
     (message "%d buffer%s killed" cnt (if (= cnt 1) "" "s"))))
 
@@ -3093,10 +2981,10 @@ Intended for `after-save-hook'."
 	 (entry (assq buf idlwave-outlawed-buffers)))
     ;; Revoke license
     (if entry
-	(setq idlwave-outlawed-buffers 
+	(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)))
+    (remove-hook 'after-save-hook #'idlwave-revoke-license-to-kill 'local)))
 
 ;;----------------------------------------------------
 ;; Statement templates
@@ -3114,8 +3002,8 @@ expression to enter.
 
 The lines containing S1 and S2 are reindented using `indent-region'
 unless the optional second argument NOINDENT is non-nil."
-  (if (eq major-mode 'idlwave-shell-mode)
-      ;; This is a gross hack to avoit template abbrev expansion
+  (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)))
@@ -3125,7 +3013,7 @@ unless the optional second argument NOINDENT is non-nil."
 	   (setq s1 (downcase s1) s2 (downcase s2)))
 	  (idlwave-abbrev-change-case
 	   (setq s1 (upcase s1) s2 (upcase s2))))
-    (let ((beg (save-excursion (beginning-of-line) (point)))
+    (let ((beg (line-beginning-position))
 	  end)
       (if (not (looking-at "\\s-*\n"))
 	  (open-line 1))
@@ -3155,7 +3043,7 @@ unless the optional second argument NOINDENT is non-nil."
 (defun idlwave-case ()
   "Build skeleton IDL case statement."
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "case")
    (idlwave-rw-case " of\n\nendcase")
    "Selector expression"))
@@ -3163,7 +3051,7 @@ unless the optional second argument NOINDENT is non-nil."
 (defun idlwave-switch ()
   "Build skeleton IDL switch statement."
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "switch")
    (idlwave-rw-case " of\n\nendswitch")
    "Selector expression"))
@@ -3171,7 +3059,7 @@ unless the optional second argument NOINDENT is non-nil."
 (defun idlwave-for ()
   "Build skeleton IDL for loop statement."
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "for")
    (idlwave-rw-case " do begin\n\nendfor")
    "Loop expression"))
@@ -3179,7 +3067,7 @@ unless the optional second argument NOINDENT is non-nil."
 (defun idlwave-foreach ()
   "Build skeleton IDL for loop statement."
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "foreach")
    (idlwave-rw-case " do begin\n\nendforeach")
    "Loop expression"))
@@ -3194,14 +3082,14 @@ unless the optional second argument NOINDENT is non-nil."
 
 (defun idlwave-procedure ()
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "pro")
    (idlwave-rw-case "\n\nreturn\nend")
    "Procedure name"))
 
 (defun idlwave-function ()
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "function")
    (idlwave-rw-case "\n\nreturn\nend")
    "Function name"))
@@ -3215,7 +3103,7 @@ unless the optional second argument NOINDENT is non-nil."
 
 (defun idlwave-while ()
   (interactive)
-  (idlwave-template 
+  (idlwave-template
    (idlwave-rw-case "while")
    (idlwave-rw-case " do begin\n\nendwhile")
    "Entry condition"))
@@ -3261,39 +3149,33 @@ unless the optional second argument NOINDENT is non-nil."
 (defun idlwave-reset-sintern (&optional what)
   "Reset all sintern hashes."
   ;; Make sure the hash functions are accessible.
-  (unless (and (fboundp 'gethash)
-               (fboundp 'puthash))
-    (require 'cl)
-    (or (fboundp 'puthash)
-        (defalias 'puthash 'cl-puthash)))
   (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
-    (loop for entry in entries
-	  for var = (car entry)
-	  do (if (not (consp (symbol-value var))) (set var (list nil))))
+    (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)))
-      (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)))
+      (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)))
-      (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))))))
-
+      (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)
@@ -3327,11 +3209,10 @@ unless the optional second argument NOINDENT is non-nil."
 	(set (idlwave-sintern-set name 'class idlwave-sint-classes set))
 	(name)))
 
-(defun idlwave-sintern-dir (dir &optional set)
+(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)
+(defun idlwave-sintern-libname (name &optional _set)
   (car (or (member name idlwave-sint-libnames)
 	   (setq idlwave-sint-libnames (cons name idlwave-sint-libnames)))))
 
@@ -3344,7 +3225,7 @@ unless the optional second argument NOINDENT is non-nil."
     iname))
 
 (defun idlwave-sintern-keyword-list (kwd-list &optional set)
-  "Sintern a set of keywords (file (key . link) (key2 . link2) ...)"
+  "Sintern a set of keywords (file (key . link) (key2 . link2) ...)."
   (mapc (lambda(x)
 	  (setcar x (idlwave-sintern-keyword (car x) set)))
 	(cdr kwd-list))
@@ -3373,11 +3254,11 @@ the base of the directory."
 	    (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  
+	    (source-dir  (if default-dir
 			     (file-name-as-directory default-dir)
 			   (nth 2 source)))
 	    (source-lib (nth 3 source)))
@@ -3386,7 +3267,7 @@ the base of the directory."
 	(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))
@@ -3411,30 +3292,12 @@ the base of the directory."
       (setcar entry (idlwave-sintern-sysvar (car entry) 'set))
       (setq tags (assq 'tags entry))
       (if tags
-	  (setcdr tags 
-		  (mapcar (lambda (x) 
+	  (setcdr tags
+		  (mapcar (lambda (x)
 			    (cons (idlwave-sintern-sysvartag (car x) 'set)
 				  (cdr x)))
 			  (cdr tags)))))))
 
-(defun 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))))
-    (set var nil) ; initial value of the association list
-    (fset func    ; set the function
-	  `(lambda (name &optional set)
-	     (cond ((not (stringp name)) name)
-		   ((cdr (assoc (downcase name) ,var)))
-		   (set
-		    (setq ,var (cons (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))
diff --git a/idlwave.texi b/idlwave.texi
index 1b79e38fbc..cef0ac3604 100644
--- a/idlwave.texi
+++ b/idlwave.texi
@@ -1,10 +1,11 @@
 \input texinfo  @c -*-texinfo-*-
 @c %**start of header
-@setfilename idlwave
+@setfilename idlwave.info
 @settitle IDLWAVE User Manual
-@dircategory Emacs
+@c @include docstyle.texi @C FIXME: This was added on the Emacs side
+@dircategory Emacs editing modes
 @direntry
-* IDLWAVE: (idlwave).	Major mode and shell for IDL files.
+* IDLWAVE: (idlwave).           Major mode and shell for IDL files.
 @end direntry
 @synindex ky cp
 @syncodeindex vr cp
@@ -20,20 +21,19 @@
 @c %**end of header
 @finalout
 
-@ifinfo 
+@ifinfo
 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, 2000, 2001, 2002, 2003, 2004, 2005, 
-          2006, 2007, 2009, 2013, 2014 Free Software Foundation, Inc.
+Copyright @copyright{} 1999--2024 Free Software Foundation, Inc.
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.2 or
 any later version published by the Free Software Foundation; with no
-Invariant Sections, with the Front-Cover texts being ``A GNU
+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'' in the Emacs manual.
@@ -58,7 +58,7 @@ license to the document, as described in section 6 of the license.
 This is edition @value{EDITION} of the @cite{IDLWAVE User Manual} for
 IDLWAVE version @value{VERSION}, @value{DATE}.
 @sp 2
-Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004, 2005, 
+Copyright @copyright{} 1999, 2000, 2001, 2002, 2003, 2004, 2005,
           2006, 2007, 2009, 2013, 2014 Free Software Foundation, Inc.
 @sp 2
 @cindex Copyright, of IDLWAVE
@@ -84,12 +84,11 @@ license to the document, as described in section 6 of the license.
 @page
 
 @ifnottex
-
-@node Top, Introduction, (dir), (dir)
+@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.
-
 @end ifnottex
 
 @menu
@@ -97,25 +96,24 @@ Interactive Data Language (IDL), and running IDL as an inferior shell.
 * 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::           
-* Installation::                How to Install or Upgrade               
-* Acknowledgements::            
-* Sources of Routine Info::     How does IDLWAVE know about routine XYZ     
-* HTML Help Browser Tips::      
+* The IDLWAVE Shell::
+* Installation::                How to Install or Upgrade
+* Acknowledgments::
+* 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
+* Windows and macOS::           What still works, and how
 * Troubleshooting::             When good computers turn bad
-* GNU Free Documentation License::  The license for this documentation.
+* 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::  
+* Lesson I---Development Cycle::
+* Lesson II---Customization::
+* Lesson III---User Catalog::
 
 The IDLWAVE Major Mode
 
@@ -135,7 +133,7 @@ The IDLWAVE Major Mode
 Code Formatting
 
 * Code Indentation::            Reflecting the logical structure
-* Continued Statement Indentation::  
+* Continued Statement Indentation::
 * Comment Indentation::         Special indentation for comment lines
 * Continuation Lines::          Splitting statements over lines
 * Syntax Highlighting::         Font-lock support
@@ -143,41 +141,41 @@ Code Formatting
 
 Online Help
 
-* Help with HTML Documentation::  
-* Help with Source::            
+* 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::  
+* 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 `=' etc
+* 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
-* Multi-Line Commands::         
-* Commands Sent to the Shell::  
-* Debugging IDL Programs::      
-* Examining Variables::         
-* Custom Expression Examination::  
+* Multi-Line Commands::
+* 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::         
+* A Tale of Two Modes::
+* Debug Key Bindings::
+* Breakpoints and Stepping::
+* Compiling Programs::
+* Walking the Calling Stack::
+* Electric Debug Mode::
 
 Installation
 
@@ -188,25 +186,25 @@ Sources of Routine Info
 
 * Routine Definitions::         Where IDL Routines are defined.
 * Routine Information Sources::  So how does IDLWAVE know about...
-* Catalogs::                    
+* Catalogs::
 * Load-Path Shadows::           Routines defined in several places
 * Documentation Scan::          Scanning the IDL Manuals
 
 Catalogs
 
-* Library Catalogs::            
-* User Catalog::                
+* Library Catalogs::
+* User Catalog::
 
 @end detailmenu
 @end menu
 
-@node Introduction, IDLWAVE in a Nutshell, Top, Top
+@node Introduction
 @chapter Introduction
 @cindex Introduction
 @cindex CORBA (Common Object Request Broker Architecture)
 @cindex Interface Definition Language
 @cindex Interactive Data Language
-@cindex cc-mode.el
+@cindex @file{cc-mode.el}
 @cindex @file{idl.el}
 @cindex @file{idl-shell.el}
 @cindex Feature overview
@@ -229,13 +227,13 @@ form a complete development environment. Here is a brief summary of
 what IDLWAVE does:
 
 @itemize @bullet
-@item 
+@item
 Smart code indentation and automatic-formatting.
 @item
 Three level syntax highlighting support.
-@item 
+@item
 Context-sensitive display of calling sequences and keywords for more
-than 1000 native IDL routines, extendible to any additional number of
+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
@@ -253,7 +251,7 @@ Integrity checks and auto-termination of logical blocks.
 @item
 Routine name space conflict search with likelihood-of-use ranking.
 @item
-Support for @file{imenu} (Emacs) and @file{func-menu} (XEmacs).
+Support for @file{imenu}.
 @item
 Documentation support.
 @item
@@ -275,24 +273,27 @@ Examining variables and expressions with a mouse click.
 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{http://idlwave.org/screenshots/emacs_21_nav.gif,An IDLWAVE buffer}
+@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_nav.gif,An IDLWAVE buffer}
 @item
-@uref{http://idlwave.org/screenshots/emacs_21_keys.gif,A keyword being completed}
+@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_keys.gif,A keyword being completed}
 @item
-@uref{http://idlwave.org/screenshots/emacs_21_help.gif,Online help text.}
+@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_help.gif,Online help text.}
 @item
-@uref{http://idlwave.org/screenshots/emacs_21_ri.gif,Routine information displayed}
+@uref{https://github.com/jdtsmith/idlwave/screenshots/emacs_21_ri.gif,Routine information displayed}
 @item
-@uref{http://idlwave.org/screenshots/emacs_21_bp.gif,Debugging code
+@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
@@ -300,7 +301,7 @@ 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
+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
@@ -308,7 +309,7 @@ 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, Getting Started, Introduction, Top
+@node IDLWAVE in a Nutshell
 @chapter IDLWAVE in a Nutshell
 @cindex Summary of important commands
 @cindex IDLWAVE in a Nutshell
@@ -402,30 +403,30 @@ at point.
 <A NAME="TUTORIAL"></A>
 @end html
 
-@node Getting Started, The IDLWAVE Major Mode, IDLWAVE in a Nutshell, Top
+@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::  
+* Lesson I---Development Cycle::
+* Lesson II---Customization::
+* Lesson III---User Catalog::
 @end menu
 
-@node  Lesson I -- Development Cycle, Lesson II -- Customization, Getting Started, Getting Started
+@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
+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 or XEmacs with the full
+It is assumed that you have access to Emacs with the full
 IDLWAVE package including online help (@pxref{Installation}).  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}
@@ -455,13 +456,13 @@ function daynr,d,m,y
   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)
@@ -481,12 +482,12 @@ buffer with @kbd{C-x h}, and indent the whole region with
 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
+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
+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
@@ -501,7 +502,7 @@ 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
+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
@@ -535,14 +536,14 @@ plot_wday,1,1
 @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
+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
+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
@@ -558,7 +559,7 @@ 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?
+Let's try a different day.  How about April fool's day?
 
 @example
 plot_wday,1,4
@@ -589,14 +590,14 @@ 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, Lesson III -- User Catalog, Lesson I -- Development Cycle, Getting Started
+@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
+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
@@ -628,7 +629,7 @@ slightly from the margin and use only 3 spaces as indentation between
 
 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 likings.  If
+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:}
@@ -639,10 +640,10 @@ 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
+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
+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.
 
@@ -673,7 +674,7 @@ breakpoints (try it, it's easier).  You can enable this with:
 
 @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.
+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
@@ -699,14 +700,14 @@ endless.  Here we set function keys f4-f8 to common debugging commands.
     (local-set-key [f8] 'idlwave-shell-clear-all-bp)))
 @end lisp
 
-@node  Lesson III -- User Catalog,  , Lesson II -- Customization, Getting Started
+@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 JHUPL
+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
@@ -722,13 +723,13 @@ 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
+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{.idlwave/idlusercat.el} in your home
-directory and will from now on automatically load whenever you use
-IDLWAVE.  You may find it necessary to rebuild the catalog on occasion
+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
@@ -736,13 +737,13 @@ be located in the library.  E.g., if you have scanned the IDL-Astro
 library:
 
 @example
-    a=readf <at> key{M-@key{TAB}}
+    a=readf <at> kbd{M-@key{TAB}}
 @end example
 
-expands to `readfits('.  Then try
+expands to ``readfits(''.  Then try
 
 @example
-    a=readfits(@key{C-c ?}
+    a=readfits(@kbd{C-c ?}
 @end example
 
 and you get:
@@ -752,14 +753,14 @@ Usage:    Result = READFITS(filename, header, heap)
 ...
 @end example
 
-I hope you made it until here.  Now you are set to work with IDLWAVE.
+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, The IDLWAVE Shell, Getting Started, Top
+@node The IDLWAVE Major Mode
 @chapter The IDLWAVE Major Mode
 @cindex IDLWAVE major mode
 @cindex Major mode, @code{idlwave-mode}
@@ -783,14 +784,14 @@ them.
 * Misc Options::                Things that fit nowhere else
 @end menu
 
-@node Code Formatting, Routine Info, The IDLWAVE Major Mode, The IDLWAVE Major Mode
+@node Code Formatting
 @section Code Formatting
 @cindex Code formatting
 @cindex Formatting, of code
 
 @menu
 * Code Indentation::            Reflecting the logical structure
-* Continued Statement Indentation::  
+* Continued Statement Indentation::
 * Comment Indentation::         Special indentation for comment lines
 * Continuation Lines::          Splitting statements over lines
 * Syntax Highlighting::         Font-lock support
@@ -811,7 +812,7 @@ it to match your coding standards, you can rely on it to help keep your
 code neat and organized.
 
 
-@node Code Indentation, Continued Statement Indentation, Code Formatting, Code Formatting
+@node Code Indentation
 @subsection Code Indentation
 @cindex Code indentation
 @cindex Indentation
@@ -826,7 +827,7 @@ 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
+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
@@ -834,7 +835,7 @@ 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}) 
+@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.
@@ -851,7 +852,7 @@ Extra indentation applied to block END lines.  A value equal to negative
 BEGIN lines.
 @end defopt
 
-@node Continued Statement Indentation, Comment Indentation, Code Indentation, Code Formatting
+@node Continued Statement Indentation
 @subsection Continued Statement Indentation
 @cindex Indentation, continued statement
 @cindex Continued statement indentation
@@ -925,7 +926,7 @@ parenthesis, regardless of whether the
 @code{idlwave-max-extra-continuation-indent} limit is satisfied.
 @end defopt
 
-@node Comment Indentation, Continuation Lines, Continued Statement Indentation, Code Formatting
+@node Comment Indentation
 @subsection Comment Indentation
 @cindex Comment indentation
 @cindex Hanging paragraphs
@@ -962,14 +963,14 @@ A comment that starts with this regexp is indented as if it is a part of
 IDL code.
 @end defopt
 
-@node Continuation Lines, Syntax Highlighting, Comment Indentation, Code Formatting
+@node Continuation Lines
 @subsection Continuation Lines and Filling
 @cindex Continuation lines
 @cindex Line splitting
 @cindex String splitting
 @cindex Splitting, of lines
 
-@kindex M-@key{RET}
+@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}.
@@ -1035,19 +1036,19 @@ in the first line of a comment paragraph.
 
 @defopt idlwave-use-last-hang-indent (@code{nil})
 Non-@code{nil} means use last match on line for
-@code{idlwave-indent-regexp}. 
+@code{idlwave-indent-regexp}.
 @end defopt
 
-@node Syntax Highlighting, Octals and Highlighting, Continuation Lines, Code Formatting
+@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}
-(in Emacs), or have @code{font-lock} turned on in any other buffer in
-XEmacs, it should also automatically work in IDLWAVE buffers.  If you'd
+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}:
 
@@ -1063,10 +1064,10 @@ for highlighting using the variable
 
 @defopt idlwave-default-font-lock-items
 Items which should be fontified on the default fontification level
-2. 
+2.
 @end defopt
 
-@node Octals and Highlighting,  , Syntax Highlighting, Code Formatting
+@node Octals and Highlighting
 @subsection Octals and Highlighting
 @cindex Syntax highlighting, Octals
 @cindex Highlighting of syntax, Octals
@@ -1094,9 +1095,9 @@ altogether, and use the more sensible alternative IDL provides:
 @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}.
+consistent with the notation for hexadecimal numbers, e.g., @code{'C5'XB}.
 
-@node Routine Info, Online Help, Code Formatting, The IDLWAVE Major Mode
+@node Routine Info
 @section Routine Info
 @cindex Routine info
 @cindex Updating routine info
@@ -1141,14 +1142,14 @@ plot,x,alog(x+5*sin(x) + 2),
 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.  
+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}).
+(e.g., @code{a->myclass::Foo}).
 
 @cindex Calling sequences
 @cindex Keywords of a routine
@@ -1199,13 +1200,13 @@ will automatically split into the next two.
 @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 
+@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
+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}.
 
@@ -1235,7 +1236,7 @@ with the middle mouse button inserts keywords or visits files:
 @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}).  
+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}
@@ -1274,7 +1275,7 @@ Maximum number of source files displayed in the Routine Info window.
 @html
 <A NAME="ONLINE_HELP"></A>
 @end html
-@node Online Help, Completion, Routine Info, The IDLWAVE Major Mode
+@node Online Help
 @section Online Help
 
 @cindex Online Help
@@ -1285,11 +1286,11 @@ Maximum number of source files displayed in the Routine Info window.
 @cindex Speed, of online help
 @cindex XML Help Catalog
 
-For IDL system routines, extensive documentation is supplied with IDL.
+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 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
+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
@@ -1298,20 +1299,20 @@ 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{~/.idlwave/}, by default).  It also re-scans the XML catalog if
+(@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. 
+information is supplied with IDL versions 6.2 and later.
 
 @cindex Eclipse-based help
 Starting with IDL 7.0, the HTML help system and associated IDL Assistant
 tool was dropped for an Eclipse-based help system, without access to the
 documentation mediated via the @samp{idlhelp} tool.  In IDL 7.1, this
-access was restored.  
+access was restored.
 
 There are a variety of options for displaying the HTML help: see below.
 Help for routines without HTML documentation is also available, by using
@@ -1320,7 +1321,7 @@ 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
+@kbd{S-mouse-3} to access context sensitive online help.  The following
 locations are recognized context for help:
 
 @cindex Context, for online help
@@ -1366,14 +1367,14 @@ 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
+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
+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).
+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
@@ -1382,11 +1383,11 @@ directly in the originating source file.
 
 
 @menu
-* Help with HTML Documentation::  
-* Help with Source::            
+* Help with HTML Documentation::
+* Help with Source::
 @end menu
 
-@node Help with HTML Documentation, Help with Source, Online Help, Online Help
+@node Help with HTML Documentation
 @subsection Help with HTML Documentation
 @cindex HTML Help
 @cindex Help using HTML manuals
@@ -1417,10 +1418,9 @@ among, with differing advantages and disadvantages.  The variable
 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
-@code{w3} (bundled with many versions of Emacs) and @code{w3m}
-(@uref{http://emacs-w3m.namazu.org/}) are run within Emacs, and use
-Emacs buffers to display the HTML help.  This can be convenient,
+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
@@ -1441,7 +1441,7 @@ configuring a browser for use with IDL's HTML help system.
 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     
+@end defopt
 
 @defopt idlwave-html-help-location @file{/usr/local/etc/}
 The directory where the @file{idl_html_help} HTML directory live.
@@ -1471,7 +1471,7 @@ contains "-w3".
 The face for links to IDLWAVE online help.
 @end defopt
 
-@node Help with Source,  , Help with HTML Documentation, Online Help
+@node Help with Source
 @subsection Help with Source
 @cindex Help using routine source
 
@@ -1549,7 +1549,7 @@ displaying source file.
 
 @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\\)"}.
+@emph{name} section.  Can be a regexp, e.g., @code{"\\(name\\|nom\\)"}.
 @end defopt
 
 @defopt idlwave-help-doclib-keyword (@code{"KEYWORD"})
@@ -1558,7 +1558,7 @@ The case-insensitive heading word in doclib headers to locate the
 @end defopt
 
 
-@node Completion, Routine Source, Online Help, The IDLWAVE Major Mode
+@node Completion
 @section Completion
 @cindex Completion
 @cindex Keyword completion
@@ -1568,13 +1568,13 @@ The case-insensitive heading word in doclib headers to locate the
 @cindex Function name completion
 @cindex Procedure name completion
 
-@kindex M-@key{TAB}
+@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
+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}).
 
@@ -1622,15 +1622,15 @@ search for a procedure matching a regexp.
 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
+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
+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, cancelling
-@cindex Cancelling completion
-Completion is not a blocking operation --- you are free to continue
+@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
@@ -1644,7 +1644,7 @@ completed keywords.
 
 @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
+completed function.  A value of 2 means also add the closing
 parenthesis and position the cursor between the two.
 @end defopt
 
@@ -1661,12 +1661,12 @@ available.
 @menu
 * Case of Completed Words::     CaseOFcomPletedWords
 * Object Method Completion and Class Ambiguity::  obj->Method, what?
-* Object Method Completion in the Shell::  
+* 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, Object Method Completion and Class Ambiguity, Completion, Completion
+@node  Case of Completed Words
 @subsection Case of Completed Words
 @cindex Case of completed words
 @cindex Mixed case completion
@@ -1693,7 +1693,7 @@ of completed words.
 
 @defopt idlwave-completion-force-default-case (@code{nil})
 Non-@code{nil} means completion will always honor the settings in
-@code{idlwave-completion-case}.  When nil (the default), entirely lower
+@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
@@ -1703,7 +1703,7 @@ Non-@code{nil} means the empty string is considered lower case for
 completion.
 @end defopt
 
-@node  Object Method Completion and Class Ambiguity, Object Method Completion in the Shell, Case of Completed Words, Completion
+@node  Object Method Completion and Class Ambiguity
 @subsection Object Method Completion and Class Ambiguity
 @cindex Object methods
 @cindex Class ambiguity
@@ -1729,14 +1729,14 @@ 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}).  
+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
+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
+(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
@@ -1766,7 +1766,7 @@ Face to highlight object operator arrows @samp{->} which carry a saved
 class text property.
 @end defopt
 
-@node Object Method Completion in the Shell, Class and Keyword Inheritance, Object Method Completion and Class Ambiguity, Completion
+@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
@@ -1777,15 +1777,15 @@ 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). 
+be used (as in the buffer).
 
-@node   Class and Keyword Inheritance, Structure Tag Completion, Object Method Completion in the Shell, Completion
+@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
+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
@@ -1820,18 +1820,18 @@ keywords based on their originating class.
 Non-@code{nil} means consider inheritance during completion, online help etc.
 @end defopt
 
-@defopt idlwave-keyword-class-inheritance 
+@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,  , Class and Keyword Inheritance, Completion
+@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
+(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}).  Tag
@@ -1841,7 +1841,7 @@ 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
+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 enabled by default.  You'll also be able to
@@ -1863,7 +1863,7 @@ shell.
 @end defopt
 
 
-@node Routine Source, Resolving Routines, Completion, The IDLWAVE Major Mode
+@node Routine Source
 @section Routine Source
 @cindex Routine source file
 @cindex Module source file
@@ -1889,7 +1889,7 @@ 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, Code Templates, Routine Source, The IDLWAVE Major Mode
+@node Resolving Routines
 @section Resolving Routines
 @cindex @code{RESOLVE_ROUTINE}
 @cindex Compiling library modules
@@ -1910,7 +1910,7 @@ 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, Abbreviations, Resolving Routines, The IDLWAVE Major Mode
+@node Code Templates
 @section Code Templates
 @cindex Code templates
 @cindex Templates
@@ -1932,7 +1932,7 @@ templates, this is done with direct key bindings:
 All code templates are also available as abbreviations
 (@pxref{Abbreviations}).
 
-@node Abbreviations, Actions, Code Templates, The IDLWAVE Major Mode
+@node Abbreviations
 @section Abbreviations
 @cindex Abbreviations
 
@@ -1943,7 +1943,7 @@ 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 ---
+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
@@ -2114,11 +2114,11 @@ 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
+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, Doc Header, Abbreviations, The IDLWAVE Major Mode
+@node Actions
 @section Actions
 @cindex Actions
 @cindex Coding standards, enforcing
@@ -2147,7 +2147,7 @@ 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
+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
@@ -2162,11 +2162,11 @@ settings are described below and set separately.
 
 @menu
 * Block Boundary Check::        Is the END statement correct?
-* Padding Operators::           Enforcing space around `=' etc
+* Padding Operators::           Enforcing space around @samp{=} etc
 * Case Changes::                Enforcing upper case keywords
 @end menu
 
-@node Block Boundary Check, Padding Operators, Actions, Actions
+@node Block Boundary Check
 @subsection Block Boundary Check
 @cindex Block boundary check
 @cindex @code{END} type checking
@@ -2199,7 +2199,7 @@ Non-@code{nil} means expand generic END to ENDIF/ENDELSE/ENDWHILE etc.
 Non-@code{nil} means re-indent line after END was typed.
 @end defopt
 
-@node Padding Operators, Case Changes, Block Boundary Check, Actions
+@node Padding Operators
 @subsection Padding Operators
 @cindex Padding operators with spaces
 @cindex Operators, padding with spaces
@@ -2227,9 +2227,9 @@ operators (outside of strings and comments, of course), try this in
 @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
+(@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
@@ -2240,7 +2240,7 @@ 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
+modified assignment operators (@samp{AND=}, @samp{OR=}, etc.)@: are
 surrounded with spaces by @code{idlwave-surround}.
 @end defopt
 
@@ -2248,7 +2248,7 @@ surrounded with spaces by @code{idlwave-surround}.
 Non-@code{nil} means space-pad the @samp{=} in keyword assignments.
 @end defopt
 
-@node Case Changes,  , Padding Operators, Actions
+@node Case Changes
 @subsection Case Changes
 @cindex Case changes
 @cindex Upcase, enforcing for reserved words
@@ -2270,7 +2270,7 @@ your @file{.emacs} file:
      (idlwave-action-and-binding "\\<\\(pro\\|function\\)\\>[ \t]*\\<"
                                  '(capitalize-word 1) t)
      ;;  Capitalize common block name
-     (idlwave-action-and-binding "\\<common\\>[ \t]+\\<" 
+     (idlwave-action-and-binding "\\<common\\>[ \t]+\\<"
                                  '(capitalize-word 1) t)))
 @end lisp
 
@@ -2290,7 +2290,7 @@ expansion.
 @end defopt
 
 
-@node Doc Header, Motion Commands, Actions, The IDLWAVE Major Mode
+@node Doc Header
 @section Documentation Header
 @cindex Documentation header
 @cindex DocLib header
@@ -2334,17 +2334,16 @@ Regexp matching the start of a document library header.
 Regexp matching the start of a document library header.
 @end defopt
 
-@node Motion Commands, Misc Options, Doc Header, The IDLWAVE Major Mode
+@node Motion Commands
 @section Motion Commands
 @cindex Motion commands
 @cindex Program structure, moving through
 @cindex Code structure, moving through
-@cindex @file{Func-menu}, XEmacs package
-@cindex @file{Imenu}, Emacs package
+@cindex @file{Imenu}
 @cindex Function definitions, jumping to
 @cindex Procedure definitions, jumping to
 
-IDLWAVE supports both @file{Imenu} and @file{Func-menu}, two packages
+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}:
@@ -2384,7 +2383,7 @@ IDL program:
 @end multitable
 
 
-@node Misc Options,  , Motion Commands, The IDLWAVE Major Mode
+@node Misc Options
 @section Miscellaneous Options
 @cindex Hooks
 
@@ -2401,11 +2400,7 @@ is first called.
 Normal hook.  Executed when a buffer is put into @code{idlwave-mode}.
 @end defopt
 
-@defopt idlwave-load-hook
-Normal hook.  Executed when @file{idlwave.el} is loaded.
-@end defopt
-
-@node The IDLWAVE Shell, Installation, The IDLWAVE Major Mode, Top
+@node The IDLWAVE Shell
 @chapter The IDLWAVE Shell
 @cindex IDLWAVE shell
 @cindex Major mode, @code{idlwave-shell-mode}
@@ -2413,7 +2408,7 @@ Normal hook.  Executed when @file{idlwave.el} is loaded.
 @cindex Subprocess of Emacs, IDL
 @cindex Comint, Emacs package
 @cindex Windows
-@cindex MacOS
+@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
@@ -2423,19 +2418,19 @@ 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 only under UNIX and MacOSX.
+currently works only under UNIX and macOS.
 
 @menu
 * Starting the Shell::          How to launch IDL as a subprocess
 * Using the Shell::             Interactively working with the Shell
-* Multi-Line Commands::         
-* Commands Sent to the Shell::  
-* Debugging IDL Programs::      
-* Examining Variables::         
-* Custom Expression Examination::  
+* Multi-Line Commands::
+* Commands Sent to the Shell::
+* Debugging IDL Programs::
+* Examining Variables::
+* Custom Expression Examination::
 @end menu
 
-@node Starting the Shell, Using the Shell, The IDLWAVE Shell, The IDLWAVE Shell
+@node Starting the Shell
 @section Starting the Shell
 @cindex Starting the shell
 @cindex Shell, starting
@@ -2513,12 +2508,12 @@ Initial commands, separated by newlines, to send to IDL.
 Non-@code{nil} means preserve command history between sessions.
 @end defopt
 
-@defopt idlwave-shell-command-history-file (@file{~/.idlwave/.idlwhist})
+@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.
@@ -2541,7 +2536,7 @@ The frame parameters for a dedicated idlwave-shell frame.
 @end defopt
 
 @defopt idlwave-shell-raise-frame (@code{t})
-Non-@code{nil} means `idlwave-shell' raises the frame showing the shell
+Non-@code{nil} means @code{idlwave-shell} raises the frame showing the shell
 window.
 @end defopt
 
@@ -2554,7 +2549,7 @@ The prefix for temporary IDL files used when compiling regions.
 Hook for customizing @code{idlwave-shell-mode}.
 @end defopt
 
-@node Using the Shell, Multi-Line Commands, Starting the Shell, The IDLWAVE Shell
+@node Using the Shell
 @section Using the Shell
 @cindex Comint
 @cindex Shell, basic commands
@@ -2571,9 +2566,9 @@ between emacs and IDL sessions.  Here is a list of commonly used
 commands:
 
 @multitable @columnfractions .12 .88
-@item @key{UP}, @key{M-p}
+@item @key{UP}, @kbd{M-p}
 @tab Cycle backwards in input history
-@item @key{DOWN}, @key{M-n}
+@item @key{DOWN}, @kbd{M-n}
 @tab Cycle forwards in input history
 @item @kbd{M-r}
 @tab Previous input matching a regexp
@@ -2629,7 +2624,7 @@ keywords, system variables, system variable tags etc.
 @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 
+@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})
@@ -2660,14 +2655,14 @@ Size of IDL graphics windows popped up by special IDLWAVE command.
 @cindex Spells, magic
 IDLWAVE works in line input mode: you compose a full command line (or
 multiple lines; see below), using all the power Emacs gives you to do
-this.  When you press @key{RET}, the whole line is sent to IDL.
+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
+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.
@@ -2682,7 +2677,7 @@ The three regular expressions which match the ``magic spells'' for input
 modes.
 @end defopt
 
-@node Multi-Line Commands, Commands Sent to the Shell, Using the Shell, The IDLWAVE Shell
+@node Multi-Line Commands
 @section Multi-Line Commands
 @cindex Multi-line commands
 @cindex Commands, multi-line
@@ -2707,12 +2702,12 @@ each line, e.g.:
 
 @example
 IDL> for i=0,3 do begin &
-print,i,' is fun' & 
+print,i,' is fun' &
 print,i^2,' is even more fun' &
 endfor
 @end example
 
-@noindent Note that this is identical syntax to an IDL batch file.  
+@noindent Note that this is identical syntax to an IDL batch file.
 Use @kbd{C-c @key{SPACE}} to insert a @samp{&} and newline together.  As
 in an IDLWAVE buffer, @kbd{M-@key{RET}} will add a continuation
 character (@samp{$}) and new line for a continued single command.  With
@@ -2734,7 +2729,7 @@ ease of editing.  Holding @key{SHIFT} while using the arrow keys will
 override this behavior; the command history will be cycled through
 directly.
 
-@node Commands Sent to the Shell, Debugging IDL Programs, Multi-Line Commands, The IDLWAVE Shell
+@node Commands Sent to the Shell
 @section Commands Sent to the Shell
 @cindex Commands in shell, showing
 @cindex Showing commands in shell
@@ -2775,10 +2770,10 @@ 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, Examining Variables, Commands Sent to the Shell, The IDLWAVE Shell
+@node Debugging IDL Programs
 @section Debugging IDL Programs
 @cindex Debugging
-@cindex Keybindings for debugging
+@cindex Key bindings for debugging
 @cindex Toolbar
 
 Programs can be compiled, run, and debugged directly from the source
@@ -2804,16 +2799,16 @@ buffers.
 @end defopt
 
 @menu
-* A Tale of Two Modes::         
-* Debug Key Bindings::          
-* Breakpoints and Stepping::    
-* Compiling Programs::          
-* Walking the Calling Stack::   
-* Electric Debug Mode::         
+* 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, Debug Key Bindings, Debugging IDL Programs, Debugging IDL Programs
+@node A Tale of Two Modes
 @subsection A Tale of Two Modes
 @cindex Electric Debug Mode
 @cindex Debugging Interface
@@ -2833,7 +2828,7 @@ 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, Breakpoints and Stepping, A Tale of Two Modes, Debugging IDL Programs
+@node Debug Key Bindings
 @subsection Debug Key Bindings
 @kindex C-c C-d
 @cindex Key bindings
@@ -2843,8 +2838,8 @@ 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
+@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
@@ -2852,14 +2847,14 @@ example, if you include in @file{.emacs}:
 @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
+@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
+@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})
@@ -2879,7 +2874,7 @@ more of @code{control}, @code{meta}, @code{super}, @code{hyper},
 @code{alt}, and @code{shift}.
 @end defopt
 
-@node Breakpoints and Stepping, Compiling Programs, Debug Key Bindings, Debugging IDL Programs
+@node Breakpoints and Stepping
 @subsection Breakpoints and Stepping
 @cindex Breakpoints
 @cindex Stepping
@@ -2890,19 +2885,19 @@ more of @code{control}, @code{meta}, @code{super}, @code{hyper},
 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
+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}),
+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
+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}).  
+(@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).
@@ -2911,11 +2906,11 @@ 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}.  
+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
+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.
 
@@ -3011,7 +3006,7 @@ configured in @code{idlwave-shell-mark-stop-line}.
 @end defopt
 
 
-@node Compiling Programs, Walking the Calling Stack, Breakpoints and Stepping, Debugging IDL Programs
+@node Compiling Programs
 @subsection Compiling Programs
 @cindex Compiling programs
 @cindex Programs, compiling
@@ -3021,8 +3016,8 @@ configured in @code{idlwave-shell-mark-stop-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 
+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.
 
@@ -3042,7 +3037,7 @@ 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, Electric Debug Mode, Compiling Programs, Debugging IDL Programs
+@node Walking the Calling Stack
 @subsection Walking the Calling Stack
 @cindex Calling stack, walking
 
@@ -3064,7 +3059,7 @@ higher calling stack levels.
 @html
 <A NAME="EDEBUG"></A>
 @end html
-@node Electric Debug Mode,  , Walking the Calling Stack, Debugging IDL Programs
+@node Electric Debug Mode
 @subsection Electric Debug Mode
 @cindex Electric Debug Mode
 @cindex @samp{*Debugging*}
@@ -3147,7 +3142,7 @@ with shortcut of examine type.
 
 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}).
+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
@@ -3185,9 +3180,9 @@ halts.
 
 @defopt idlwave-shell-electric-stop-color (Violet)
 Default color of the stopped line overlay when in electric debug mode.
-@end defopt        
+@end defopt
 
-@defopt idlwave-shell-electric-stop-line-face 
+@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
@@ -3201,7 +3196,7 @@ window, but is useful for immediate stepping, etc.
 @html
 <A NAME="EXAMINE"></A>
 @end html
-@node Examining Variables, Custom Expression Examination, Debugging IDL Programs, The IDLWAVE Shell
+@node Examining Variables
 @section Examining Variables
 @cindex @code{PRINT} expressions
 @cindex @code{HELP}, on expressions
@@ -3211,9 +3206,9 @@ window, but is useful for immediate stepping, etc.
 @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)},
+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
+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
@@ -3224,17 +3219,17 @@ 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
+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,
+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 @key{c}
-clears the contents, and @key{q} hides the buffer.
+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
@@ -3253,8 +3248,8 @@ print, only an initial portion of long arrays will be printed, up to
 
 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
+@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
@@ -3282,7 +3277,7 @@ with a @samp{( )} will be interpreted as function calls.
 @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
+which may or may not be available in future versions of IDL@.  Caveat
 Examinor.
 @end itemize
 
@@ -3293,14 +3288,14 @@ the expression printed by IDL.
 @end defopt
 
 @defopt idlwave-shell-output-face
-The face for @code{idlwave-shell-output-overlay}.  
-Allows to choose the font, color and other properties for the most
+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. 
+@file{*Examine*} buffer, instead of in the shell itself.
 @end defopt
 
 @defopt idlwave-shell-max-print-length (200)
@@ -3308,7 +3303,7 @@ The maximum number of leading array entries to print, when examining
 array expressions.
 @end defopt
 
-@node Custom Expression Examination,  , Examining Variables, The IDLWAVE Shell
+@node Custom Expression Examination
 @section Custom Expression Examination
 @cindex Expressions, custom examination
 @cindex Custom expression examination
@@ -3321,7 +3316,7 @@ 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
+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,
@@ -3354,17 +3349,17 @@ Both functions take a single string argument sharing the syntax of the
 @lisp
 (add-hook 'idlwave-shell-mode-hook
           (lambda ()
-            (idlwave-shell-define-key-both [s-down-mouse-2] 
-                                 (idlwave-shell-mouse-examine 
+            (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 
+            (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                                        
-            
+@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,
@@ -3378,7 +3373,7 @@ examine command strings to send, after all instances of @code{___}
 (three underscores) are replaced by the indicated expression.
 @end defopt
 
-@node Installation, Acknowledgements, The IDLWAVE Shell, Top
+@node Installation
 @chapter Installation
 @cindex Installation
 
@@ -3387,7 +3382,7 @@ examine command strings to send, after all instances of @code{___}
 * Installing Online Help::      Where to get the additional files needed
 @end menu
 
-@node Installing IDLWAVE, Installing Online Help, Installation, Installation
+@node Installing IDLWAVE
 @section Installing IDLWAVE
 
 @cindex FTP site
@@ -3404,7 +3399,7 @@ download IDLWAVE and install it yourself from
 @uref{@value{IDLWAVEHOMEPAGE}, the maintainers webpage}.  Follow the
 instructions in the INSTALL file.
 
-@node Installing Online Help,  , Installing IDLWAVE, Installation
+@node Installing Online Help
 @section Installing Online Help
 @cindex Installing online help
 @cindex Online Help, Installation
@@ -3422,7 +3417,7 @@ system and tell IDLWAVE where they are with:
 
 @lisp
 ; e.g. /usr/local/etc/
-(setq idlwave-html-help-location "/path/to/help/dir/") 
+(setq idlwave-html-help-location "/path/to/help/dir/")
 @end lisp
 
 @noindent The default location is @file{/usr/local/etc}, and if you
@@ -3432,9 +3427,9 @@ documentation, and need not be updated unless your version of IDL
 changes.  Since the help system is distributed with IDL starting at
 version 6.2, no new help packages will be created for these versions.
 
-@node Acknowledgements, Sources of Routine Info, Installation, Top
-@chapter Acknowledgements
-@cindex Acknowledgements
+@node Acknowledgments
+@chapter Acknowledgments
+@cindex Acknowledgments
 @cindex Maintainer, of IDLWAVE
 @cindex Authors, of IDLWAVE
 @cindex Contributors, to IDLWAVE
@@ -3456,7 +3451,7 @@ 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 
+@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
@@ -3511,7 +3506,7 @@ scripts and documentation to interface with the IDL Assistant.
 @noindent
 Thanks to everyone!
 
-@node Sources of Routine Info, HTML Help Browser Tips, Acknowledgements, Top
+@node Sources of Routine Info
 @appendix Sources of Routine Info
 
 @cindex Sources of routine information
@@ -3523,12 +3518,12 @@ know about the accessible routines.
 @menu
 * Routine Definitions::         Where IDL Routines are defined.
 * Routine Information Sources::  So how does IDLWAVE know about...
-* Catalogs::                    
+* Catalogs::
 * Load-Path Shadows::           Routines defined in several places
 * Documentation Scan::          Scanning the IDL Manuals
 @end menu
 
-@node Routine Definitions, Routine Information Sources, Sources of Routine Info, Sources of Routine Info
+@node Routine Definitions
 @appendixsec Routine Definitions
 @cindex Routine definitions
 @cindex IDL variable @code{!PATH}
@@ -3541,7 +3536,7 @@ know about the accessible routines.
 several places:
 
 @enumerate
-@item 
+@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.
@@ -3549,7 +3544,7 @@ the IDL documentation.
 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 
+@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
@@ -3564,7 +3559,7 @@ 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, Catalogs, Routine Definitions, Sources of Routine Info
+@node Routine Information Sources
 @appendixsec Routine Information Sources
 @cindex Routine info sources
 @cindex Builtin list of routines
@@ -3587,7 +3582,7 @@ directly with IDL in the form of an XML catalog which IDLWAVE scans.
 Formerly, this list was created (imperfectly) by scanning the IDL
 manuals to produce the file @file{idlw-rinfo.el}.
 
-@item 
+@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
@@ -3651,7 +3646,7 @@ Controls under what circumstances routine info is updated automatically.
 @html
 <A NAME="CATALOGS"></A>
 @end html
-@node Catalogs, Load-Path Shadows, Routine Information Sources, Sources of Routine Info
+@node Catalogs
 @appendixsec Catalogs
 @cindex Catalogs
 
@@ -3662,22 +3657,22 @@ 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
+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
+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
+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{~/.idlwave/idlpath.el}, by
+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.
@@ -3689,31 +3684,31 @@ to locate library catalogs.
 @end defopt
 
 @defopt idlwave-library-path
-IDL library path for Windows and MacOS.  Under Unix/MacOSX, will be
+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
+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/MacOSX, will be obtained from the Shell and recorded, if run.
+Unix/macOS, will be obtained from the Shell and recorded, if run.
 @end defopt
 
-@defopt idlwave-config-directory (@file{~/.idlwave})
+@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::                
+* Library Catalogs::
+* User Catalog::
 @end menu
 
 @html
 <A NAME="LIBRARY_CATALOGS"></A>
 @end html
-@node Library Catalogs, User Catalog, Catalogs, Catalogs
+@node Library Catalogs
 @appendixsubsec Library Catalogs
 @cindex @file{.idlwave_catalog}
 @cindex Library catalogs
@@ -3723,20 +3718,20 @@ 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
+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.
+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.
+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
@@ -3777,25 +3772,25 @@ 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,  , Library Catalogs, Catalogs
+@node User Catalog
 @appendixsubsec User Catalog
 @cindex User catalog
 @cindex IDL library routine info
 @cindex Windows
-@cindex MacOS
+@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{.idlwave/idlusercat.el} by default).  Although library catalogs
+(@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 
+@item Can be used to scan directories for which the user has no write
 privileges.
 @item Easy widget-based path selection.
 @end itemize
@@ -3807,7 +3802,7 @@ 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 and MacOS (not OSX), you need to specify the IDL search path in
+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 <at> footnote{The initial @samp{+}
@@ -3850,7 +3845,7 @@ Alist of regular expressions matching special library directories for
 labeling in routine-info display.
 @end defopt
 
-@node Load-Path Shadows, Documentation Scan, Catalogs, Sources of Routine Info
+@node Load-Path Shadows
 @appendixsec Load-Path Shadows
 @cindex Load-path shadows
 @cindex Shadows, load-path
@@ -3876,9 +3871,9 @@ C-i}.  Here are the different routines (also available in the Menu
 
 @table @asis
 @item @kbd{M-x idlwave-list-buffer-load-path-shadows}
-This commands checks the names of all routines defined in the current
+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}
+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
@@ -3898,20 +3893,19 @@ files.  Therefore, such local files should not be installed inside the
 many other reasons.
 
 @cindex Windows
-@cindex MacOS
 @cindex IDL variable @code{!DIR}
 @cindex @code{!DIR}, IDL variable
-Users of Windows and MacOS (not X) also must set the 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 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,  , Load-Path Shadows, Sources of Routine Info
-@appendixsec Documentation Scan 
+@node Documentation Scan
+@appendixsec Documentation Scan
 @cindex @file{get_html_rinfo}
 @cindex @file{idlw-rinfo.el}
 @cindex Scanning the documentation
@@ -3943,7 +3937,7 @@ 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, Configuration Examples, Sources of Routine Info, Top
+@node HTML Help Browser Tips
 @appendix HTML Help Browser Tips
 @cindex Browser Tips
 
@@ -3955,41 +3949,35 @@ raw HTML help files.
 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
+@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 a many different system types, a single browser
-configuration is not possible, but choices abound.  On many systems,
-the default browser configured in @code{browse-url-browser-function},
-and hence inherited by default by
-@code{idlwave-help-browser-function}, is Netscape.  Unfortunately, the
-HTML manuals decompiled from the original source contain formatting
-structures which Netscape 4.x does not handle well, though they are
-still readable.  A much better choice is Mozilla, or one of the
-Mozilla-derived browsers such as
-@uref{http://galeon.sourceforge.net/,Galeon} (GNU/Linux),
-@uref{http://www.mozilla.org/projects/camino/,Camino} (MacOSX), or
-@uref{http://www.mozilla.org/projects/firebird/,Firebird} (all
-platforms).  Newer versions of Emacs provide a browser-function choice
-@code{browse-url-gnome-moz} which uses the Gnome-configured browser.
-
-Note that the HTML files decompiled from the help sources contain
+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/MacOSX: The @uref{http://www.w3m.org,@code{w3m}} browser
+@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
@@ -4022,8 +4010,9 @@ following, to get consistent behavior with the @kbd{q} key:
 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, Windows and MacOS, HTML Help Browser Tips, Top
+@node Configuration Examples
 @appendix Configuration Examples
 @cindex Configuration examples
 @cindex Example configuration
@@ -4043,7 +4032,7 @@ features which:
 
 @itemize @minus
 @item
-are not self-evident (i.e. too magic) when used by an unsuspecting user.
+are not self-evident (i.e., too magic) when used by an unsuspecting user.
 @item
 are too intrusive.
 @item
@@ -4074,7 +4063,7 @@ the old maintainer had in his @file{.emacs}:
 
 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
+is an example of a much more extensive configuration of IDLWAVE@.  The
 user is King!
 
 @example
@@ -4084,7 +4073,7 @@ user is King!
 (setq idlwave-main-block-indent 3)
 (setq idlwave-end-offset -3)
 (setq idlwave-continuation-indent 1)
-(setq idlwave-begin-line-comment "^;[^;]")  ; Leave ";" but not ";;" 
+(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 '='
@@ -4109,7 +4098,7 @@ user is King!
       w3m-use-header-line nil
       w3m-use-toolbar nil)
 
-;; Close my help window or frame when w3m closes with `q'
+;; 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)))
@@ -4135,11 +4124,11 @@ user is King!
     (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
+    ;; 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.)
+    ;; (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)
@@ -4151,10 +4140,10 @@ user is King!
     ;; (local-set-key "\C-j" 'idlwave-newline) ; My preference.
 
     ;; Some personal abbreviations
-    (define-abbrev idlwave-mode-abbrev-table  
+    (define-abbrev idlwave-mode-abbrev-table
       (concat idlwave-abbrev-start-char "wb") "widget_base()"
       (idlwave-keyword-abbrev 1))
-    (define-abbrev idlwave-mode-abbrev-table  
+    (define-abbrev idlwave-mode-abbrev-table
       (concat idlwave-abbrev-start-char "on") "obj_new()"
       (idlwave-keyword-abbrev 1))
     ))
@@ -4172,32 +4161,31 @@ user is King!
 (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 
+            (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 
+            (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="WIN_MAC"></A>
+<A NAME="WINDOWS_MAC"></A>
 @end html
-@node Windows and MacOS, Troubleshooting, Configuration Examples, Top
-@appendix Windows and MacOS
+@node Windows and macOS
+@appendix Windows and macOS
 @cindex Windows
-@cindex MacOS
-@cindex MacOSX
+@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 or NTXEmacs) or MacOS.
+operating systems like Windows (with NTEmacs).
 
 The only real problem is that there is no command-line version of IDL
-for Windows or MacOS(<=9) with which IDLWAVE can interact.  As a
+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
@@ -4226,13 +4214,13 @@ system.  I am assuming that IDLWAVE has been installed in
 
 @end lisp
 
-@noindent Furthermore, Windows sometimes tries to outsmart you --- make
+@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 
+@item When you download the IDLWAVE distribution, make sure you save the
 file under the names @file{idlwave.tar.gz}.
-@item M-TAB switches among running programs --- use Esc-TAB
+@item M-@key{TAB} switches among running programs---use @key{ESC}-@key{TAB}
 instead.
 @item Other issues as yet unnamed...
 @end itemize
@@ -4244,7 +4232,7 @@ help can skip the browser and use the HTMLHelp functionality directly.
 @html
 <A NAME="TROUBLE"></A>
 @end html
-@node Troubleshooting, GNU Free Documentation License, Windows and MacOS, Top
+@node Troubleshooting
 @appendix Troubleshooting
 @cindex Troubleshooting
 
@@ -4266,7 +4254,7 @@ customize the variable @code{idlwave-shell-automatic-electric-debug}
 if you prefer not to enter electric debug on breakpoints <at> 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.  
+encountered.
 
 @item @strong{I get errors like @samp{Searching for program: no such
 file or directory, idl} when attempting to start the IDL shell.}
@@ -4278,37 +4266,17 @@ 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 MacOSX; see the next topic.
+application with macOS; see the next topic.
 
 @item @strong{IDLWAVE is disregarding my @samp{IDL_PATH} which I set
-under MacOSX}
+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
+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{I get errors like @samp{Symbol's function is void:
-overlayp}}
-
-You don't have the @samp{fsf-compat} package installed, which IDLWAVE
-needs to run under XEmacs.  Install it, or find an XEmacs distribution
-which includes it by default.
-
-@item @strong{I'm getting errors like @samp{Symbol's value as variable is void:
-cl-builtin-gethash} on completion or routine info.}
-
-This error arises if you upgraded Emacs from 20.x to 21.x without
-re-installing IDLWAVE.  Old Emacs and new Emacs are not byte-compatible
-in compiled lisp files.  Presumably, you kept the original .elc files in
-place, and this is the source of the error.  If you recompile (or just
-"make; make install") from source, it should resolve this problem.
-Another option is to recompile the @file{idlw*.el} files by hand using
-@kbd{M-x byte-compile-file}.  Why not take the opportunity to grab the
-latest IDLWAVE version at @uref{@value{IDLWAVEHOMEPAGE}, the maintainers
-webpage}.
-
 @item @strong{@kbd{M-@key{TAB}} doesn't complete words, it switches
 windows on my desktop.}
 
@@ -4355,11 +4323,11 @@ tried to install the optional modules @file{idlw-roprompt.el} or
 load file}}.
 
 The problem is that your Emacs is not finding the version of IDLWAVE you
-installed.  Many Emacsen come with an older bundled copy of IDLWAVE
-(e.g. v4.7 for Emacs 21.x), which is likely what's being used instead.
+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' default search directories.  You can
+default), @emph{before} Emacs's default search directories.  You can
 accomplish this by putting the following in your @file{.emacs}:
 
 @lisp
@@ -4410,22 +4378,22 @@ 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
+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
+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
-@key{C-d} to quit the shell, however.  Another possibility is
+@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
+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
@@ -4437,27 +4405,13 @@ webpage} for more.  Note that, starting with IDL 6.2, the HTML help and
 its catalog are distributed with IDL, and so should never be
 inconsistent.
 
-@item @strong{I get errors such as @samp{void-variable
-browse-url-browser-function} or similar when attempting to load IDLWAVE
-under XEmacs.}
-
-You don't have the @samp{browse-url} (or other required) XEmacs package.
-Unlike GNU Emacs, XEmacs distributes many packages separately from the
-main program.  IDLWAVE is actually among these, but is not always the
-most up to date.  When installing IDLWAVE as an XEmacs package, it
-should prompt you for required additional packages.  When installing it
-from source, it won't and you'll get this error.  The easiest solution
-is to install all the packages when you install XEmacs (the so-called
-@samp{sumo} bundle).  The minimum set of XEmacs packages required by
-IDLWAVE is @samp{fsf-compat, xemacs-base, mail-lib}.
-
 @end enumerate
 
-@node GNU Free Documentation License, Index, Troubleshooting, Top
+@node GNU Free Documentation License
 @appendix GNU Free Documentation License
 @include doclicense.texi
 
-@node Index,  , GNU Free Documentation License, Top
+@node Index
 @unnumbered Index
 @printindex cp
 
diff --git a/lpath.el b/lpath.el
index 24d2837d63..f79019f14a 100644
--- a/lpath.el
+++ b/lpath.el
@@ -1,4 +1,4 @@
-;; IDLWAVE helper file for batch compiles -- Make sure we get the right files.
+;; IDLWAVE helper file for batch compiles -- Make sure we get the right files.  -*- lexical-binding: t; -*-
 (setq load-path (cons "." load-path)
       byte-compile-warnings nil)
 
[idlwave.log (text/plain, inline)]
Byte compiling packages/idlwave/idlw-bindings.el

In end of data:
packages/idlwave/idlw-bindings.el:384:51: Warning: the function ‘idlwave-show-begin-check’ is not known to be defined.
packages/idlwave/idlw-bindings.el:328:46: Warning: the function ‘idlwave-show-begin’ is not known to be defined.
packages/idlwave/idlw-bindings.el:313:36: Warning: the function ‘idlwave-elif’ is not known to be defined.
packages/idlwave/idlw-bindings.el:312:36: Warning: the function ‘idlwave-if’ is not known to be defined.
packages/idlwave/idlw-bindings.el:309:36: Warning: the function ‘idlwave-procedure’ is not known to be defined.
packages/idlwave/idlw-bindings.el:308:36: Warning: the function ‘idlwave-function’ is not known to be defined.
packages/idlwave/idlw-bindings.el:307:36: Warning: the function ‘idlwave-foreach’ is not known to be defined.
packages/idlwave/idlw-bindings.el:305:36: Warning: the function ‘idlwave-switch’ is not known to be defined.
packages/idlwave/idlw-bindings.el:240:37: Warning: the function ‘idlwave-quoted’ is not known to be defined.
packages/idlwave/idlw-bindings.el:227:47: Warning: the function ‘idlwave-surround’ is not known to be defined.
packages/idlwave/idlw-bindings.el:224:47: Warning: the function ‘idlwave-custom-ltgtr-surround’ is not known to be defined.
packages/idlwave/idlw-bindings.el:221:47: Warning: the function ‘idlwave-expand-equal’ is not known to be defined.
packages/idlwave/idlw-bindings.el:217:36: Warning: the function ‘idlwave-custom-ampersand-surround’ is not known to be defined.
packages/idlwave/idlw-bindings.el:129:12: Warning: the function ‘idlwave-restore-wconf-after-completion’ is not known to be defined.
packages/idlwave/idlw-bindings.el:118:30: Warning: the function ‘idlwave-help-return-to-calling-frame’ is not known to be defined.
packages/idlwave/idlw-bindings.el:117:27: Warning: the function ‘idlwave-help-fontify’ is not known to be defined.
packages/idlwave/idlw-bindings.el:116:27: Warning: the function ‘idlwave-help-toggle-header-match-and-def’ is not known to be defined.
packages/idlwave/idlw-bindings.el:115:27: Warning: the function ‘idlwave-help-find-first-header’ is not known to be defined.
packages/idlwave/idlw-bindings.el:114:27: Warning: the function ‘idlwave-help-find-header’ is not known to be defined.
packages/idlwave/idlw-bindings.el:106:27: Warning: the function ‘idlwave-help-quit’ is not known to be defined.
packages/idlwave/idlw-bindings.el:95:27: Warning: the function ‘idlwave-quit-help’ is not known to be defined.
packages/idlwave/idlw-bindings.el:94:27: Warning: the function ‘idlwave-active-rinfo-space’ is not known to be defined.
packages/idlwave/idlw-bindings.el:93:33: Warning: the function ‘idlwave-mouse-active-rinfo-right’ is not known to be defined.
packages/idlwave/idlw-bindings.el:92:41: Warning: the function ‘idlwave-mouse-active-rinfo-shift’ is not known to be defined.
packages/idlwave/idlw-bindings.el:91:33: Warning: the function ‘idlwave-mouse-active-rinfo’ is not known to be defined.
packages/idlwave/idlw-bindings.el:83:41: Warning: the function ‘idlwave-mouse-context-help’ is not known to be defined.
packages/idlwave/idlw-bindings.el:82:34: Warning: the function ‘idlwave-resolve’ is not known to be defined.
packages/idlwave/idlw-bindings.el:81:34: Warning: the function ‘idlwave-update-routine-info’ is not known to be defined.
packages/idlwave/idlw-bindings.el:79:32: Warning: the function ‘idlwave-complete’ is not known to be defined.
packages/idlwave/idlw-bindings.el:74:9: Warning: the function ‘idlwave-help-with-topic’ is not known to be defined.
packages/idlwave/idlw-bindings.el:72:36: Warning: the function ‘idlwave-context-help’ is not known to be defined.
packages/idlwave/idlw-bindings.el:71:36: Warning: the function ‘idlwave-routine-info’ is not known to be defined.
packages/idlwave/idlw-bindings.el:70:36: Warning: the function ‘idlwave-find-module-this-file’ is not known to be defined.
packages/idlwave/idlw-bindings.el:69:36: Warning: the function ‘idlwave-find-module’ is not known to be defined.
packages/idlwave/idlw-bindings.el:68:34: Warning: the function ‘idlwave-list-buffer-load-path-shadows’ is not known to be defined.
packages/idlwave/idlw-bindings.el:67:34: Warning: the function ‘idlwave-shell-recenter-shell-window’ is not known to be defined.
packages/idlwave/idlw-bindings.el:65:34: Warning: the function ‘idlwave-kill-autoloaded-buffers’ is not known to be defined.
packages/idlwave/idlw-bindings.el:64:34: Warning: the function ‘idlwave-while’ is not known to be defined.
packages/idlwave/idlw-bindings.el:63:34: Warning: the function ‘idlwave-repeat’ is not known to be defined.
packages/idlwave/idlw-bindings.el:60:34: Warning: the function ‘idlwave-for’ is not known to be defined.
packages/idlwave/idlw-bindings.el:56:13: Warning: the function ‘idlwave-shell-run-region’ is not known to be defined.
packages/idlwave/idlw-bindings.el:53:13: Warning: the function ‘idlwave-shell-break-here’ is not known to be defined.
packages/idlwave/idlw-bindings.el:50:13: Warning: the function ‘idlwave-shell-save-and-run’ is not known to be defined.
packages/idlwave/idlw-bindings.el:40:34: Warning: the function ‘idlwave-case’ is not known to be defined.
packages/idlwave/idlw-bindings.el:39:34: Warning: the function ‘idlwave-doc-modification’ is not known to be defined.
packages/idlwave/idlw-bindings.el:38:34: Warning: the function ‘idlwave-doc-header’ is not known to be defined.
packages/idlwave/idlw-bindings.el:37:34: Warning: the function ‘idlwave-edit-in-idlde’ is not known to be defined.
packages/idlwave/idlw-bindings.el:36:34: Warning: the function ‘idlwave-fill-paragraph’ is not known to be defined.
packages/idlwave/idlw-bindings.el:34:45: Warning: the function ‘idlwave-indent-statement’ is not known to be defined.
packages/idlwave/idlw-bindings.el:31:34: Warning: the function ‘idlwave-next-statement’ is not known to be defined.
packages/idlwave/idlw-bindings.el:30:34: Warning: the function ‘idlwave-previous-statement’ is not known to be defined.
packages/idlwave/idlw-bindings.el:29:34: Warning: the function ‘idlwave-indent-subprogram’ is not known to be defined.
packages/idlwave/idlw-bindings.el:28:34: Warning: the function ‘idlwave-split-line’ is not known to be defined.
packages/idlwave/idlw-bindings.el:27:34: Warning: the function ‘idlwave-backward-up-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:26:34: Warning: the function ‘idlwave-down-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:25:34: Warning: the function ‘idlwave-backward-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:24:34: Warning: the function ‘idlwave-forward-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:23:42: Warning: the function ‘idlwave-mark-subprogram’ is not known to be defined.
packages/idlwave/idlw-bindings.el:22:34: Warning: the function ‘idlwave-close-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:21:34: Warning: the function ‘idlwave-end-of-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:20:34: Warning: the function ‘idlwave-beginning-of-block’ is not known to be defined.
packages/idlwave/idlw-bindings.el:19:34: Warning: the function ‘idlwave-end-of-subprogram’ is not known to be defined.
packages/idlwave/idlw-bindings.el:18:34: Warning: the function ‘idlwave-beginning-of-subprogram’ is not known to be defined.
packages/idlwave/idlw-bindings.el:17:34: Warning: the function ‘idlwave-toggle-comment-region’ is not known to be defined.
packages/idlwave/idlw-bindings.el:14:34: Warning: the function ‘idlwave-show-matching-quote’ is not known to be defined.
packages/idlwave/idlw-bindings.el:11:34: Warning: the function ‘idlwave-hard-tab’ is not known to be defined.
Byte compiling packages/idlwave/idlw-complete.el

In idlwave-complete-class-structure-tag-help:
packages/idlwave/idlw-complete.el:862:19: Warning: reference to free variable ‘idlwave-system-class-info’
packages/idlwave/idlw-complete.el:869:11: Warning: assignment to free variable ‘idlwave-help-do-class-struct-tag’

In idlwave-class-add-init-special:
packages/idlwave/idlw-complete.el:890:17: Warning: reference to free variable ‘idlwave-routines’

In idlwave-complete-sysvar-or-tag:
packages/idlwave/idlw-complete.el:923:40: Warning: reference to free variable ‘idlwave-system-variables-alist’

In idlwave-complete-sysvar-help:
packages/idlwave/idlw-complete.el:950:28: Warning: reference to free variable ‘idlwave-system-variables-alist’

In idlwave-complete-sysvar-tag-help:
packages/idlwave/idlw-complete.el:961:27: Warning: reference to free variable ‘idlwave-system-variables-alist’

In idlwave-shell-complete:
packages/idlwave/idlw-complete.el:1004:35: Warning: reference to free variable ‘idlwave-executive-commands-alist’

In idlwave-shell-complete-execcomm-help:
packages/idlwave/idlw-complete.el:1027:35: Warning: reference to free variable ‘idlwave-executive-commands-alist’

In idlwave-shell-complete-filename:
packages/idlwave/idlw-complete.el:1044:47: Warning: reference to free variable ‘idlwave-shell-file-name-chars’

In end of data:
packages/idlwave/idlw-complete.el:1042:4: Warning: the function ‘idlwave-shell-resync-dirs’ is not known to be defined.
packages/idlwave/idlw-complete.el:1014:13: Warning: the function ‘idlwave-shell-filename-string’ is not known to be defined.
packages/idlwave/idlw-complete.el:1011:8: Warning: the function ‘idlwave-shell-shell-command’ is not known to be defined.
packages/idlwave/idlw-complete.el:1008:8: Warning: the function ‘idlwave-shell-batch-command’ is not known to be defined.
packages/idlwave/idlw-complete.el:992:24: Warning: the function ‘idlwave-shell-executive-command’ is not known to be defined.
packages/idlwave/idlw-complete.el:974:22: Warning: the function ‘idlwave-substitute-link-target’ is not known to be defined.
packages/idlwave/idlw-complete.el:910:44: Warning: the function ‘idlwave-sintern-sysvar-alist’ is not known to be defined.
packages/idlwave/idlw-complete.el:908:40: Warning: the function ‘idlwave-sysvars-reset’ is not known to be defined.
packages/idlwave/idlw-complete.el:898:14: Warning: the function ‘idlwave-all-assq’ is not known to be defined.
packages/idlwave/idlw-complete.el:891:12: Warning: the function ‘idlwave-sintern-rinfo-list’ is not known to be defined.
packages/idlwave/idlw-complete.el:884:29: Warning: the function ‘idlwave-class-tags’ is not known to be defined.
packages/idlwave/idlw-complete.el:882:18: Warning: the function ‘idlwave-all-class-tags’ is not known to be defined.
packages/idlwave/idlw-complete.el:865:35: Warning: the function ‘idlwave-class-found-in’ is not known to be defined.
packages/idlwave/idlw-complete.el:823:49: Warning: the function ‘idlwave-current-routine’ is not known to be defined.
packages/idlwave/idlw-complete.el:742:21: Warning: the function ‘idlwave-all-method-classes’ is not known to be defined.
packages/idlwave/idlw-complete.el:740:23: Warning: the function ‘idlwave-all-method-keyword-classes’ is not known to be defined.
packages/idlwave/idlw-complete.el:735:22: Warning: the function ‘idlwave-class-or-superclass-with-tag’ is not known to be defined.
packages/idlwave/idlw-complete.el:693:33: Warning: the function ‘idlwave-class-info’ is not known to be defined.
packages/idlwave/idlw-complete.el:689:21: Warning: the function ‘idlwave-class-alist’ is not known to be defined.
packages/idlwave/idlw-complete.el:666:6: Warning: the function ‘comint-dynamic-complete-filename’ is not known to be defined.
packages/idlwave/idlw-complete.el:628:37: Warning: the function ‘idlwave-mouse-completion-help’ is not known to be defined.
packages/idlwave/idlw-complete.el:536:20: Warning: the function ‘idlwave-sintern-method’ is not known to be defined.
packages/idlwave/idlw-complete.el:504:20: Warning: the function ‘idlwave-sintern-routine’ is not known to be defined.
packages/idlwave/idlw-complete.el:476:18: Warning: the function ‘idlwave-sintern-class’ is not known to be defined.
packages/idlwave/idlw-complete.el:475:19: Warning: the function ‘idlwave-sintern-routine-or-method’ is not known to be defined.
packages/idlwave/idlw-complete.el:424:30: Warning: the function ‘idlwave-entry-has-help’ is not known to be defined.
packages/idlwave/idlw-complete.el:408:4: Warning: the function ‘idlwave-set-local’ is not known to be defined.
packages/idlwave/idlw-complete.el:397:17: Warning: the function ‘idlwave-local-value’ is not known to be defined.
packages/idlwave/idlw-complete.el:335:36: Warning: the function ‘idlwave-uniquify’ is not known to be defined.
packages/idlwave/idlw-complete.el:311:18: Warning: the function ‘idlwave-sintern’ is not known to be defined.
packages/idlwave/idlw-complete.el:218:21: Warning: the function ‘idlwave-fix-keywords’ is not known to be defined.
packages/idlwave/idlw-complete.el:217:19: Warning: the function ‘idlwave-make-full-name’ is not known to be defined.
packages/idlwave/idlw-complete.el:214:21: Warning: the function ‘idlwave-entry-keywords’ is not known to be defined.
packages/idlwave/idlw-complete.el:211:22: Warning: the function ‘idlwave-best-rinfo-assq’ is not known to be defined.
packages/idlwave/idlw-complete.el:149:18: Warning: the function ‘idlwave-all-class-inherits’ is not known to be defined.
packages/idlwave/idlw-complete.el:148:24: Warning: the function ‘idlwave-explicit-class-listed’ is not known to be defined.
packages/idlwave/idlw-complete.el:146:40: Warning: the function ‘idlwave-determine-class’ is not known to be defined.
packages/idlwave/idlw-complete.el:127:13: Warning: the function ‘idlwave-in-quote’ is not known to be defined.
packages/idlwave/idlw-complete.el:107:14: Warning: the function ‘idlwave-where’ is not known to be defined.
packages/idlwave/idlw-complete.el:99:4: Warning: the function ‘idlwave-routines’ is not known to be defined.
Byte compiling packages/idlwave/idlw-complete-structtag.el

In end of data:
packages/idlwave/idlw-complete-structtag.el:214:4: Warning: the function ‘idlwave-shell-send-command’ is not known to be defined.
Byte compiling packages/idlwave/idlwave.el

In end of data:
packages/idlwave/idlwave.el:718:8: Warning: the function ‘idlwave-shell-send-command’ is not known to be defined.
Byte compiling packages/idlwave/idlw-menus.el
Byte compiling packages/idlwave/idlw-roprompt.el

In idlwave--swap-read-only:
packages/idlwave/idlw-roprompt.el:108:25: Warning: reference to free variable ‘comint-last-prompt-overlay’

In idlwave--remove-text-read-only:
packages/idlwave/idlw-roprompt.el:132:11: Warning: reference to free variable ‘comint-last-prompt-overlay’

In end of data:
packages/idlwave/idlw-roprompt.el:105:25: Warning: the function ‘idlwave-shell-buffer’ is not known to be defined.
Byte compiling packages/idlwave/idlw-help.el

In idlwave-do-context-help1:
packages/idlwave/idlw-help.el:254:21: Warning: Unused lexical variable ‘tag’
packages/idlwave/idlw-help.el:261:42: Warning: reference to free variable ‘tag’

In idlwave-help-html-link:
packages/idlwave/idlw-help.el:583:17: Warning: reference to free variable ‘idlwave-help-use-eclipse-help’

In idlwave-help-with-topic:
packages/idlwave/idlw-help.el:1009:34: Warning: reference to free variable ‘idlwave-system-routines’

In idlwave-html-help-location:
packages/idlwave/idlw-help.el:1036:39: Warning: reference to free variable ‘idlwave-system-html-help-location’

In end of data:
packages/idlwave/idlw-help.el:1030:19: Warning: the function ‘idlwave-sys-dir’ is not known to be defined.
packages/idlwave/idlw-help.el:1008:43: Warning: the function ‘idlwave-routine-first-link-file’ is not known to be defined.
packages/idlwave/idlw-help.el:679:17: Warning: the function ‘idlwave-find-struct-tag’ is not known to be defined.
packages/idlwave/idlw-help.el:678:17: Warning: the function ‘idlwave-find-class-definition’ is not known to be defined.
packages/idlwave/idlw-help.el:634:16: Warning: the function ‘idlwave-routine-source-file’ is not known to be defined.
packages/idlwave/idlw-help.el:535:33: Warning: the function ‘idlwave-entry-find-keyword’ is not known to be defined.
packages/idlwave/idlw-help.el:529:51: Warning: the function ‘idlwave-routines’ is not known to be defined.
packages/idlwave/idlw-help.el:528:25: Warning: the function ‘idlwave-best-rinfo-assoc’ is not known to be defined.
packages/idlwave/idlw-help.el:373:29: Warning: the function ‘idlwave-sintern-keyword’ is not known to be defined.
packages/idlwave/idlw-help.el:371:28: Warning: the function ‘idlwave-all-method-keyword-classes’ is not known to be defined.
packages/idlwave/idlw-help.el:363:25: Warning: the function ‘idlwave-sintern-routine-or-method’ is not known to be defined.
packages/idlwave/idlw-help.el:362:24: Warning: the function ‘idlwave-find-inherited-class’ is not known to be defined.
packages/idlwave/idlw-help.el:357:26: Warning: the function ‘idlwave-popup-select’ is not known to be defined.
packages/idlwave/idlw-help.el:355:32: Warning: the function ‘idlwave-members-only’ is not known to be defined.
packages/idlwave/idlw-help.el:351:29: Warning: the function ‘idlwave-sintern-method’ is not known to be defined.
packages/idlwave/idlw-help.el:350:28: Warning: the function ‘idlwave-all-method-classes’ is not known to be defined.
packages/idlwave/idlw-help.el:339:17: Warning: the function ‘idlwave-this-word’ is not known to be defined.
packages/idlwave/idlw-help.el:277:28: Warning: the function ‘idlwave-make-full-name’ is not known to be defined.
packages/idlwave/idlw-help.el:272:31: Warning: the function ‘idlwave-expand-keyword’ is not known to be defined.
packages/idlwave/idlw-help.el:237:29: Warning: the function ‘idlwave-class-found-in’ is not known to be defined.
packages/idlwave/idlw-help.el:235:32: Warning: the function ‘idlwave-current-routine’ is not known to be defined.
packages/idlwave/idlw-help.el:234:24: Warning: the function ‘idlwave-class-or-superclass-with-tag’ is not known to be defined.
packages/idlwave/idlw-help.el:223:26: Warning: the function ‘idlwave-sintern-class’ is not known to be defined.
packages/idlwave/idlw-help.el:217:19: Warning: the function ‘idlwave-in-quote’ is not known to be defined.
packages/idlwave/idlw-help.el:203:27: Warning: the function ‘idlwave-substitute-link-target’ is not known to be defined.
packages/idlwave/idlw-help.el:175:46: Warning: the function ‘idlwave-beginning-of-statement’ is not known to be defined.
packages/idlwave/idlw-help.el:174:25: Warning: the function ‘idlwave-downcase-safe’ is not known to be defined.
packages/idlwave/idlw-help.el:172:30: Warning: the function ‘idlwave-where’ is not known to be defined.
packages/idlwave/idlw-help.el:171:27: Warning: the function ‘idlwave-what-module-find-class’ is not known to be defined.
Byte compiling packages/idlwave/idlw-routine.el

In idlwave-routine-twin-compare:
packages/idlwave/idlw-routine.el:269:2: Warning: docstring wider than 80 characters
packages/idlwave/idlw-routine.el:325:12: Warning: reference to free variable ‘idlwave-sort-prefer-buffer-info’

In idlwave-what-function:
packages/idlwave/idlw-routine.el:760:26: Warning: reference to free variable ‘idlwave-find-symbol-syntax-table’

In idlwave-fix-keywords:
packages/idlwave/idlw-routine.el:1009:22: Warning: assignment to free variable ‘idlwave-current-obj_new-class’

In idlwave-entry-keywords:
packages/idlwave/idlw-routine.el:1127:40: Warning: reference to free variable ‘idlwave-html-link-sep’

In idlwave-entry-find-keyword:
packages/idlwave/idlw-routine.el:1145:40: Warning: reference to free variable ‘idlwave-html-link-sep’

In idlwave-display-calling-sequence:
packages/idlwave/idlw-routine.el:1201:24: Warning: reference to free variable ‘idlwave-rinfo-map’
packages/idlwave/idlw-routine.el:1209:40: Warning: reference to free variable ‘idlwave-rinfo-mouse-map’

In end of data:
packages/idlwave/idlw-routine.el:1440:19: Warning: the function ‘idlwave-help-get-special-help’ is not known to be defined.
packages/idlwave/idlw-routine.el:1432:13: Warning: the function ‘idlwave-online-help’ is not known to be defined.
packages/idlwave/idlw-routine.el:1353:8: Warning: the function ‘idlwave-lib-p’ is not known to be defined.
packages/idlwave/idlw-routine.el:1040:20: Warning: the function ‘idlwave-sintern-keyword’ is not known to be defined.
packages/idlwave/idlw-routine.el:984:31: Warning: the function ‘idlwave-sintern-method’ is not known to be defined.
packages/idlwave/idlw-routine.el:938:26: Warning: the function ‘idlwave-sintern-routine’ is not known to be defined.
packages/idlwave/idlw-routine.el:895:12: Warning: the function ‘idlwave-beginning-of-statement’ is not known to be defined.
packages/idlwave/idlw-routine.el:658:32: Warning: the function ‘idlwave-start-of-substatement’ is not known to be defined.
packages/idlwave/idlw-routine.el:605:19: Warning: the function ‘idlwave-completing-read’ is not known to be defined.
packages/idlwave/idlw-routine.el:579:35: Warning: the function ‘idlwave-current-routine’ is not known to be defined.
packages/idlwave/idlw-routine.el:504:8: Warning: the function ‘idlwave-uniquify’ is not known to be defined.
packages/idlwave/idlw-routine.el:445:23: Warning: the function ‘idlwave-count-memq’ is not known to be defined.
packages/idlwave/idlw-routine.el:421:18: Warning: the function ‘idlwave-do-find-module’ is not known to be defined.
packages/idlwave/idlw-routine.el:356:15: Warning: the function ‘idlwave-shell-is-running’ is not known to be defined.
packages/idlwave/idlw-routine.el:234:20: Warning: the function ‘idlwave-downcase-safe’ is not known to be defined.
packages/idlwave/idlw-routine.el:204:17: Warning: the function ‘idlwave-syslib-p’ is not known to be defined.
packages/idlwave/idlw-routine.el:159:23: Warning: the function ‘idlwave-all-assq’ is not known to be defined.
packages/idlwave/idlw-routine.el:138:32: Warning: the function ‘idlwave-all-class-inherits’ is not known to be defined.
packages/idlwave/idlw-routine.el:91:10: Warning: the function ‘idlwave-sintern-class’ is not known to be defined.
packages/idlwave/idlw-routine.el:90:5: Warning: the function ‘idlwave-sintern-routine-or-method’ is not known to be defined.
Byte compiling packages/idlwave/idlw-scan.el

In idlwave-load-rinfo-next-step:
packages/idlwave/idlw-scan.el:101:14: Warning: reference to free variable ‘idlwave-load-rinfo-steps-done’
packages/idlwave/idlw-scan.el:165:17: Warning: assignment to free variable ‘idlwave-load-rinfo-idle-timer’

In idlwave-load-all-rinfo:
packages/idlwave/idlw-scan.el:175:30: Warning: reference to free variable ‘idlwave-load-rinfo-steps-done’

In idlwave-convert-xml-system-routine-info:
packages/idlwave/idlw-scan.el:398:35: Warning: Unused lexical variable ‘graphics-keywords’
packages/idlwave/idlw-scan.el:407:18: Warning: Unused lexical variable ‘xml-validating-parser’

In idlwave-save-xml-routine-info:
packages/idlwave/idlw-scan.el:501:56: Warning: reference to free variable ‘idlwave-mode-version’

In idlwave-process-sysvars:
packages/idlwave/idlw-scan.el:1766:9: Warning: assignment to free variable ‘idlwave-sint-sysvars’
packages/idlwave/idlw-scan.el:1767:9: Warning: assignment to free variable ‘idlwave-sint-sysvartags’

In idlwave-split-link-target:
packages/idlwave/idlw-scan.el:1809:41: Warning: reference to free variable ‘idlwave-html-link-sep’

In idlwave-substitute-link-target:
packages/idlwave/idlw-scan.el:1817:39: Warning: reference to free variable ‘idlwave-html-link-sep’

In end of data:
packages/idlwave/idlw-scan.el:1794:49: Warning: the function ‘idlwave-sintern-sysvartag’ is not known to be defined.
packages/idlwave/idlw-scan.el:1785:30: Warning: the function ‘idlwave-sintern-sysvar’ is not known to be defined.
packages/idlwave/idlw-scan.el:1783:23: Warning: the function ‘idlwave-split-string’ is not known to be defined.
packages/idlwave/idlw-scan.el:1768:4: Warning: the function ‘idlwave-sintern-sysvar-alist’ is not known to be defined.
packages/idlwave/idlw-scan.el:1753:7: Warning: the function ‘idlwave-shell-routine-info-filter’ is not known to be defined.
packages/idlwave/idlw-scan.el:1717:27: Warning: the function ‘idlwave-find-file-noselect’ is not known to be defined.
packages/idlwave/idlw-scan.el:1716:34: Warning: the function ‘idlwave-shell-temp-file’ is not known to be defined.
packages/idlwave/idlw-scan.el:1237:19: Warning: the function ‘idlwave-expand-path’ is not known to be defined.
packages/idlwave/idlw-scan.el:1182:16: Warning: the function ‘idlwave-routine-source-file’ is not known to be defined.
packages/idlwave/idlw-scan.el:1056:28: Warning: the function ‘idlwave-end-of-statement’ is not known to be defined.
packages/idlwave/idlw-scan.el:738:50: Warning: the function ‘idlwave-html-help-location’ is not known to be defined.
packages/idlwave/idlw-scan.el:738:21: Warning: the function ‘idlwave-recursive-find-file’ is not known to be defined.
packages/idlwave/idlw-scan.el:385:43: Warning: the function ‘idlwave-sys-dir’ is not known to be defined.
packages/idlwave/idlw-scan.el:294:46: Warning: the function ‘idlwave-shell-get-path-info’ is not known to be defined.
packages/idlwave/idlw-scan.el:292:16: Warning: the function ‘idlwave-shell-send-command’ is not known to be defined.
packages/idlwave/idlw-scan.el:115:20: Warning: the function ‘idlwave-sintern-rinfo-list’ is not known to be defined.
packages/idlwave/idlw-scan.el:112:14: Warning: the function ‘idlwave-reset-sintern’ is not known to be defined.
Byte compiling packages/idlwave/idlw-toolbar.el
Byte compiling packages/idlwave/idlw-variables.el
Byte compiling packages/idlwave/idlw-shell.el

In idlwave-shell-mode:
packages/idlwave/idlw-shell.el:971:9: Warning: assignment to free variable ‘idlwave-shell-hide-output’
Byte compiling packages/idlwave/lpath.el

Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Tue, 20 Feb 2024 14:14:02 GMT) Full text and rfc822 format available.

Message #26 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Tue, 20 Feb 2024 09:12:03 -0500
Thanks for your work on this.  I encountered just a few merge conflicts.  Most had to do with assoc-ignore-case -> assoc-string, which I had already fixed on my local repo, and loop -> cl-loop as well. 

I unarchived my repo and pushed these changes to a new branch: https://github.com/jdtsmith/idlwave/commits/emacs-upstream-merge/.  

I will look into the compiler results, fix those up, and give it a test in the next week or so.


> On Feb 19, 2024, at 6:06 PM, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
> 
>> I agree.  I think this has even been suggested before, but I don't have the
>> resources to take it on myself (though I'm happy to test it).  Maybe it's
> 
> Can you test the patch below (which basically applies the
> diff between commits 627e0a14e87 to 77576cd7626e on `emacs.git).
> Clearly, the code reorg made the work harder.
> 
> But it's a bit worse: the split chosen for the reorganization tends
> to create circular dependencies (e.g. all the files need to depend on
> `idlw-variables`, so `idlw-variables` can't depend on anything at all).
> So it's harder to get rid of all the warnings.
> 
> I also attach the warnings resulting from compiling the code (after
> applying the patch).
> 
> 





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 24 Feb 2024 21:41:01 GMT) Full text and rfc822 format available.

Message #29 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 24 Feb 2024 16:39:20 -0500
> Just a brief update.  I updated the version to 6.5.0 across the board, and
> squashed a few compiler complaints.  In some simple testing of idlwave-mode
> (only in the buffer for .pro files) everything seems to be working well.

Good, thanks.

> I am fairly critical of my old idea to refactor everything, but that's
> where we are.  It's a bear to compile everything without putting it on
> the load-path (I'm curious if you just append to the load-path when
> dealing with this kind of thing).

I compile using the method used in `elpa-admin`, which comes down to:

    .PRECIOUS: packages/%.elc
    packages/%.elc: packages/%.el
            @echo 'Byte compiling $<'
            @$(EMACS)                                                    \
                --eval "(setq package-directory-list                     \
                              (list \"$(abspath other-packages)\")       \
                              load-prefer-newer t                        \
                              byte-compile-debug t                       \
                              debug-on-error t                           \
                              package-user-dir \"$(abspath packages)\")" \
                -f package-initialize                                    \
                -L $(dir $@) -f batch-byte-compile $<

So, yes, of course, `-L $(dir $@)` adds the directory to the
`load-path`, but "prepend" rather than "append" (otherwise you'll end
up loading the old version built into Emacs).
I don't consider that to be a problem.


        Stefan





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 24 Feb 2024 21:56:02 GMT) Full text and rfc822 format available.

Message #32 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>,
 69171 <at> debbugs.gnu.org
Cc: Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 24 Feb 2024 16:27:46 -0500
Just a brief update.  I updated the version to 6.5.0 across the board, and squashed a few compiler complaints.  In some simple testing of idlwave-mode (only in the buffer for .pro files) everything seems to be working well.  I am fairly critical of my old idea to refactor everything, but that's where we are.  It's a bear to compile everything without putting it on the load-path (I'm curious if you just append to the load-path when dealing with this kind of thing).

Because of stupid licensing issues, I will have to wait more than a week to test idlw-shell capabilities (which are more complex and therefore more likely to encounter issues).  Will do more testing and fix any encountered errors, then we can proceed with the ELPAfication.  At that point there will be a good argument to remove from core: the ELPA version will be the superset of my changes over a decade and those from core.

> On Feb 20, 2024, at 9:12 AM, JD Smith <jdtsmith <at> gmail.com> wrote:
> 
> Thanks for your work on this.  I encountered just a few merge conflicts.  Most had to do with assoc-ignore-case -> assoc-string, which I had already fixed on my local repo, and loop -> cl-loop as well. 
> 
> I unarchived my repo and pushed these changes to a new branch: https://github.com/jdtsmith/idlwave/commits/emacs-upstream-merge/.  
> 
> I will look into the compiler results, fix those up, and give it a test in the next week or so.
> 
> 
>> On Feb 19, 2024, at 6:06 PM, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>> 
>>> I agree.  I think this has even been suggested before, but I don't have the
>>> resources to take it on myself (though I'm happy to test it).  Maybe it's
>> 
>> Can you test the patch below (which basically applies the
>> diff between commits 627e0a14e87 to 77576cd7626e on `emacs.git).
>> Clearly, the code reorg made the work harder.
>> 
>> But it's a bit worse: the split chosen for the reorganization tends
>> to create circular dependencies (e.g. all the files need to depend on
>> `idlw-variables`, so `idlw-variables` can't depend on anything at all).
>> So it's harder to get rid of all the warnings.
>> 
>> I also attach the warnings resulting from compiling the code (after
>> applying the patch).
>> 
>> 
> 





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Thu, 11 Apr 2024 15:30:01 GMT) Full text and rfc822 format available.

Message #35 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Thu, 11 Apr 2024 11:29:23 -0400
Hi JD,

> Just a brief update.  I updated the version to 6.5.0 across the board, and
> squashed a few compiler complaints.  In some simple testing of idlwave-mode
> (only in the buffer for .pro files) everything seems to be working well.

And further news?


        Stefan





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Thu, 11 Apr 2024 18:36:01 GMT) Full text and rfc822 format available.

Message #38 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Thu, 11 Apr 2024 14:35:00 -0400

> On Apr 11, 2024, at 11:29 AM, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
> 
> Hi JD,
> 
>> Just a brief update.  I updated the version to 6.5.0 across the board, and
>> squashed a few compiler complaints.  In some simple testing of idlwave-mode
>> (only in the buffer for .pro files) everything seems to be working well.
> 
> And further news?

Believe it or not I am *still* waiting on our license server upgrade to be finalized (a particular joy of network license software is when they change vendors and your IT people have to open new ports).  I expect I can look at this quickly when the semester wraps up in a few weeks, make any tweaks necessary for idlw-shell-mode (hopefully few) and green-light for ELPA. 





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Thu, 11 Apr 2024 18:46:01 GMT) Full text and rfc822 format available.

Message #41 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Thu, 11 Apr 2024 14:44:52 -0400
> Believe it or not I am *still* waiting on our license server upgrade to be
> finalized (a particular joy of network license software is when they change
> vendors and your IT people have to open new ports).

Ah!  The perks of proprietary software!
No hurry on my end,


        Stefan





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 27 Apr 2024 20:49:02 GMT) Full text and rfc822 format available.

Message #44 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 27 Apr 2024 15:42:18 -0400
[Message part 1 (text/plain, inline)]
> On Apr 11, 2024, at 2:44 PM, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
> 
>> Believe it or not I am *still* waiting on our license server upgrade to be
>> finalized (a particular joy of network license software is when they change
>> vendors and your IT people have to open new ports).
> 
> Ah!  The perks of proprietary software!
> No hurry on my end,

Our license issues have been sorted out and I've been able to test the idlw-shell capabilities of the emacs-upstream-merge branch.  I had to make a few small tweaks to the help system, as often happens with new IDL releases, but the (funky old) completion and other features continue to work pretty well.  I merged the branch to master and mentioned ELPA in the README.

One question I had is what happens to the texinfo manual for ELPA packages, and if they need any special treatment to get installed.  I am also not 100% sure this will load correctly as a package given the file re-org I did some time back; I've been testing it using a use-package :load-path and that works, but nothing like a real test of the live package.  Can always give it a try after it lands on ELPA and make any changes needed.

Other than that, and any pending suggestions or concerns you had, I think I'm ready to flip the ELPA switch.

Thanks for your work on this.

[Message part 2 (text/html, inline)]

Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 27 Apr 2024 20:49:02 GMT) Full text and rfc822 format available.

Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sat, 27 Apr 2024 21:17:02 GMT) Full text and rfc822 format available.

Message #50 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Philip Kaludercic <philipk <at> posteo.net>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 27 Apr 2024 21:15:56 +0000
JD Smith <jdtsmith <at> gmail.com> writes:

>> On Apr 11, 2024, at 2:44 PM, Stefan Monnier <monnier <at> iro.umontreal.ca> wrote:
>> 
>>> Believe it or not I am *still* waiting on our license server upgrade to be
>>> finalized (a particular joy of network license software is when they change
>>> vendors and your IT people have to open new ports).
>> 
>> Ah!  The perks of proprietary software!
>> No hurry on my end,
>
> Our license issues have been sorted out and I've been able to test the
> idlw-shell capabilities of the emacs-upstream-merge branch.  I had to
> make a few small tweaks to the help system, as often happens with new
> IDL releases, but the (funky old) completion and other features
> continue to work pretty well.  I merged the branch to master and
> mentioned ELPA in the README.
>
> One question I had is what happens to the texinfo manual for ELPA
> packages, and if they need any special treatment to get installed.  

Usually they just have to be listed in the package specification.

>                                                                     I
> am also not 100% sure this will load correctly as a package given the
> file re-org I did some time back; I've been testing it using a
> use-package :load-path and that works, but nothing like a real test of
> the live package.  Can always give it a try after it lands on ELPA and
> make any changes needed.

We can build a package tarball locally and send it to you to try it out
(the procedure isn't complicated, you can also do it yourself if you
prefer).

> Other than that, and any pending suggestions or concerns you had, I think I'm ready to flip the ELPA switch.
>
> Thanks for your work on this.
>

-- 
	Philip Kaludercic on icterid




Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sun, 28 Apr 2024 02:17:02 GMT) Full text and rfc822 format available.

Message #53 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sat, 27 Apr 2024 22:15:41 -0400
> Our license issues have been sorted out and I've been able to test the
> idlw-shell capabilities of the emacs-upstream-merge branch.  I had to make
> a few small tweaks to the help system, as often happens with new IDL
> releases, but the (funky old) completion and other features continue to work
> pretty well.  I merged the branch to master and mentioned ELPA in
> the README.
>
> One question I had is what happens to the texinfo manual for ELPA packages,
> and if they need any special treatment to get installed.  I am also not 100%
> sure this will load correctly as a package given the file re-org I did some
> time back; I've been testing it using a use-package :load-path and that
> works, but nothing like a real test of the live package.  Can always give it
> a try after it lands on ELPA and make any changes needed.
>
> Other than that, and any pending suggestions or concerns you had, I think
> I'm ready to flip the ELPA switch.

Great.  I just added `idlwave` to `elpa.git`.
Currently, no tarball gets released because the build fails with:

    Missing copyright notice in idlwave/lpath.el
    Missing copyright notice in idlwave/idlw-variables.el
    Missing copyright notice in idlwave/idlw-toolbar.el
    Missing copyright notice in idlwave/idlw-scan.el
    Missing copyright notice in idlwave/idlw-routine.el
    Missing copyright notice in idlwave/idlw-menus.el
    Missing copyright notice in idlwave/idlw-complete.el
    Missing copyright notice in idlwave/idlw-bindings.el

because of missing

    Copyright (C) <something>  Free Software Foundation, Inc.

Another problem is that `idlwave.el` doesn't contain an email address
for the maintainer.

Once you fix these things, maybe some other problems will show up.
When all those problems are fixed, we'll get a tarball released in
GNU-devel ELPA, so we can try it out and tweak it until it has the right
shape (GNU-devel packages get rebuilt after "every" commit).

Once it all looks good, you can make a commit that changes the
`Version:` header in `idlwave.el` to trigger a real release in GNU ELPA.


        Stefan





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sun, 28 Apr 2024 12:14:01 GMT) Full text and rfc822 format available.

Message #56 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sun, 28 Apr 2024 08:12:43 -0400
> Currently, no tarball gets released because the build fails <snip> because of missing
> 
>    Copyright (C) <something>  Free Software Foundation, Inc.
> 
> Another problem is that `idlwave.el` doesn't contain an email address
> for the maintainer.

Fixed these.  I removed lpath.el since path munging shouldn't be necessary as a package. 





Information forwarded to elpa-maintainers <at> gnu.org:
bug#69171; Package elpa. (Sun, 28 Apr 2024 15:03:01 GMT) Full text and rfc822 format available.

Message #59 received at 69171 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 69171 <at> debbugs.gnu.org, Stefan Kangas <stefankangas <at> gmail.com>
Subject: Re: bug#69171: Moving packages out of core to ELPA
Date: Sun, 28 Apr 2024 11:01:58 -0400
>> Currently, no tarball gets released because the build fails <snip> because of missing
>> 
>>    Copyright (C) <something>  Free Software Foundation, Inc.
>> 
>> Another problem is that `idlwave.el` doesn't contain an email address
>> for the maintainer.
>
> Fixed these.  I removed lpath.el since path munging shouldn't be necessary as a package. 

Thanks.  Let's see what the next cron-job says (they're run about every 12h).

Please also fix the Maintainers line in `idlwave.el`:

    ;; Maintainer: J.D. Smith

it should have a valid email.


        Stefan





This bug report was last modified 6 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.