[bknr-cvs] r2350 - in branches/bos/thirdparty/emacs/slime: . CVS contrib contrib/CVS doc doc/CVS
ksprotte at common-lisp.net
ksprotte at common-lisp.net
Fri Jan 18 11:07:06 UTC 2008
Author: ksprotte
Date: Fri Jan 18 06:05:59 2008
New Revision: 2350
Added:
branches/bos/thirdparty/emacs/slime/
branches/bos/thirdparty/emacs/slime/.cvsignore
branches/bos/thirdparty/emacs/slime/CVS/
branches/bos/thirdparty/emacs/slime/CVS/Entries
branches/bos/thirdparty/emacs/slime/CVS/Entries.Log
branches/bos/thirdparty/emacs/slime/CVS/Repository
branches/bos/thirdparty/emacs/slime/CVS/Root
branches/bos/thirdparty/emacs/slime/CVS/Template
branches/bos/thirdparty/emacs/slime/ChangeLog
branches/bos/thirdparty/emacs/slime/HACKING
branches/bos/thirdparty/emacs/slime/NEWS
branches/bos/thirdparty/emacs/slime/PROBLEMS
branches/bos/thirdparty/emacs/slime/README
branches/bos/thirdparty/emacs/slime/contrib/
branches/bos/thirdparty/emacs/slime/contrib/CVS/
branches/bos/thirdparty/emacs/slime/contrib/CVS/Entries
branches/bos/thirdparty/emacs/slime/contrib/CVS/Repository
branches/bos/thirdparty/emacs/slime/contrib/CVS/Root
branches/bos/thirdparty/emacs/slime/contrib/CVS/Template
branches/bos/thirdparty/emacs/slime/contrib/ChangeLog
branches/bos/thirdparty/emacs/slime/contrib/README
branches/bos/thirdparty/emacs/slime/contrib/bridge.el
branches/bos/thirdparty/emacs/slime/contrib/inferior-slime.el
branches/bos/thirdparty/emacs/slime/contrib/slime-asdf.el
branches/bos/thirdparty/emacs/slime/contrib/slime-autodoc.el
branches/bos/thirdparty/emacs/slime/contrib/slime-banner.el
branches/bos/thirdparty/emacs/slime/contrib/slime-c-p-c.el
branches/bos/thirdparty/emacs/slime/contrib/slime-editing-commands.el
branches/bos/thirdparty/emacs/slime/contrib/slime-fancy-inspector.el
branches/bos/thirdparty/emacs/slime/contrib/slime-fancy.el
branches/bos/thirdparty/emacs/slime/contrib/slime-fuzzy.el
branches/bos/thirdparty/emacs/slime/contrib/slime-highlight-edits.el
branches/bos/thirdparty/emacs/slime/contrib/slime-parse.el
branches/bos/thirdparty/emacs/slime/contrib/slime-presentation-streams.el
branches/bos/thirdparty/emacs/slime/contrib/slime-presentations.el
branches/bos/thirdparty/emacs/slime/contrib/slime-references.el
branches/bos/thirdparty/emacs/slime/contrib/slime-scheme.el
branches/bos/thirdparty/emacs/slime/contrib/slime-scratch.el
branches/bos/thirdparty/emacs/slime/contrib/slime-tramp.el
branches/bos/thirdparty/emacs/slime/contrib/slime-typeout-frame.el
branches/bos/thirdparty/emacs/slime/contrib/slime-xref-browser.el
branches/bos/thirdparty/emacs/slime/contrib/swank-arglists.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-asdf.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-c-p-c.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-fancy-inspector.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-fuzzy.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-listener-hooks.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-presentation-streams.lisp
branches/bos/thirdparty/emacs/slime/contrib/swank-presentations.lisp
branches/bos/thirdparty/emacs/slime/doc/
branches/bos/thirdparty/emacs/slime/doc/.cvsignore
branches/bos/thirdparty/emacs/slime/doc/CVS/
branches/bos/thirdparty/emacs/slime/doc/CVS/Entries
branches/bos/thirdparty/emacs/slime/doc/CVS/Repository
branches/bos/thirdparty/emacs/slime/doc/CVS/Root
branches/bos/thirdparty/emacs/slime/doc/CVS/Template
branches/bos/thirdparty/emacs/slime/doc/Makefile
branches/bos/thirdparty/emacs/slime/doc/slime-refcard.pdf (contents, props changed)
branches/bos/thirdparty/emacs/slime/doc/slime-refcard.tex
branches/bos/thirdparty/emacs/slime/doc/slime-small.eps
branches/bos/thirdparty/emacs/slime/doc/slime-small.pdf (contents, props changed)
branches/bos/thirdparty/emacs/slime/doc/slime.texi
branches/bos/thirdparty/emacs/slime/doc/texinfo-tabulate.awk
branches/bos/thirdparty/emacs/slime/hyperspec.el
branches/bos/thirdparty/emacs/slime/metering.lisp
branches/bos/thirdparty/emacs/slime/mkdist.sh (contents, props changed)
branches/bos/thirdparty/emacs/slime/nregex.lisp
branches/bos/thirdparty/emacs/slime/sbcl-pprint-patch.lisp
branches/bos/thirdparty/emacs/slime/slime-autoloads.el
branches/bos/thirdparty/emacs/slime/slime.el
branches/bos/thirdparty/emacs/slime/swank-abcl.lisp
branches/bos/thirdparty/emacs/slime/swank-allegro.lisp
branches/bos/thirdparty/emacs/slime/swank-backend.lisp
branches/bos/thirdparty/emacs/slime/swank-clisp.lisp
branches/bos/thirdparty/emacs/slime/swank-cmucl.lisp
branches/bos/thirdparty/emacs/slime/swank-corman.lisp
branches/bos/thirdparty/emacs/slime/swank-ecl.lisp
branches/bos/thirdparty/emacs/slime/swank-gray.lisp
branches/bos/thirdparty/emacs/slime/swank-lispworks.lisp
branches/bos/thirdparty/emacs/slime/swank-loader.lisp
branches/bos/thirdparty/emacs/slime/swank-openmcl.lisp
branches/bos/thirdparty/emacs/slime/swank-sbcl.lisp
branches/bos/thirdparty/emacs/slime/swank-scl.lisp
branches/bos/thirdparty/emacs/slime/swank-source-file-cache.lisp
branches/bos/thirdparty/emacs/slime/swank-source-path-parser.lisp
branches/bos/thirdparty/emacs/slime/swank.asd
branches/bos/thirdparty/emacs/slime/swank.lisp
branches/bos/thirdparty/emacs/slime/test-all.sh (contents, props changed)
branches/bos/thirdparty/emacs/slime/test.sh (contents, props changed)
branches/bos/thirdparty/emacs/slime/xref.lisp
Log:
Added newest SLIME (needed by FiveAM -> arnesi -> slime)
Added: branches/bos/thirdparty/emacs/slime/.cvsignore
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/.cvsignore Fri Jan 18 06:05:59 2008
@@ -0,0 +1,6 @@
+*.x86f
+*.fasl
+*.dfsl
+*.lx64fsl
+*.elc
+_darcs
Added: branches/bos/thirdparty/emacs/slime/CVS/Entries
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/CVS/Entries Fri Jan 18 06:05:59 2008
@@ -0,0 +1,34 @@
+/.cvsignore/1.5/Sun Apr 8 19:23:57 2007//
+/ChangeLog/1.1268/Thu Jan 17 05:53:44 2008//
+/HACKING/1.8/Wed Sep 19 11:08:27 2007//
+/NEWS/1.9/Tue Nov 27 11:50:13 2007//
+/PROBLEMS/1.8/Sun Nov 20 23:31:56 2005//
+/README/1.14/Tue Oct 3 21:49:13 2006//
+/hyperspec.el/1.11/Thu Dec 7 07:36:54 2006//
+/metering.lisp/1.4/Fri Apr 1 20:16:35 2005//
+/mkdist.sh/1.7/Mon Aug 29 20:02:58 2005//
+/nregex.lisp/1.4/Mon Sep 19 08:20:48 2005//
+/sbcl-pprint-patch.lisp/1.1/Fri Feb 17 01:30:21 2006//
+/slime-autoloads.el/1.3/Thu Sep 20 14:59:08 2007//
+/slime.el/1.892/Mon Jan 14 12:08:44 2008//
+/swank-abcl.lisp/1.44/Mon Oct 22 08:36:32 2007//
+/swank-allegro.lisp/1.98/Wed Sep 26 23:15:41 2007//
+/swank-backend.lisp/1.126/Mon Sep 10 15:39:05 2007//
+/swank-clisp.lisp/1.64/Thu Aug 23 19:03:37 2007//
+/swank-cmucl.lisp/1.175/Fri Nov 30 13:10:40 2007//
+/swank-corman.lisp/1.11/Thu Aug 23 19:03:37 2007//
+/swank-ecl.lisp/1.10/Sat Dec 22 02:53:58 2007//
+/swank-gray.lisp/1.10/Wed Apr 12 08:43:55 2006//
+/swank-lispworks.lisp/1.93/Sat Nov 24 08:18:59 2007//
+/swank-loader.lisp/1.75/Sat Nov 24 08:18:59 2007//
+/swank-openmcl.lisp/1.120/Mon Oct 22 08:19:58 2007//
+/swank-sbcl.lisp/1.187/Thu Jan 17 05:53:44 2008//
+/swank-scl.lisp/1.14/Sat Dec 22 13:24:49 2007//
+/swank-source-file-cache.lisp/1.8/Tue Dec 5 13:00:42 2006//
+/swank-source-path-parser.lisp/1.17/Sun Jun 25 08:33:16 2006//
+/swank.asd/1.5/Fri Sep 14 12:41:28 2007//
+/swank.lisp/1.523/Thu Dec 20 10:33:37 2007//
+/test-all.sh/1.2/Mon Aug 29 20:02:58 2005//
+/test.sh/1.9/Mon Aug 27 13:16:49 2007//
+/xref.lisp/1.2/Mon May 17 00:25:24 2004//
+D
Added: branches/bos/thirdparty/emacs/slime/CVS/Entries.Log
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/CVS/Entries.Log Fri Jan 18 06:05:59 2008
@@ -0,0 +1,2 @@
+A D/contrib////
+A D/doc////
Added: branches/bos/thirdparty/emacs/slime/CVS/Repository
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/CVS/Repository Fri Jan 18 06:05:59 2008
@@ -0,0 +1 @@
+slime
Added: branches/bos/thirdparty/emacs/slime/CVS/Root
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/CVS/Root Fri Jan 18 06:05:59 2008
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous at common-lisp.net:/project/slime/cvsroot
Added: branches/bos/thirdparty/emacs/slime/CVS/Template
==============================================================================
Added: branches/bos/thirdparty/emacs/slime/ChangeLog
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/ChangeLog Fri Jan 18 06:05:59 2008
@@ -0,0 +1,13454 @@
+2008-01-17 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank-sbcl.lisp (sbcl-source-file-p): When a buffer is not
+ associated with any file, M-. for names defined there ends up
+ calling SBCL-SOURCE-FILE-P with NIL -- guard against that.
+
+2008-01-14 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (sldb-mode): Add `sldb-quit' to `kill-buffer-hook' to
+ close the debugging machinery on swank side when the SLDB buffer
+ is killed. (Notice that killing the SLDB buffer manually will not
+ restore window configuration in contrast to typing `q'.)
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-delete-and-extract-region): New
+ function. Portable version of `delete-and-extract-region' which
+ returned NIL instead of "", as experienced by Matthias Koeppe.
+
+2008-01-09 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-mode-map): Bind C-c C-t to
+ slime-toggle-trace-fdefinition (as in Lisp buffers) instead of
+ slime-repl-clear-buffer. This binding is useful for untracing
+ functions directly from the trace output. Move
+ slime-repl-clear-buffer to the keybinding C-c M-o.
+
+2008-01-04 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (source-file-source-location): Use the
+ debootstrap readtable when appropriate (fixes occasional reader
+ errors when using "v" on debugger frames that point to functions
+ defined in SBCL). Likewise for the debootstrapping packages.
+ (code-location-debug-source-name): Ensure that we always return a
+ physical namestring, Emacs won't like a pathname or a logical
+ namestring.
+
+2008-01-02 Luís Oliveira <loliveira at common-lisp.net>
+
+ Use sane default values for slime-repl-set-package.
+
+ Previously, when typing `,!p' at the REPL, the current package
+ would have been inserted as a default (although the whole intent
+ was to /change/ the current package in the first place), now
+ nothing is inserted anymore.
+
+ * slime.el (slime-pretty-current-package): rename it to
+ slime-pretty-find-buffer-package and make it use
+ slime-find-buffer-package instead of slime-current-package.
+ (slime-repl-set-package, slime-set-package): use new function.
+
+2008-01-02 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-print-apropos): Simplified: Don't insert action
+ properties anymore for the symbol; they were ignored anyway,
+ because `apropos-follow' (bound to RET in the resulting
+ *SLIME Apropos* buffer) looks for buttons only.
+
+2008-01-02 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-apropos): Update docstring: Apropos doesn't
+ match on regular expressions anymore since 2007-11-24.
+
+2007-12-22 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-scl.lisp (set-stream-timeout, make-socket-io-stream): update
+ for Scieneer CL 1.3.7.
+
+2007-12-20 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (read-softly-from-string): Now actually returns all
+ three values as explained in its docstring.
+
+2007-12-14 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-insert-xref-location): New function. Tries to
+ either insert the file name a function is defined in, or inserts
+ information about the buffer a function was interactively
+ `C-c C-c'd from. Idea from Knut Olav Bøhmer.
+ (slime-insert-xrefs): Use it.
+
+2007-12-04 Helmut Eller <heller at common-lisp.net>
+
+ Simplify the inspector.
+
+ * swank.lisp (inspect-object): Ignore the title value returned
+ from backends.
+
+ * slime.el (slime-open-inspector): Updated accordingly.
+
+2007-12-04 Helmut Eller <heller at common-lisp.net>
+
+ Fix slime-list-thread selector.
+
+ * slime.el (slime-list-threads): Wait for the result before
+ continuing.
+
+2007-12-04 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-insert-result): Use slime-repl-emit-result
+ since handling of markers has changed.
+ (slime-repl-emit-result): New argument: bol.
+
+2007-12-02 Alan Caulkins <fatman at maxint.net>
+
+ Make it possible to close listening sockets.
+
+ * swank.lisp (stop-server, restart-server): New functions.
+ (*listener-sockets*): New variable.
+ (setup-server): Store open sockets in *listener-sockets*.
+
+2007-12-02 Helmut Eller <heller at common-lisp.net>
+
+ Add hook to customize the region used by C-c C-c.
+ Useful to recognize block declarations in CMUCL sources.
+
+ * slime.el (slime-region-for-defun-function): New variable.
+ (slime-region-for-defun-at-point): Use it.
+
+2007-11-30 Helmut Eller <heller at common-lisp.net>
+
+ Handle byte-functions without debug-info.
+
+ * swank-cmucl.lisp (byte-function-location): Return an error
+ if the component has no debug-info.
+
+2007-11-30 Helmut Eller <heller at common-lisp.net>
+
+ Disable the pretty-printer for backtraces.
+ Would be nice if we could print newlines in strings as \n.
+
+ * swank.lisp (*backtrace-printer-bindings*): New varaible.
+ (backtrace, frame-locals-for-emacs): Use it.
+
+2007-11-29 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (valid-function-name-p): Fixed wrt. setf functions.
+
+2007-11-29 Helmut Eller <heller at common-lisp.net>
+
+ Prettify package names for slime-repl-set-package.
+
+ * slime.el (slime-repl-set-package): slime-current-package may
+ have leading colons. Use slime-pretty-package-name to remove
+ them. Reported by Constantine Vetoshev.
+ (slime-pretty-current-package): New function.
+ (slime-set-package): Use it.
+
+2007-11-24 Helmut Eller <heller at common-lisp.net>
+
+ Drop remaining dependencies on nregex.
+
+ * swank-lispworks.lisp (unmangle-unfun): Use sys::setf-symbol-p
+ instead of regexp matching.
+
+ * swank-loader.lisp (*sysdep-files*): Don't include nregex.
+
+2007-11-24 Helmut Eller <heller at common-lisp.net>
+
+ Mirror *modules* in Emacs.
+
+ * slime.el (slime-lisp-modules): New connction variable.
+ (slime-set-connection-info): Load requested modules.
+ (slime-required-modules): New variable.
+ (slime-require, slime-load-contribs): New functions.
+
+ * swank.lisp (connection-info): Include *modules*.
+ (swank-require): Accept a list of modules as argument.
+
+2007-11-24 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (parse-package): The old version didn't pass the
+ test-suite. Now use the reader directly instead of emulating it
+ half-heartedly.
+
+ * slime.el (slime-search-buffer-package): Don't remove double
+ quotes or "#:", swank:parse-package takes care of that.
+
+2007-11-24 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (apropos-symbols): Use simple search instead of
+ regexps.
+ (make-apropos-matcher): Used to be make-regexp-matcher.
+
+ (*sldb-printer-bindings*): Set *print-right-margin* to
+ most-positive-fixnum. This prints each frame in the backtrace in a
+ single long line. But is suboptimal for other purposes, like
+ eval-in-frame.
+
+ (setup-server): Initialize multiprocessing here, so that is also
+ done for create-server.
+
+2007-11-23 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (swank-require): Fix typo (:key was used instead of
+ :test.) Reported by Stelian Ionescu.
+
+2007-11-22 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (swank-require): Don't search the file if the
+ module-name is present in *modules*. That should avoid problems if
+ swank is included in a core file and moved to a different
+ location. Reported by John Wiegley.
+
+2007-11-19 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-repl-mode-map, slime-repl-read-mode),
+ (slime-compiler-notes-mode-map, slime-xref-mode-map),
+ (sldb-mode-map, slime-connection-list-mode-map),
+ (slime-inspector-mode-map): Added bindings for [return] in
+ addition to (kbd "RET"). The reason is that pressing enter in X is
+ translated to (kbd "RET") only if no binding for [return] is
+ active; if [return] is bound to something, pressing enter is
+ translated to this key binding henceforth, as was explained to me
+ by Pierre Gaston, thanks! This can cause quite confusing behaviour
+ as Andreas Davour faced in his post <cs9k5ofqbt7.fsf at Psilocybe.Update.UU.SE>
+ to comp.lang.lisp.
+
+2007-11-06 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-events-buffer, slime-inspector-buffer): Disable
+ undo.
+
+2007-11-01 Tobias C. Rittweiler <tcr at freebits.de>
+
+ The inspector page layout has changed slightly. Before the header
+ looked like
+
+ A proper list.
+ [type: CONS]
+ -------------------
+
+ It now looks like
+
+ #<CONS {B3DBD39}>:
+ A proper list.
+ --------------------
+
+ Rationale is to have a "presentation link" to the currently
+ inspected object itself, to copy it down to the REPL via `M-RET'.
+ This is mostly useful when trying to get a value from the Slime
+ Debugger to the REPL, which you can do by inspecting the value
+ first by `i', and then using `M-RET' on the object representation
+ in the new header layout.
+
+ Such a "presentation link" existed already but was removed in
+ 2007-08-23. The old behaviour was to have the title ("A proper
+ list" in the above example) to contain the link. I decided to make
+ the link more explicit.
+
+ * swank.lisp (inspect-object): Now additionally returns a
+ string-representation of the object itself, and an inspector id
+ for it. Removed returning its type as this is implicit in the new
+ string representation.
+
+ * slime.el (slime-open-inspector): Adapted for new header layout.
+
+2007-10-22 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (read-softly-from-string, unintern-in-home-package):
+ Moved from `contrib/swank-arglist.lisp'.
+ (parse-package): Use them. (Removes FIXME about interning
+ symbols.) Also changed the logic somewhat to avoid passing :|| to
+ FIND-PACKAGE as ECL chokes on that.
+
+2007-10-22 Steve Smith <tarkasteve at gmail.com>
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Added
+ missing `load' argument to function definition on Corman Lisp /
+ ECL.
+
+2007-10-22 Mark Evenson <mark.evenson at gmx.at>
+
+ * swank-abcl.lisp (getpid): Implemented.
+
+2007-10-22 R. Matthew Emerson <rme at thoughtstuff.com>
+
+ * swank-openmcl.lisp (closure-closed-over-values): Use
+ CCL::NTH-IMMEDIATE instead of CCL::%SVREF. This makes it work on
+ x86-64 OpenMCL. (The %SVREF worked on PPC, but this will work on
+ both.)
+
+2007-09-27 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-filesystem-toplevel-directory): New function.
+ Windows doesn't have a filesystem that is as hierarchical as the
+ Unix' one. Reported by Carsten Blaauw and Stefan Kluehspies.
+ (slime-file-name-merge-source-root): Use it.
+ (slime-highlight-differences-in-dirname): Use it.
+
+2007-09-26 Utz-Uwe Haus <haus+slime at mail.math.uni-magdeburg.de>
+
+ * swank-allegro.lisp (fspec-definition-locations): Allow the
+ POSITION datum of :top-level-form fspecs to be missing. This
+ apparently helpful for Allegro CL 8.1.
+
+2007-09-21 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-length=, slime-length>): Restore support for
+ vectors, as `slime-length=' was already used with strings in
+ `slime-parse.el'. This broke extended arglist display.
+
+2007-09-20 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-setup): Call the respective init functions of
+ contribs.
+
+ * slime-autoloads.el (slime-setup-contribs): Ditto.
+
+2007-09-19 Helmut Eller <heller at common-lisp.net>
+
+ Simplify slime-compile-file.
+
+ * slime.el (slime-compile-file): Don't save window config.
+ (slime-curry, slime-rcurry): New functions.
+
+ * slime.el (slime-complete-symbol*-fancy): Move defcustom to
+ contrib/slime-c-p-c.el
+
+ * swank-version.el: Delete file. No longer used.
+
+ * bridge.el: Moved to contrib.
+
+ * tree-widget.el: File deleted. Only needed by contribs and is
+ distributed with Emacs 21.
+
+ * slime.el: Reorder some devfars and menus code so that the
+ compiler doesn't complain about free variables.
+
+ Fix apropos in Emacs 22.
+
+ * slime.el (slime-print-apropos): Add button props for Emacs 22.
+ (slime-call-describer): ARG is a marker in Emacs 22.
+
+ (def-slime-selector-method ?c): Wait until slime-list-threads
+ returns.
+
+ Remove define-slime-dialect.
+
+ * slime.el (define-slime-dialect): Deleted. Use
+ slime-lisp-implementations instead.
+
+ Introduce a slime-start-and-init function.
+
+ * slime.el (slime-start-and-init, slime-lisp-options): New
+ functions.
+ (slime-start-and-load): Use it.
+
+ Simplify slime-length=.
+
+ * slime.el (slime-length=, slime-length>): No need for vectors.
+
+ Remove explicit support for Scheme mode.
+
+ * slime.el (slime-scheme-mode-hook, slime-shared-lisp-mode-hook)
+ Deleted.
+ (slime-indentation-update-hooks): New hook.
+ (slime-handle-indentation-update): Use it.
+
+ Fix close-connection.
+
+ * swank.lisp (close-connection): Use *log-output* instead of
+ *debug-io* (which could be redirected to the to-be-closed
+ connection).
+
+2007-09-15 Helmut Eller <heller at common-lisp.net>
+
+ Let slime-setup load contribs.
+
+ * slime.el (slime-setup): Take a list of contribs to load as
+ argument.
+
+ * slime-autoloads.el (slime-setup): Ditto, but delay the actual
+ loading until slime is loaded.
+ (slime-setup-contribs): New function.
+
+2007-09-15 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-maybe-warn-for-different-source-root): Catch
+ returned NIL from `slime-file-name-merge-source-root' if the two
+ filenames don't share a common source root.
+ Reported by Frank Goenninger.
+
+2007-09-15 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-split-string): New semi-portability function.
+ The behaviour of `split-string' changed between Emacs21 and
+ Emacs22. Thanks to Christophe Rhodes for reporting this.
+ (slime-file-name-merge-source-root): Use `slime-split-string'.
+ (slime-highlight-differences-in-dirname): Likewise.
+
+2007-09-14 Helmut Eller <heller at common-lisp.net>
+
+ Some cleanups for the REPL.
+
+ * slime.el (slime-repl-write-string): Split it up into smaller
+ functions.
+ (slime-repl-emit, slime-repl-emit-result)
+ (slime-emit-string): New functions.
+
+ (slime-repl-save-history): Use prin1 instead of pp.
+
+ (repl-type-ahead): New test case.
+
+2007-09-12 Christophe Rhodes <csr21 at cantab.net>
+
+ Make ASDF:LOAD-OP (and SBCL REQUIRE) happy with swank.asd
+
+ * swank.asd: Define and use a CL-SCRIPT-FILE class for loading as
+ source, even with ASDF:LOAD-OP.
+
+2007-09-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-loader.lisp: Aways compile-file `contrib/swank-asdf.lisp'
+ on SBCL. This fixes "Undefined function" style-warnings when using
+ `slime-asdf' in combination with SBCL. Reported by Cyrus Harmon.
+
+ * swank-sbcl.lisp: Explicitly require ASDF. (While this is not
+ strictly necessary, as it's implicitly loaded on requiring the
+ other modules, I think it's better to be explicit about it.)
+
+2007-09-10 Helmut Eller <heller at common-lisp.net>
+
+ Fix some bugs introduced while moving doc refs to contrib.
+
+ * swank-sbcl.lisp (condition-references): It's still needed.
+
+ * slime.el (sldb-dispatch-extras): Add missing quote.
+ (slime-sbcl-manual-root): Move definition to
+ contrib/slime-references.el.
+ (slime-cl-symbol-name, slime-cl-symbol-package): Move to
+ contrib/slime-parse.el.
+
+2007-09-10 Helmut Eller <heller at common-lisp.net>
+
+ Move SBCL doc references to contrib.
+
+ * slime.el (sldb-insert-condition): Merge REFERENCES and EXTRAS.
+ (sldb-extras-hooks, sldb-dispatch-extras): New hook.
+
+ * swank-backend.lisp (condition-references): Removed. Merged with
+ condition-extras.
+
+ * swank-sbcl.lisp (condition-references): Removed.
+ (condition-extras): Include references.
+ (externalize-reference): New function. Don't return plain
+ symbols.
+
+ * swank-allegro.lisp (condition-references): Removed.
+
+2007-09-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-cl-symbol-name, slime-cl-symbol-package):
+ Ressurected, as they're still used in this file.
+ Reported by Edward Cant.
+
+2007-09-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ When working on multiple source trees simultaneously, the way
+ `slime-edit-definition' (M-.) works can sometimes be confusing:
+
+ `M-.' visits locations that are present in the current Lisp image,
+ which works perfectly well as long as the image reflects the
+ source tree that one is currently looking at.
+
+ In the other case, however, one can easily end up visiting a file
+ in a different source root directory (the one corresponding to the
+ Lisp image), and is thus easily tricked to modify the wrong source
+ files---which can lead to quite some stressfull cursing.
+
+ If the variable `slime-warn-when-possibly-tricked-by-M-.' is
+ T (the default), a warning message is issued to raise the user's
+ attention whenever `M-.' is about opening a file in a different
+ source root that also exists in the source root directory of the
+ user's _current buffer_.
+
+ There's no guarantee that all possible cases are covered, but if
+ you encounter such a warning, it's a strong indication that you
+ should check twice before modifying.
+
+ * slime.el (slime-file-name-merge-source-root): New function.
+ (slime-highlight-differences-in-dirname): New function.
+ (slime-maybe-warn-for-different-source-root): New function.
+ (slime-warn-when-possibly-tricked-by-M-.): New variable (T by default.)
+ (slime-goto-location-buffer): Where appropriate, call
+ `slime-maybe-warn-for-different-source-root'
+
+2007-09-08 Stelian Ionescu <sionescu at common-lisp.net>
+
+ * slime.el (save-restriction-if-possible): Place macro definition
+ above use of the macro, to regain ability to byte-compile-file.
+
+2007-09-08 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Fix message displaying on XEmacs. Reported by Steven E. Harris,
+ and Ken Causey.
+
+ * slime.el (slime-display-message): Resurrect secondary
+ `buffer-name' argument which got lost in 2007-08-24.
+ (slime-format-display-message): Resurrect passing "*SLIME Note*"
+ as default buffer-name to `slime-display-message'.
+
+2007-09-08 Matt Pillsbury <mtbp at rci.rutgers.edu>
+
+ * swank-backend.lisp (definterface): Updated docstring.
+
+2007-09-06 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-write-string): Use case, not ecase, for
+ dispatching targets.Should fix XEmacs compatibility.
+ Reported by Steven E. Harris.
+
+2007-09-05 Didier Verna <didier at xemacs.org>
+
+ * slime.el (slime-filename-translations): Fix custom type.
+
+2007-09-05 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-toggle-trace-fdefinition): Fix typo. The
+ argument for interactive should be "P" not "p".
+
+2007-09-04 Mark Evenson <mark.evenson at gmx.at>
+
+ * swank-abcl.lisp: Call accessors of compiler-condition at load
+ time to work around some ABCL problems.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Move asdf support to contrib.
+
+ * swank-backend.lisp (operate-on-system): Moved to
+ swank-asdf.lisp. It wasn't specialized in any backend.
+
+ * swank.lisp (operate-on-system-for-emacs)
+ (list-all-systems-known-to-asdf, list-asdf-systems): Moved to
+ swank-asdf.lisp.
+
+ * slime.el: Move asdf commands to contrib slime-adsf.el.
+
+ * swank-loader.lisp: Load swank-asdf if ASDF is in
+ *FEATURES*. Also add the contrib source directory to
+ swank::*load-path*.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Move tramp support to contrib.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Move startup animation to contrib.
+
+ * slime.el (slime-repl-banner-function): New hook.
+ (slime-repl-update-banner): Use it and reset markers after calling
+ it.
+ (slime-set-default-directory): Don't call slime-repl-update-banner
+ here.
+ (slime-repl-insert-prompt): Set slime-repl-input-end-mark to
+ point-max.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Move inferior-slime-mode to contrib.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Fix the test suite (except for SBCL).
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Simplify slime-process-available-input.
+
+ * slime.el (slime-process-available-input): We are called in a
+ process filter, i.e. at arbitrary times and in an aribtrary
+ buffer. So it doesn't make sense to save-and-restore the current
+ buffer here
+ (slime-eval-async): Instead, save and restore the buffer here.
+ (slime-net-read-or-lose): New.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Remove request-abort condition.
+
+ * swank-backend.lisp (request-abort): Removed
+ (abort-request): Removed. Replace all (3) uses with ERROR.
+ * swank.lisp (eval-for-emacs): No special case for request-abort.
+ * slime.el (slime-eval-async): Remove optional arg of :abort.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Rename slime-insert-possibly-as-rectangle to slime-insert-indented.
+
+ * slime.el (slime-insert-indented): Renamed. Update callers.
+
+2007-08-31 Helmut Eller <heller at common-lisp.net>
+
+ Move compound prefix completion and autodoc to contrib.
+
+ * swank.lisp (simple-completions): Rewritten for simplicity.
+ (operator-arglist): Rewritten for simplicity.
+
+ * slime.el (slime-complete-symbol-function): Make simple
+ completion the default.
+ (slime-echo-arglist-function, slime-echo-arglist): New hook.
+
+ Remove corresponding key bindigs.
+
+ * slime.el (slime-obsolete-commands): New table. Use it to bind
+ a command with an upgrade notice.
+
+2007-08-31 Andreas Fuchs <asf at boinkor.net>
+
+ * slime.el (slime-reindent-defun): Fixed when used in lisp file
+ buffers. (Similiar patch also provided by Gábor Melis; problem
+ also reported by Jeff Cunningham.)
+
+2007-08-31 Jon Allen Boone <ipmonger at delamancha.org>
+
+ * swank-cmucl.lisp: CMUCL now has an x86-Darwin port as well as
+ the PPC-Darwin version. Changed to conditionalize on the
+ presence of darwin instead of ppc so that slime works with both
+ Darwin versions of CMUCL.
+
+2007-08-31 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-sexp-at-point): Explicitely set current syntax
+ table to operate in `lisp-mode-syntax-table' because
+ `thing-at-point' is used which depends on the syntax table. (E.g.
+ keywords like `:foo' aren't recognized as sexp otherwise.)
+
+ * slime.el (slime-parse-extended-operator/declare): Wrap regexp
+ stuff in `save-match-data'
+ (slime-internal-scratch-buffer): Removed again. Was only
+ introduced as a performance hack; but it turned out that the bad
+ performance was because of unneccessary recursive calls of
+ `slime-make-form-spec-from-string'. (Which was fixed on 2007-08-27
+ already.)
+ (slime-make-form-spec-from-string): Use `with-temp-buffer' instead
+ of `slime-internal-scratch-buffer'. Removed activation of
+ `lisp-mode' in the temporary buffer, because this made
+ `lisp-mode-hooks' run. This activated autodoc in the temp buffer,
+ although the temp buffer is used to compute an autodoc
+ itself (which resulted in some very mutual recursion which caused
+ the current arglist to be displayed again and again---as could
+ have been witnessed in `*Messages*'.) `Lisp-mode' was activated to
+ get the right syntax-table for `slime-sexp-at-point', but this one
+ sets the correct syntax-table itself now.
+
+2007-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Fix user input type-ahead again (this change from 2007-08-25 got
+ lost). Testcase: Type (dotimes (i 5) (format t "Number ~A~%"
+ i) (sleep 1)) and then type ahead while the command is executing
+ and output arrives.
+
+ * slime.el (slime-repl-insert-prompt): Don't go to point-max but
+ to slime-repl-input-start-mark if there is one.
+ (slime-repl-write-string): Insert a :repl-result before the
+ prompt, not at point-max. Update markers properly.
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp (safe-definition-finding): Remove whitespace
+ around error messages.
+ (trim-whitespace): New function.
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ Fix some output related bugs.
+
+ * swank.lisp (send-repl-results-to-emacs): Emit a fresh line.
+
+ * slime.el (slime-insert-transcript-delimiter): Use
+ insert-before-markers since slime-output-end is no longer left
+ inserting. Reported by Austin Haas <austin at pettomato.com>.
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-display-or-scroll-completions,
+ slime-scroll-completions): New functions. Factored out of
+ slime-expand-abbreviations-and-complete.
+
+2007-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-write-string): Handle arbitrary targets
+ using slime-output-target-marker.
+ (slime-last-output-target-id, slime-output-target-to-marker)
+ (slime-output-target-marker)
+ (slime-redirect-trace-output): Move back here from slime-presentations.el.
+
+2007-08-28 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (classify-symbol, symbol-classification->string):
+ Resurrected in swank.lisp. (I was bitten by cvs-pcl which
+ committed (2007-08-27) my locally changed `contribs/swank-fuzzy.lisp'
+ where I already removed these functions from.)
+
+2007-08-28 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-make-form-spec-from-string): Elisp Hacking 101:
+ Don't use `beginning-of-buffer' and `end-of-buffer' in Elisp code.
+
+ * swank.lisp (read-form-spec): Unintern just newly interned
+ symbols when an reader error occurs.
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ Move presentations to contrib. Part II.
+
+ * swank.lisp (*listener-eval-function*): New variables.
+ (listener-eval): Use it
+ (repl-eval): Used to be listener-eval.
+ (*send-repl-results-function*): New variable.
+ (eval-region): Simplify.
+ (track-package, cat): New functions.
+ (slime-repl-clear-buffer-hook): New hook.
+ (slime-repl-clear-buffer): Use it.
+
+2007-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Remove the ID argument from :write-string protocol messages.
+ Everything, except for rigid-indentation tricks, can be achieved
+ by using :write-string in conjunction with :presentation-start and
+ :presentation-end.
+
+ * swank.lisp (present-in-emacs): Unused, removed.
+
+ * swank.lisp (make-output-function-for-target): Remove id argument
+ from :write-string.
+ (send-repl-results-to-emacs): Don't call
+ save-presented-object. Remove id argument from :write-string.
+
+ * slime.el (slime-dispatch-event): Change it here.
+ (slime-write-string, slime-repl-write-string): And here.
+
+2007-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-loader.lisp (*contribs*): Add swank-presentations.
+
+2007-08-27 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-make-extended-operator-parser/look-ahead): Move
+ to end of symbol at point.
+ (slime-make-form-spec-from-string): Fixes unexpected behaviour of
+ `save-excursion'.
+
+2007-08-27 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-sexp-at-point): Fixes a few edge cases were
+ Emacs' `(thing-at-point 'sexp)' behaves suboptimally. For example,
+ `foo(bar baz)' where point is at the ?\(.
+ (slime-internal-scratch-buffer): New. This variable holds an
+ internal scratch buffer that can be reused instead of having to
+ create a new temporary buffer again and again.
+ (slime-make-extended-operator-parser/look-ahead): Uses
+ `slime-make-form-spec-from-string' to parse nested expressions
+ properly.
+ (slime-nesting-until-point): Added docstring.
+ (slime-make-form-spec-from-string): Added new optional parameter
+ for stripping the operator off the passed string representation of
+ a form. Necessary to work in the context of
+ `slime-make-extended-operator-parser/look-ahead'. Added safety check
+ against a possible endless recursion.
+
+ * swank.lisp (parse-form-spec): Looses restriction for nesting.
+
+2007-08-27 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-eval-feature-conditional): Fix typo.
+ (slime-keywordify): Simplify.
+
+2007-08-27 Helmut Eller <heller at common-lisp.net>
+
+ Move presentations to contrib. Part I.
+
+ * slime.el (slime-event-hooks, slime-dispatch-event): New hook.
+ (slime-write-string-function, slime-write-string): New hook.
+ (slime-repl-return-hooks, slime-repl-return): New hook.
+ (slime-repl-current-input-hooks, slime-repl-current-input): New hook.
+ (slime-open-stream-hooks, slime-open-stream-to-lisp): New hook.
+ (sldb-insert-locals, slime-inspector-insert-ispec)
+ (slime-last-expression): Don't use presentations.
+
+2007-08-26 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Reduces needless interning of symbols that was introduced by my
+ recent work on autodoc to a minimum. Also fixes this issue for
+ `slime-complete-form' which always interned symbols even before my
+ changes.
+
+ * slime.el (slime-sexp-at-point): If N is given, but there aren't
+ N sexps available at point, make it return a list of just as many
+ as there are.
+ (slime-make-form-spec-from-string): New. Creates a ``raw form
+ spec'' from a string that's suited for determining newly interned
+ symbols later in Swank.
+ (slime-parse-extended-operator/declare): Uses it.
+
+ * swank.lisp (parse-symbol): Returns internal knowledge, to
+ provide a means for callers to perform a sanity check.
+ (call-with-ignored-reader-errors): New. Abstracted out from
+ `read-incomplete-form-from-string.'
+
+ * swank.lisp (read-form-spec): New. Only READs elements of a form
+ spec if necessary. And if it does have to READ, it keeps track
+ of newly interned symbols which are returned as secondary
+ return value.
+ (parse-form-spec): Use it. Propagate newly interned symbols.
+ (parse-first-valid-form-spec): Likewise.
+ (arglist-for-echo-area, complete-form, completions-for-keyword):
+ Adapted to unintern the newly interned symbols.
+
+
+2007-08-26 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (current-slime-narrowing-configuration):
+ Renamed to `slime-current-narrowing-configuration'.
+ (set-slime-narrowing-configuration):
+ Renamed to `slime-set-narrowing-configuration'.
+ (current-slime-emacs-snapshot):
+ Renamed to `slime-current-emacs-snapshot'.
+ (current-slime-emacs-snapshot-fingerprint):
+ Renamed to `slime-current-emacs-snapshot-fingerprint'.
+ (set-slime-emacs-snapshot):
+ Renamed to `slime-set-emacs-snapshot'.
+
+2007-08-26 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (save-restriction-if-possible): Fixed another typo,
+ duh! Thanks again to Matthias Koeppe.
+
+2007-08-26 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-cl-symbol-name): Handle vertical bars (|)
+ (%slime-nesting-until-point): Renamed to `slime-nesting-until-point'.
+
+2007-08-25 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Fix a bug where REPL results would sometimes be indented by a
+ random amount.
+
+ * slime.el (slime-insert-presentation): Make the
+ rectangle-ification of multi-line presentations, introduced
+ 2006-12-19, optional.
+ (slime-write-string): Use it here only for regular output, but not
+ for REPL results.
+ (sldb-insert-locals): Use it here.
+ (slime-inspector-insert-ispec): Use it here.
+
+2007-08-25 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Fix handling of user-input type-ahead in the REPL.
+ Reported by Madhu <enometh at meer.net> on 2007-04-24.
+
+ * slime.el (slime-write-string): Make sure text properties are
+ rear-nonsticky, so typed-ahead user input does not pick up the
+ text properties. Fix up some markers.
+ (slime-reset-repl-markers): Make the marker slime-output-end of
+ insertion type nil (no automatic advances on insertions).
+ (slime-with-output-end-mark): Update the location of
+ slime-output-end here manually.
+ (slime-repl-update-banner): Use insert-before-markers.
+
+2007-08-25 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ New command slime-redirect-trace-output creates a separate Emacs
+ buffer, where all subsequent trace output is sent.
+
+ * slime.el (slime-last-output-target-id): New variable.
+ (slime-output-target-to-marker): New variable.
+ (slime-output-target-marker): New function.
+ (slime-write-string): Handle general "target" arguments using
+ slime-output-target-marker.
+ (slime-redirect-trace-output): New command.
+ (slime-easy-menu): Add a menu item for it.
+
+ * slime.el (slime-mark-presentation-start)
+ (slime-mark-presentation-end): Make "target" argument optional.
+ Use slime-output-target-to-marker.
+
+ * swank.lisp (make-output-stream-for-target): New function,
+ factored out from open-streams.
+ (open-streams): Use it here.
+
+ * swank.lisp (connection): New slot "trace-output".
+ (call-with-redirected-io): Use it here.
+ (redirect-trace-output): New slimefun; set the slot to a new
+ target stream.
+
+2007-08-25 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (save-restriction-if-possible): Fixed typo in
+ macroexpansion. Thanks to Matthias Koeppe for reporting.
+
+2007-08-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-insert-arglist): Removed, superseded by
+ slime-complete-form since 2005-02-20.
+
+ * swank.lisp (arglist-for-insertion): Now unused, removed.
+
+2007-08-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Some fixes to the presentation-streams contrib.
+
+ * slime.el (slime-dispatch-event): Handle new optionals args of
+ messages :presentation-start and :presentation-end.
+
+ * slime.el (slime-mark-presentation-start)
+ (slime-mark-presentation-end): New arg "target"; record
+ presentation boundaries separately for REPL results and regular
+ process output. This fixes the presentation markup of REPL
+ results when the presentation-streams contrib is loaded.
+
+2007-08-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Make the fancy presentation-streams feature a contrib.
+ Previously, it was only available if "present.lisp" was loaded
+ manually. Now it can be loaded automatically using:
+
+ (add-hook 'slime-load-hook
+ (lambda () (require 'slime-presentation-streams)))
+
+ Note that the normal presentations that are created by REPL
+ results, the inspector, and the debugger are NOT dependent on this
+ code.
+
+ * present.lisp: Moved to contrib/swank-presentation-streams.lisp.
+ * swank-loader.lisp (*contribs*): Add swank-presentation-streams.
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ Move typeout frame to contrib.
+
+ * slime.el (slime-message-function, slime-background-message-function)
+ (slime-autodoc-message-function): New variables.
+ (slime-message, slime-background-message)
+ (slime-autodoc-message): Call the function in the respective
+ variable, so that the typeout window can be plugged in.
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ Move xref and class browser to contrib.
+
+ * slime.el (slime-browse-classes, slime-browse-xrefs): Gone. The
+ Common Lisp part is still there.
+
+2007-08-24 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-forward-blanks): Wrapped w/ `ignore-errors.'
+ (slime-sexp-at-point): Return results as a list of strings, rather
+ than just one big string if called with arg > 1.
+ (slime-parse-extended-operator-name): Wrapping some movement code
+ in `ignore-errors'. Adapted to new return value of
+ `slime-enclosing-form-specs'. Minor cosmetic changes.
+ (slime-make-extended-operator-parser/look-ahead): Adapted to
+ changes of the ``raw form spec'' format; returns a form of
+ strings, instead of a string of a form.
+ (slime-parse-extended-operator/declare): Simplified. Adapted to
+ changes of the ``raw form spec'' format; passes decl-identifiers,
+ or typespec-operators respectively, along the decl/type-spec.
+ (%slime-in-mid-of-typespec-p): Removed. Replaced by an regexp
+ based approach.
+ (%slime-nesting-until-point): New helper for
+ `slime-parse-extended-operator/declare'.
+
+ * swank.lisp (parse-form-spec): Adapted to new ``raw form spec''
+ format. Updated format description in docstring accordingly. The
+ new format allows less interning of wrong symbols names comming
+ from Slime. Thanks to Matthias Koeppe for spotting this.
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ Move slime-highlight-edits-mode to contrib.
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ Move slime-scratch to contrib.
+
+ * slime.el (slime-scratch): Gone.
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ Various cleanups related to slime-insert-propertized.
+
+ * slime.el (slime-with-rigid-indentation): Fix evaluation order.
+ (slime-indent-rigidly): New.
+ (slime-insert-possibly-as-rectange): Don't set mark.
+ (slime-insert-propertized): Use plain insert instead of
+ slime-insert-possibly-as-rectange.
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (sbcl-inspector): Fix typo.
+
+2007-08-23 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Repair inspection of presentations.
+
+ * swank.lisp (inspect-presentation): New slimefun.
+ * slime.el (slime-inspect-presentation-at-mouse): Use it here.
+
+2007-08-23 Helmut Eller <heller at common-lisp.net>
+
+ Move Marco Baringer's inspector to contrib.
+
+ * swank.lisp (*default-inspector*): New variable. Set this
+ variable dispatch to different inspectors.
+ (inspect-object): Use it.
+
+ * swank-loader.lisp (*contribs*): Add 'swank-fancy-inspector.
+
+ * swank-backend.lisp (backend-inspector): New class. Introduce a
+ named class to give as another way to dispatch to backend methods.
+
+ * swank-cmucl.lisp: Use backend-inspector class.
+ * swank-sbcl.lisp: Use backend-inspector class.
+ * swank-clisp.lisp: Use backend-inspector class.
+ * swank-lispworks.lisp: Use backend-inspector class.
+ * swank-allegro.lisp: Use backend-inspector class.
+ * swank-openmcl.lisp: Use backend-inspector class.
+ * swank-abcl.lisp: Use backend-inspector class.
+ * swank-corman.lisp: Use backend-inspector class.
+ * swank-scl.lisp: Use backend-inspector class.
+
+2007-08-23 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Added arglist display for declaration specifiers and type
+ specifiers.
+
+ Examples:
+
+ `(declare (type' will display
+
+ (declare (type type-specifier &rest vars))
+
+ `(declare (type (float' will display
+
+ [Typespec] (float &optional lower-limit upper-limit)
+
+ `(declare (optimize' will display
+
+ (declare (optimize &any (safety 1) (space 1) (speed 1) ...))
+
+ &ANY is a new lambda keyword that is introduced for arglist
+ description purpose, and is very similiar to &KEY, but isn't based
+ upon plists; they're more based upon *FEATURES* lists. (See the
+ comment near the ARGLIST defstruct in `swank.lisp'.)
+
+ * slime.el:
+ (slime-to-feature-keyword): Renamed to `slime-keywordify'.
+ (slime-eval-feature-conditional): Adapted to use `slime-keywordify'.
+ (slime-ensure-list): New utility.
+ (slime-sexp-at-point): Now takes an argument that specify how many
+ sexps at point should be returned.
+ (slime-enclosing-operator-names): Renamed to
+ `slime-enclosing-form-specs'.
+ (slime-enclosing-form-specs): Returns a list of ``raw form specs''
+ instead of what was called ``extended operator names'' before, see
+ `swank::parse-form-spec' for more information. This is a
+ simplified superset. Additionally as tertiary return value return
+ a list of points to let the caller see where each form spec is
+ located. Adapted callers accordingly. Extended docstring.
+ (slime-parse-extended-operator-name): Adapted to changes in
+ `slime-enclosing-form-specs'. Now gets more context, and is such
+ more powerful. This was needed to allow parsing DECLARE forms.
+ (slime-make-extended-operator-parser/look-ahead): Because the
+ protocol for arglist display was simplified, it was possible to
+ replace the plethora of parsing function just by this one.
+ (slime-extended-operator-name-parser-alist): Use it. Also add
+ parser for DECLARE forms.
+ (slime-parse-extended-operator/declare): Responsible for parsing
+ DECLARE forms.
+ (%slime-in-mid-of-typespec-p): Helper function for
+ `slime-parse-extended-operator/declare'.
+ (slime-incomplete-form-at-point): New. Return the ``raw form
+ spec'' near point.
+ (slime-complete-form): Use `slime-incomplete-form-at-point'.
+
+ * swank.lisp: New Helper functions.
+ (length=, ensure-list, recursively-empty-p): New.
+ (maybecall, exactly-one-p): New.
+
+ * swank.lisp (arglist-for-echo-area): Adapted to take ``raw form
+ specs'' from Slime.
+ (parse-form-spec): New. Takes a ``raw form spec'' and returns a
+ ``form spec'' for further processing in Swank. Docstring documents
+ these two terms.
+ (split-form-spec): New. Return relevant information from a form spec.
+ (parse-first-valid-form-spec): Replaces `find-valid-operator-name'.
+ (find-valid-operator-name): Removed.
+ (operator-designator-to-form): Removed. Obsoleted by `parse-form-spec'.
+
+ (defstruct arglist): Add `any-p' and `any-args' slots to contain
+ arguments belonging to the &ANY lambda keyword.
+ (print-arglist): Adapted to also print &ANY args.
+ (print-decoded-arglist-as-template): Likewise.
+ (decode-arglist): Adapted to also decode &ANY args.
+ (remove-actual-args): Adapted to also remove &ANY args.
+ (remove-&key-args): Split out from `remove-actual-args'.
+ (remove-&any-args): New. Removes already provided &ANY args.
+ (arglist-from-form-spec): New. Added detailed docstring.
+ (arglist-dispatch): Dispatching generic function for
+ `arglist-from-form-spec' that does all the work. Renamed from
+ prior `form-completion'.
+ (arglist-dispatch) Added methods for dealing with declaration and
+ type-specifiers.
+ (complete-form): Adapted to take ``raw form specs'' from Slime.
+ (completions-for-keyword): Likewise.
+ (format-arglist-for-echo-area): Removed. Not needed anymore.
+
+ * swank-backend.lisp (declaration-arglist): New generic
+ function. Returns the arglist for a given declaration
+ identifier. (Backends are supposed to specialize it if they can
+ provide additional information.)
+ (type-specifier-arglist): New generic function. Returns the
+ arglist for a given type-specifier operator. (Backends are
+ supposed to specialize it if they can provide additional
+ information.)
+ (*type-specifier-arglists*): New variable. Contains the arglists
+ for the type specifiers in Common Lisp.
+
+ * swank-sbcl.lisp: Now depends upon sb-cltl2.
+ (declaration-arglist 'optimize): Specialize the `optimize'
+ declaration identifier to pass it to
+ sb-cltl2:declaration-information.
+
+
+2007-08-23 Helmut Eller <heller at common-lisp.net>
+
+ Some inspector cleanups.
+
+ * slime.el (slime-inspect): Remove dwim stuff and drop keyword
+ args.
+ (slime-read-object): Killed.
+ (slime-open-inspector): Drop keyword args. Update callers
+ accodordingly, expect presentation related code. Presentations no
+ longer work in the inspector.
+
+ * swank.lisp (*inspector-dwim-lookup-hooks*)
+ (default-dwim-inspector-lookup-hook): Deleted.
+ (init-inspector): Sanitize arglist.
+ (inspect-object): Don't return an :id for *inspectee-parts*.
+
+ * swank-backend (type-for-emacs): Removed. No backend implemented
+ it.
+
+2007-08-23 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-fuzzy-upgrade-notice): New function. Bound to
+ the key where slime-fuzzy-complete-symbol used to be.
+
+2007-08-22 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-close-all-parens-in-sexp): Fix interplay with
+ `slime-close-parens-limit'. This should also affect
+ `slime-complete-form' (C-c C-s) in a positive way.
+
+2007-08-19 Helmut Eller <heller at common-lisp.net>
+
+ * contrib: New directory. Move fuzzy completion code to that
+ directory.
+
+ * swank.lisp (swank-require): New function to load contrib code.
+ (*find-module*, module-filename, *load-path*, merged-directory)
+ (find-module, module-canditates): New. Pathname acrobatics for
+ swank-require.
+
+ * swank-loader.lisp: Compile (but don't load) contribs.
+ (*contribs*, contrib-source-files): New.
+
+2007-08-16 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-process-available-input): Correct yesterday's
+ change: the buffer a request was originally performed in doesn't
+ necessarily exist at this time anymore, so we check for buffer
+ liveness now.
+
+ The problem arised when quitting in SLDB which would cause Swank
+ to send a `:debug-return' message before the acknowledgement
+ message for `sldb-quit' is sent. So the acknowledgement is
+ received in a context where the sldb-buffer is closed already.
+
+2007-08-15 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-process-available-input): Make sure that the
+ event received from SWANK is processed in the context of the
+ original buffer the request of the response was performed in.
+ Previously, the clauses of `slime-rex' were processed in the
+ internal *cl-connection* buffer. And as a result the continuations
+ passed to `slime-eval' and `slime-eval-async' ditto.
+
+2007-08-15 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Make `M-.' work on definitions outside the current restriction.
+ `M-,' will also properly restore the narrowing as of before the
+ jump. Similiarly for quiting from the compilation notes buffer and
+ the Xref buffers.
+
+ * slime.el (slime-narrowing-configuration, slime-emacs-snapshot),
+ (current-slime-narrowing-configuration),
+ (set-slime-narrowing-configuration),
+ (current-slime-emacs-snapshot),
+ (set-slime-emacs-snapshot),
+ (current-slime-emacs-snapshot-fingerprint): New. Emacs' window
+ configurations do not restore narrowing, so introduce a
+ snapshot facility that contains the necessary information.
+
+ * slime.el: Various renaming and adaptions in the Slime temp
+ buffer, xref, goto-definition and compilation notes section to use
+ the newly introduced snapshots instead of mere window
+ configurations.
+
+ * slime.el: (slime-highlight-notes, slime-remove-old-overlays):
+ Still operate on whole buffer, but restore previous restriction if
+ there was any.
+ (slime-goto-location-position): Now widens the buffer to properly
+ jump to definitions outside of the current restriction.
+
+ * slime.el (slime-push-definition-stack),
+ (slime-pop-find-definition-stack): Now also stores information
+ about narrowing on the definition stack, in order to properly
+ restore narrowing on `M-,'.
+
+ * slime.el (def-slime-test narrowing): Test case for properly
+ dealing with narrowing.
+
+ * slime.el (slime-buffer-narrowed-p): New function, tests whether
+ the current buffer is narrowed or not.
+ (save-restriction-if-possibly): Like `save-restriction', but not
+ as strict---see doc string.
+
+ * slime.el (slime-length=): New function; semantically the same
+ as (= (length seq) n), but more efficiently implemented for lists.
+ Changed the above pattern into a call to SLIME-LENGTH= where
+ appropriate.
+
+2007-08-05 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (backtrace): Handle printer errors while printing a
+ frame. This makes debugging print-object methods with SLIME
+ easier. Reported by Utz-Uwe Haus.
+
+2007-08-02 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-kill-all-buffers): Now also kills all buffers
+ beginning with a `*SLIME' prefix (like, for instance, `*SLIME
+ Apropos*', or `*SLIME macroexpansion*'.)
+
+2007-06-28 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (def-slime-selector-method): Revert Marco's change from
+ 2007-05-23. BODY can return a buffer name, like "*slime-events*".
+ Handle that and never ignore invalid return values. Force BODY to
+ abort if there's no suitable buffer. Why would you want to switch
+ buffers if the desired buffer doesn't exist?
+
+2007-06-27 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Fixing `C-c M-q' at the REPL. Thanks to André Thieme for pointing
+ out that it has been broken since several months.
+
+ * slime.el (slime-reindent-defun): Use functions
+ `slime-beginning-of-defun' and `slime-end-of-defun' that were
+ introduced in the last changeset.
+
+2007-06-16 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el: Pressing `C-M-a' (beginning-of-defun) in midst of the
+ last REPL prompt directs the cursor to the beginning of the
+ prompt. Pressing it again, would do nothing; now it moves the
+ cursor to the start of the previous prompt (as it's consistent
+ with the behaviour when the cursor was placed midst one of the old
+ prompts.)
+
+ Likewise for `C-M-e' (end-of-defun)
+
+ Additionally fixing `C-c C-s' (slime-complete-form) at the REPL.
+
+ (slime-keys): New bindings for `C-M-a' and `C-M-e' to
+ SLIME-BEGINNING-OF-DEFUN and SLIME-END-OF-DEFUN respectively.
+ (slime-keys): Making `C-c C-q' (slime-close-parens-at-point)
+ obsolete, as it didn't work correctly on the REPL.
+ (slime-repl-mode-map): Removed bindings for `C-M-a' and `C-M-e',
+ as they're now inherited from SLIME-KEYS.
+ (slime-repl-beginning-of-defun, slime-repl-end-of-defun): Jump to
+ the previous (next) prompt if called twice in a row.
+
+ (slime-close-parens-at-point): Commented out.
+ (slime-close-all-sexp): Renamed to SLIME-CLOSE-ALL-PARENS-IN-SEXP.
+ (slime-close-all-parens-in-sexp): Modified to take
+ SLIME-CLOSE-PARENS-LIMIT into account.
+ (slime-complete-form): Use SLIME-CLOSE-ALL-PARENS-IN-SEXP.
+
+
+2007-05-24 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Fixed regression in completion: "swank[TAB]" would
+ previously be completed to "swank-backend:"; "get-internal[TAB]"
+ would be completed to "get-internal-r-time" (instead of simply
+ "get-internal-r"); and "custom:*comp[TAB]" would be completed to
+ "custom:*compiled-" on CLISP, even though there's a
+ "custom:*complile-".
+
+ Thanks to Ken Causey for helping me find the first two.
+
+ (completions): Revert changes from 2007-05-11.
+ (longest-compound-prefix): Fixed to properly generate a compound
+ _prefix_.
+
+2007-05-23 Marco Baringer <mb at bese.it>
+
+ * slime.el (def-slime-selector-method): Allow the selector body to
+ not return a buffer. This means that, instead of being to forced
+ to signal an error when a choosen buffer can't be found (like
+ choosing d when there are no debugger buffers) can simply display
+ a message.
+
+ Fix handling of auto-flushing on sbcl:
+
+ * swank-sbcl.lisp (*auto-flush-interval*): New variable
+ controlling how often streams are flushed.
+ (*auto-flush-lock*): New lock guarding access to the shared
+ variable *auto-flush-streams*.
+ (make-stream-interactive): Wrapped access to *auto-flush-streams*
+ in a call-with-recursive-lock-held.
+ (flush-streams): Wrapped in call-with-recursive-lock-held.
+
+2007-05-17 Martin Simmons <martin at lispworks.com>
+
+ * swank-lispworks.lisp (lispworks-inspect): Fix hanging caused by
+ mapcan, i.e. nconc, on a constant list returned by
+ label-value-line.
+
+2007-05-17 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-complete-form): Only insert a closing
+ parenthesis if the form is not already closed. Reported by and
+ adapted from Mac Chan.
+
+2007-05-17 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Fixed bug in completion as previously "swank:[tab]"
+ would correctly list all the symbols in SWANK, but would
+ simultaneously append a spooky dash to the original
+ string ("swank:-").
+
+ (completions): Strip off the package identifier part, and only
+ compute the longest compound prefix for the actual symbol
+ identifiers.
+ (untokenize-symbol): New function. Inverse of TOKENIZE-SYMBOL.
+ (format-completion-result): Use UNTOKENIZE-SYMBOL.
+
+2007-05-17 Dustin Long <dlong at stevens.edu>
+
+ * swank-ecl.lisp (compile-from-stream): Fixed typo that prevented
+ `slime-compile-defun' from actually compiling a function.
+
+2007-05-17 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-loader.lisp (*sysdep-files*): Load the auxiliary files
+ swank-source-*.lisp before swank-sbcl.lisp to avoid
+ undefined-function style warnings.
+
+2007-05-16 Takehiko Abe <keke at gol.com>
+
+ * swank.lisp (inspect-for-emacs file-stream, stream-error): Fixed
+ typo in keyword arg; it's `:refreshp', not `:refresh'.
+
+2007-05-14 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el: Fixed proper handling of the abortion of a
+ request. (For instance, when calling (SWANK::ABORT-REQUEST "FOO")
+ from the REPL.)
+
+ (sldb-quit): Updated the DESTRUCTURE-CASE clause for (:abort) to
+ take an argument.
+ (sldb-continue): Likewise.
+ (sldb-invoke-restart): Likewise.
+ (sldb-break-with-default-debugger): Likewise.
+ (sldb-return-from-frame): Likewise.
+ (sldb-restart-frame): Likewise.
+ (slime-repl-eval-string) Likewise.
+ (slime-repl-show-abort): Now also inserts the reason for the abort
+ into the REPL buffer.
+
+ * swank.lisp (eval-for-emacs): Remove code that would suggest that
+ it's possible to use the rex `(:abort ...)' with more than one
+ argument.
+
+2007-05-14 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Liberated from unnecessary style-warnings!
+
+ (eval-for-emacs): Don't use SLOT-VALUE on condition objects!
+ (inspect-bigger-piece-actions): Changed from DEFMETHOD to DEFUN.
+ (inspect-whole-thing-action): Likewise.
+ (inspect-show-more-action): Likewise.
+ (make-symbols-listing): Adds an explicit DEFGENERIC.
+ (menu-choices-for-presentation): Likewise.
+
+ (make-symbols-listing (eql :classification)): Use `(loop for k
+ being EACH hash-key ...)' rather than `(loop for k being THE
+ hash-key)', to omit the justified style-warning from CLISP.
+
+2007-05-14 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (package-names): Make sure to return a fresh list.
+ (fuzzy-find-matching-packages): Use PACKAGE-NAMES.
+ (list-all-package-names): Use PACKAGE-NAMES.
+
+2007-05-13 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-pretty-lambdas): Removed. If you really want
+ this, please use one of the external ressources that provide this;
+ for instance, `pretty-lambda.el', `pretty-greek.el', or even
+ `pretty-symbols.el'. For more information, please see
+
+ http://www.emacswiki.org/cgi-bin/wiki/PrettyLambda
+
+2007-05-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (fuzzy-find-matching-symbols): Modified to take
+ package nicknames into account. Previously, fuzzy completing on
+ nicknames did (except for some incidental cases) not work. Thanks
+ to Luís Oliveira and Attila Lendvai for pointing that out.
+
+2007-05-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Removed support for completing to the longest compound pre- and
+ suffix with the default completion method (C-c TAB, or just TAB on
+ the REPL), because it has been causing trouble all the time, but
+ didn't offer any real advantage besides niftiness. E.g.:
+
+ previous behaviour:
+
+ asdf:*com TAB => asdf:*compile-file--behaviour*
+
+ now simply:
+
+ asdf:*com TAB => asdf:*compile-file-
+
+ For discussing on this subject, please see the mail with
+ message-id <87y7l53lch.fsf at freebits.de> that was posted to
+ slime-devel 2007-04-06, or alternatively:
+
+ http://common-lisp.net/pipermail/slime-devel/2007-April/006087.html
+
+ * swank.lisp (make-compound-prefix-matcher): New function.
+ Abstracted from COMPOUND-PREFIX-MATCH.
+ (compound-prefix-match): Use MAKE-COMPOUND-PREFIX-MATCHER.
+ (compound-prefix-match/ci/underscores): Removed.
+
+ (longest-completion): Renamed to LONGEST-COMPOUND-PREFIX. Changed
+ to only return a compound prefix, instead of a concatenation of a
+ compound prefix and a compound suffix. Added an &optional
+ parameter to specify what delimeter the passed string is
+ compounded with.
+ (tokenize-completion): Takes additional parameter to specify the
+ delimeter for tokenization.
+ (longest-completion/underscores): Removed; not needed anymore.
+ (tokenize-completion/underscores): Likewise.
+ (untokenize-completion/underscores): Likewise.
+
+ (completions): Slight docstring modification, also added an
+ examplary use case; use LONGEST-COMPOUND-PREFIX instead of
+ LONGEST-COMPLETION.
+ (completions-for-character): Use LONGEST-COMPOUND-PREFIX, and
+ MAKE-COMPOUND-PREFIX-MATCHER.
+ (completions-for-keyword): Use LONGEST-COMPOUND-PREFIX.
+
+2007-05-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (apropos-symbols): Really use MAKE-REGEXP-MATCHER.
+
+2007-05-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Previously when using SLIME-APROPOS-PACKAGE, only
+ those symbols were considered whose home package matched the
+ given package; this would, however, prevent all those symbols from
+ being listed that are imported from another package, and then
+ exported again in the package they got imported into. (As an
+ example, SWANK:RESTART-FRAME is actually from SWANK-BACKEND.)
+
+ (apropos-matcher): Renamed to MAKE-REGEXP-MATCHER.
+ (make-regexp-matcher): Changed to only match for a given regexp.
+ (apropos-symbols): Use MAKE-REGEXP-MATCHER.
+
+2007-05-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el: Fix macroexpanding on things like ",(loop ...)".
+
+ (slime-sexp-at-point-for-macroexpansion): New function; like
+ SLIME-SEXP-AT-POINT-OR-ERROR, but fixes up some misbehaviour with
+ respect to macroexpansion.
+ (slime-eval-macroexpand, slime-eval-macroexpand-inplace): Use the
+ new function.
+
+2007-05-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el: Within the Slime Inspector, `S-Tab' will now also work
+ on X. Furthermore `Tab' and `S-Tab' will now correctly wrap
+ around the beginning and end of the buffer; priorly it'd hang on
+ the beginning with a message "Beginning of buffer", and would
+ require an additional `S-Tab'.
+
+ (slime-inspector-mode-map): Attached `[backtab]' to
+ SLIME-INSPECTOR-PREVIOUS-INSPECTABLE-OBJECT, as Emacs translates
+ `S-Tab' to `Backtab' on X.
+ (slime-find-inspectable-object): New function; finds next or
+ previous inspectable object.
+ (slime-inspector-next-inspectable-object): Mostly rewritten. Use
+ SLIME-FIND-INSPECTABLE-OBJECT to make the code clearer.
+
+2007-04-19 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-backend.lisp (label-value-line): Add :newline as &key
+ argument; if true (the default) inserts a newline.
+
+ * swank.lisp (inspect-for-emacs-list): Don't add a newline after
+ the last value of the list.
+
+2007-04-18 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (log-event): Setup the printer so that, no matter
+ what the global values of the *print-XYZ* variables, this function
+ works as expected.
+ (*debug-on-swank-error*): New variable.
+ (defpackage :swank): Export *debug-on-swank-error*.
+ (with-reader-error-handler): When *debug-on-swank-error* is
+ non-nil drop into a debugger.
+ (dispatch-loop): Idem.
+
+2007-04-17 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Instead of just having all the symbols of a package
+ listed alphabetically in the inspector page recently introduced
+ for that purpose, add a button to that page to group them by their
+ classification.
+
+ (%package-symbols-container): New slot GROUPING-KIND.
+ (%make-package-symbols-container): New function; wraps around
+ %%MAKE-PACKAGE-SYMBOLS-CONTAINER, which will actually create the
+ structure. We need this, to make GROUPING-KIND an entirely
+ internal affair.
+
+ (make-symbols-listing): New generic function to dispatch on
+ GROUPING-KIND.
+ (make-symbols-listing :symbol): Just the stuff that was priorly
+ wired into INSPECT-FOR-EMACS (%PACKAGE-SYMBOLS-CONTAINER).
+ (make-symbols-listing :classification): New; returns the passed
+ symbols grouped by their classification.
+ (inspect-for-emacs %package-symbols-container): Most code split
+ off into MAKE-SYMBOLS-LISTING.
+
+2007-04-17 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (swank-compiler): Fix the return value to always be a
+ list of two elements even if the abort restart is invoked which
+ originally just returned NIL. (Which wouldn't play with the recent
+ change to use DESTRUCTURING-BIND in SLIME-COMPILATION-FINISHED.)
+
+2007-04-17 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (inspect-for-emacs %package-symbols-container):
+ Revert Marco's change from 2007-04-08; he had the good idea of
+ adding a facility to jump to the relevant source line of a symbol,
+ but `M-.' is already bound to SLIME-FIND-DEFINITION in the
+ inspector, which is a nicer way of doing this alltogether.
+
+2007-04-16 Takehiko Abe <keke at gol.com>
+
+ * swank-openmcl.lisp (accept-connection, find-external-format):
+ utf-8 support.
+
+2007-04-16 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-with-xref-buffer): Added missing ,
+
+2007-04-16 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el: Pressing `q' in *compiler notes* after a `C-c C-k' or
+ `C-c M-k' would not probably restore the original window
+ configuration. Fix that.
+
+ (slime-get-temp-buffer-create): New &key arg WINDOW-CONFIGURATION.
+ (slime-with-xref-buffer): Likewise.
+
+ (slime-compilation-finished): New &optional arg WINDOW-CONFIG.
+ (slime-maybe-show-xrefs-for-notes): Likewise.
+ (slime-show-xrefs) Likewise.
+ (slime-maybe-list-compiler-notes): Likewise.
+ (slime-list-compiler-notes): Likewise.
+
+ (slime-compilation-finished-continuation): Renamed to
+ SLIME-MAKE-COMPILATION-FINISHED-CONTINUATION.
+
+ (slime-make-compilation-finished-continuation): Now takes two
+ args, the current buffer and optionally the current window config
+ to be restored.
+
+ (slime-compile-file): Save current window configuration before
+ popping up the REPL for compilation output, pass it down.
+ (slime-easy-menu): Add entry for SLIME-UNTRACE-ALL.
+
+2007-04-16 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (fuzzy-find-matching-packages): Fix a small typo that
+ prevented interpreting NIL as the argument TIME-LIMIT-IN-MEC to
+ mean an infinite time limit. This bug propagated up to explicit
+ calls to FUZZY-COMPLETIONS, like
+ (swank:fuzzy-completions "mvb" "COMMON-LISP") => (NIL, T)
+
+ (format-fuzzy-completions): Renamed to FORMAT-FUZZY-COMPLETION-SET
+
+ (format-fuzzy-completion-set): Accomodated to recent changes of
+ the return value of FUZZY-COMPLETIONS; changed the docstring to
+ make it explicit that this function is supposed to take the return
+ value of FUZZY-COMPLETION-SET.
+
+ * slime.el (slime-compilation-finished): Don't use
+ MULTIPLE-VALUE-BIND for list destructuring, only because multiple
+ values happen to be implemented via lists in elisp!
+ (slime-fuzzy-completions-mode): Added an detailed explanation to
+ the docstring of how Fuzzy Completion works and how it'ss supposed
+ to be worked with.
+ (slime-fuzzy-explanation): Shortened to reference to
+ SLIME-FUZZY-COMPLETIONS-MODE for help on fuzzy completion.
+ (slime-fuzzy-choices-buffer): Set BUFFER-QUIT-FUNCTION to
+ SLIME-FUZZY-ABORT to make it correctly exit fuzzy completion when
+ pressing `Esc Esc Esc' (`M-Esc Esc').
+
+2007-04-12 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank-sbcl.lisp (emacs-buffer-source-location): Add &allow-other-keys
+ to the descructuring of the source location plist in order to accept
+ :emacs-directory.
+
+2007-04-09 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (inspector-content-for-emacs): Look for refresh
+ keyword argument in :action links.
+ (inspect-whole-thing-action, inspect-show-more-action): Update for
+ new :action argument handling.
+ (inspect-for-emacs stream, inspect-for-emacs stream-error): Pass
+ :refresh nil on :action links.
+ (action-part-for-emacs): Set both lambda and refresh in the
+ *inspectee-actions* array.
+ (inspector-call-nth-action): *inspectee-actions* now holds both
+ the function and the boolean specifying whether to refresh or not.
+
+ * swank-backend.lisp (inspect-for-emacs): Docstring update.
+
+ * slime.el (slime-inspector-operate-on-point): Allow the action
+ calls to return nil.
+
+2007-04-08 Marco Baringer <mb at bese.it>
+
+ * .cvsignore: Added *.lx64fsl (openmcl on linux fasls).
+
+2007-04-08 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (inspect-for-emacs): Added 'jump to source' action
+ for symbols in the new package-symbol browser.
+
+2007-04-08 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Implemented a new special inspector page for
+ displaying internal (external, &c) symbols that display
+ classification flags additionally to each symbol, similiar to the
+ content of a *Fuzzy Completion* buffer. Furthermore, added the
+ possibility to display all symbols that are /present/ in a
+ package. Combined with cleanup of the code parts in question.
+
+ (symbol-status): New function. Returns the status of a symbol in a
+ given package (:internal, :external &c.)
+
+ (symbol-external-p): Adapted to use new function SYMBOL-STATUS.
+
+ (symbol-classification->string): New function. Converts a list of
+ classification flags into a concise string representation.
+
+ (%package-symbols-container): New struct. We need a unique type to
+ dispatch in INSPECT-FOR-EMACS for the new inspector page, use this
+ as a wrapper structure.
+
+ (inspect-for-emacs package): Reorganized to not cause too much eye
+ cancer; now with a saner maximum column width. Changed to make use
+ of new SYMBOL-STATUS, for code reuse. Also changed to make use of
+ new %PACKAGE-SYMBOLS-CONTAINER to let a new page pop up in Emacs
+ if the user wants to access the list of symbols of the package.
+ Added such a possibility to access all `present' symbols.
+
+ (inspect-for-emacs %package-symbols-container): New method.
+ Displays all symbols wrapped up in the container structure
+ combined with their classification flags as determined by
+ CLASSIFY-SYMBOL.
+
+2007-04-08 Luís Oliveira <loliveira at common-lisp.net>
+
+ * swank-backend.lisp (compute-sane-restarts): New interface.
+ * swank-clisp.lisp: Fix tabs and trailing whitespace.
+ (compute-sane-restarts): Implement new interface.
+
+2007-04-08 Takehiko Abe <keke at gol.com>
+
+ * swank-openmcl.lisp (xref-locations):
+
+2007-04-08 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (fuzzy-completion-set): Use two check-type forms
+ instead of a place like (values limit time-limit-in-msec). While
+ sbcl seems to accept this form openmcl doesn't and it's not clear
+ from the spec that this is allowed.
+
+2007-04-07 Harald Hanche-Olsen <hanche at math.ntnu.no>
+
+ * slime.el (sldb-mode-map): Added key definition for follow-link.
+
+2007-04-06 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Making fuzzy completion regard the time limit
+ correctly. Also make it properly use microseconds as time
+ granularity and inform the Emacs side if the time limit has
+ exhausted. Additionally, over all minor and cosmetic changes:
+
+ (fuzzy-completions, fuzzy-completion-set): Returns now
+ additionally a flag indicating whether the time limit has
+ exhausted under the hood. Accomodated docstring accordingly.
+
+ (fuzzy-create-completion-set): Changed to correctly catch and
+ propagate the remaining time limit to the actual match functions,
+ and return once time limit has exhausted. Some aesthetical code
+ reorganization.
+
+ (get-real-time-in-msecs): New function.
+
+ (fuzzy-find-matching-symbols, fuzzy-find-matching-packages):
+ Correctly regard the time limit. Use new function
+ GET-REAL-TIME-IN-MSECS for that purpose. Return the remaining
+ time limit as second value.
+
+ * slime.el (slime-fuzzy-complete-symbol): Accomodated to deal with
+ the additionally returned flag of SWANK:FUZZY-COMPLETIONS. Pass
+ the flag by.
+ (slime-fuzzy-choices-buffer): Pass interruption flag by.
+ (slime-fuzzy-fill-completions-buffer): If time limit has exhausted
+ during completion retrieval, show an informational indication as
+ last entry in *Fuzzy Completion*.
+ (slime-fuzzy-last): New variable. To hold the last real completion
+ choice previous to the (possible) Time Limit Exhausted information.
+ (slime-fuzzy-next): Accomodated to not go beneath SLIME-FUZZY-LAST.
+
+2007-04-06 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp (tokenize-symbol, tokenize-symbol-thoroughly):
+ Previously these functions said a string representing a symbol is
+ internal exactly if it contained "::" as substring. Now they say
+ additionally so for symbols without any package identifier, as
+ they are internal to am implicit current package. (Otherwise
+ will break fuzzy completion.)
+
+ (tokenize-symbol): Added docstring.
+
+ * swank.lisp (format-completion-result): Fixed formation
+ for the case that PACKAGE-NAME is NIL but INTERNAL-P is T.
+
+2007-04-06 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Making fuzzy completion semantically right from a
+ user perspective. As an example on SBCL, "sb:with- C-c M-i" will
+ display all exported "with"-style macros in all sb-* packages from
+ now on. :)
+
+ (parse-completion-arguments): Replacing with a semantically-sound
+ implementation, as the previous one was a bit confused. Clarifying
+ docstring. Adding commentary table of various constellations of
+ returned values for thorough explanation.
+
+ (carefully-find-package): Removed. Obsolete by above change.
+
+ (defstruct fuzzy-matching): Introduced to make internally-used
+ datastructure explicit. Distinguishing ``completion chunks''
+ between those pertaining to the symbol itself and those to the
+ package identifier.
+
+ (convert-fuzzy-completion-result): Renamed to
+ FUZZY-CONVERT-MATCHING-FOR-EMACS.
+
+ (fuzzy-convert-matching-for-emacs): Accomodating for the new
+ datastructure. Only the chunks pertaining to the symbol itself are
+ fixed up positionally, the package-chunks are untouched.
+ Necessary for letting package identifiers be highlighted within
+ *Fuzzy Completions* in cases like "sb:with- C-c M-i."
+
+ (fuzzy-completion-set): Taking out most code to become new
+ function FUZZY-CREATE-COMPLETION-SET.
+
+ (fuzzy-create-completion-set): Doing all the hard work. Crux of
+ this changeset. so to speak. Largly rewritten to accomodate all
+ different cases of PARSE-COMPLETION-ARGUMENT.
+
+ (fuzzy-find-matching-symbols, fuzzy-find-matching-packages):
+ Accomodating to new datatstructure FUZZY-MATCHING. Adapting
+ docstring accordingly.
+
+ * swank-backend.lisp: Export WITH-STRUCT.
+
+ * swank.lisp (eval-for-emacs, fuzzy-completions):
+ Various trivia like fixing spelling and indentation.
+
+2007-04-06 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-fuzzy-highlight-current-completion): Fix
+ off-by-one error that causes the currently selected
+ completion in the *Fuzzy Completion* buffer be highlighted
+ one char too far.
+
+2007-04-06 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank.lisp: Cleanup of parts of the fuzzy completion code.
+ Additionally a couple of enhancements. As follows:
+
+ (fuzzy-completions, fuzzy-completion-selected): Minor
+ stylistic and clarifying modifications of the docstrings.
+
+ (fuzzy-find-matching-symbols): Huge code reorganization.
+ Organizing relevant code into local function TIME-EXHAUSTED-P,
+ renaming local function SYMBOL-MATCH to PERFORM-FUZZY-MATCH,
+ making previously required argument EXTERNAL to new &key
+ argument :EXTERNAL-ONLY, clarifying docstring.
+
+ (fuzzy-find-matching-packages): Making its return value
+ conformant to that of FUZZY-FIND-MATCHING-SYMBOLS, i.e.
+ instead of returning, among others, a package's name as
+ string, it now returns a symbol representing the package.
+ Accomodates the docstring accordingly.
+
+ (fuzzy-completion-set): Minor typographical fix in docstring.
+ Changing local function CONVERT to use MAP-INTO instead of
+ doing it essentially manually. Accomodating to changes of
+ FUZZY-FIND-MATCHING-SYMBOLS, resp. -PACKAGES.
+
+ (fuzzy-completion-set): Additional new feature:
+ The returned completions are sorted alphabetically by the
+ matched completion string before sorted by its score.
+ Affects especially the list of all possible completions when
+ the user hits fuzzy-completion on an empty string within Emacs;
+ also makes the potential limitness of the listed completions
+ clearer to the end user of SLIME.
+
+ (classify-symbol): New function. Returns a list with keywords
+ that classifies a given symbol. (E.g. :BOUNDP, :MACRO &c)
+ Supersedes parts of CONVERT-FUZZY-COMPLETION-RESULT,
+ implementing them in a more straightforward and proper way;
+ removes prior KLUDGE in that part of the original function.
+
+ (convert-fuzzy-completion-result): The above changes made
+ it possible to simplify this function drastically. Now uses
+ the newly introduced function CLASSIFY-SYMBOL.
+
+ * slime.el: Minor stylistic changes. Additionally:
+ (slime-fuzzy-insert-completion-choice):
+ (slime-fuzzy-fill-completions-buffer) : Adding use of the
+ :PACKAGE classification flag returned by SWANK:FUZZY-COMPLETIONS.
+ This flag is called "p".
+
+2007-04-06 Neil Van Dyke <neil at neilvandyke.org>
+
+ * slime.el (sldb-insert-frame): Added mouse-face to frame label
+ and expression in Backtrace.
+ (sldb-insert-frames): Added mouse-face to "--more--" label in
+ Backtrace.
+
+2007-04-06 Michael Weber <michaelw+slime at foldr.org>
+
+ * slime.el (slime-call-defun): insert the closing parenthesis for
+ the form.
+
+2007-04-06 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp (package swank-mop): Added
+ slot-makunbound-using-class.
+
+2007-03-29 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank-sbcl.lisp (swank-compile-string): save the original
+ directory into the source plist as :emacs-directory.
+ (make-definition-source-location): use the :emacs-directory from
+ the source plist and guess-readtable-for-filename to determine the
+ correct readtable for string-compiled definitions.
+
+2007-03-29 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank.lisp (*macroexpand-printer-bindings*): add *print-lines*
+ to defaults (NIL).
+ (find-definitions-for-emacs): use unless instead of cond.
+
+2007-03-25 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * slime.el (with-selected-window): define for compatibility with
+ Emacs 21.
+
+2007-03-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (menu-choices-for-presentation): Offer a
+ "disassemble" menu item for functions.
+
+2007-03-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-read-port-and-connect): Fix race condition:
+ retry one more time if the port file is empty. Pop up the debugger
+ on other errors.
+ (slime-attempt-connection): Moved to toplevel.
+ (slime-timer-call): New. Used by slime-attempt-connection.
+ (slime-cancel-connect-retry-timer): New.
+ (slime-abort-connection): Use it.
+ (slime-repl-insert-prompt): Use insert-before-markers. This fixes
+ some redisplay problems, but I don't know why. Also: remove the
+ timer for async output.
+ (slime-repl-move-output-mark-before-prompt): Removed.
+ (slime-repl-save-merged-history): Use with-temp-message.
+ (slime-goto-location-buffer): Support Zip files.
+ (sldb-quit): Don't print "Evaluation aborted".
+
+2007-03-22 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-scratch-buffer): Respect the syntax text
+ properties of presentations.
+
+2007-03-21 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (lookup-presented-object): The presentation id of
+ frame locals now includes the thread id; ignore it for now.
+
+ * slime.el (slime-copy-presentation-at-mouse-to-point): Manually
+ invoke the after-change function, so that the presentation overlay
+ is created even if we paste to non-REPL buffers.
+ (slime-menu-choices-for-presentation): Evaluate
+ menu-choices-for-presentation-id in the right buffer, thus in the
+ right Lisp thread. Reported by Attila Lendvai.
+ (slime-menu-choices-for-presentation): Show the id of the presentation.
+ (sldb-insert-locals): Include the thread id in the presentation id.
+
+2007-03-21 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-eval-string, slime-repl-insert-result):
+ Support the presentation-less old protocol.
+ (slime-goto-location-position): Use column number if available.
+
+2007-03-20 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (completion-output-symbol-converter): Fix completion
+ for mixed-case symbols that need escaping in readtable-case
+ :upcase or :downcase.
+
+ * slime.el (slime-copy-presentation-at-mouse-to-point)
+ (slime-copy-presentation-at-mouse-to-kill-ring): New commands.
+ (slime-menu-choices-for-presentation): Change interface. New
+ menu options, Copy to kill-ring, Copy to point.
+ (slime-presentation-menu): Change call to
+ slime-menu-choices-for-presentation.
+
+2007-03-20 Takehiko Abe <keke at gol.com>
+
+ * swank-openmcl.lisp (hash-table-weakness): fix typo
+
+2007-03-14 Christophe Rhodes <csr21 at cantab.net>
+
+ * slime.el (slime-search-suppressed-forms): handle multiple
+ conditionals on the same line.
+
+2007-02-26 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank.lisp (inspect-for-emacs): Add support for inspecting
+ non-decodable float entities like NaNs and infinities.
+
+2007-02-25 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-backend.lisp (inspect-for-emacs): Remove reference to
+ inexistent argument from docstring.
+
+2007-02-25 Harald Hanche-Olsen <hanche at math.ntnu.no>
+
+ * slime.el (slime-init-keymaps): Use vectors when defining keys,
+ because e.g. (define-key (string ?\C-c) ...) doesn't work in the
+ emacs-unicode-2 branch. Some strings are still there.
+
+2007-02-25 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-delete-swank-port-file): Don't use
+ display-warning; that's not available everywhere.
+ (slime-repl-update-banner): Insert the date only if the buffer is
+ empty.
+ (slime-list-compiler-notes): Fetch the notes only if called
+ interactively.
+ (slime-set-query-on-exit-flag): New function, to avoid compiler
+ warnings about obsolete function process-kill-without-query.
+ (slime-defun-if-undefined): Perform the test at runtime not at
+ compile time. Reported by Lennart Staflin.
+
+ * swank.lisp (guess-package): Renamed from
+ guess-package-from-string.
+ (set-package): Use it.
+
+2007-02-22 Juho Snellman <jsnell at iki.fi>
+
+ * slime.el (slime-start-lisp): Don't cd if no directory was specified.
+ (slime-maybe-start-lisp): Pass directory argument to slime-start-lisp
+ also in other cond branch.
+ (slime-restart-sentinel): Pass a NIL directory to slime-start-lisp.
+
+2007-02-21 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-start): Added :directory argument and pass it to
+ slime-maybe-start-lisp.
+ (slime-maybe-start-lisp): Added directory argument and pass it to
+ slime-start-lisp (but not slime-reinitialize-inferior-lisp-p)
+ (slime-start-lisp): Added directory argument. Used to set buffer's
+ directory before starting the inferior lisp.
+
+2007-02-17 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-find-tag-if-tags-table-visited): New function.
+ (slime-edit-definition-fallback-function): Offer it as a value
+ for customization.
+
+2007-02-05 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (sldb-insert-locals): Repair presentation markup of
+ frame locals.
+
+2007-02-04 Antonio Menezes Leitao <aml at gia.ist.utl.pt>
+
+ * swank-lispworks.lisp (dspec-file-position): Bind
+ *compile-file-pathname*, *compile-file-truename*, *load-pathname*
+ and *load-truename* in dspec-file-position.
+
+2007-02-04 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-write-string): When writing a :repl-result,
+ update the slime-output-end marker for the purpose of asynchronous
+ output (when *use-dedicated-output-stream* is true).
+ Reported by Madhu <enometh at meer.net>.
+
+2007-02-03 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-delete-swank-port-file): Fix typo in
+ warning message.
+
+2007-02-02 Marco Baringer <mb at bese.it>
+
+ Warn, as opposed to bailing out with an error, when deleting the
+ port file fails. Patch by: Samium Gromoff
+ <_deepfire at feelingofgreen.ru>
+
+ * slime.el (slime-delete-swank-port-file): New function.
+ (slime-inferior-connect): Use slime-delete-swank-port-file.
+ (slime-read-port-and-connect): Use slime-delete-swank-port-file.
+
+2007-01-31 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-repl-update-banner): Restore animation.
+ (slime-startup-animation): restore.
+
+2007-01-30 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-complete-symbol-function): Restore old default.
+ (set-keymap-parents): Deleted.
+ (slime-startup-animation): Deleted.
+ (slime-read-from-minibuffer): Don't use defun*.
+ (slime-repl-terminate-history-search): New.
+ (slime-repl-next-matching-input): Use it.
+
+ * slime-autoloads.el: New file.
+
+2007-01-29 Sean O'Rourke <sorourke at cs.ucsd.edu>
+
+ * slime.el (slime-start): Continue even if the user, after
+ prompting, didn't recompile the stale .elc file.
+ (slime-urge-bytecode-recompile) [xemacs]: Abort immediately if the
+ user doesn't want to continue.
+ (slime-recompile-bytecode): Don't use byte-compile-warning-types;
+ it may not exist in XEmacs.
+
+2007-01-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (sldb-recenter-region): Use count-screen-lines instead
+ of count-lines.
+
+ * swank.lisp (unparse-name): New function.
+ (list-all-package-names): Use it. This fixes a bug related to
+ readtable-case and makes package name completions look prettier.
+ Suggested by Harald Hanche-Olsen <hanche at math.ntnu.no>.
+
+2007-01-24 Bill Clementson <billclem at gmail.com>
+
+ * slime.el (slime-call-defun): Put the docstring before
+ the (interactive) form so that "C-h f slime-call-defun" will
+ return it.
+
+ * slime.el (slime-scratch-mode-map): Changed parent keymap to
+ lisp-mode-map to prevent unnecessary duplication of slime-mode-map
+ bindings and so that lisp-mode-map key bindings are present in the
+ slime scratch buffer. Change identified by Ariel Badichi.
+
+2007-01-20 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime): Use COMMAND and CODING-SYSTEM parameters
+ Previously they were ignored.
+
+2007-01-17 Christian Lynbech <christian.lynbech at ericsson.com>
+
+ * slime.el (slime-init-command): Use expanded files when writing
+ the LOAD form for swank.
+
+2007-01-14 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Cleanups for the repl history code.
+ (slime-repl-mode-map): Don't shadow M-C-d.
+ (slime-repl-history-replace): Simplified.
+ (slime-repl-history-search-in-progress-p): New.
+ (slime-repl-position-in-history): If there's no match return
+ out-of-bound positions instead of nil.
+ (slime-repl-add-to-input-history): Never modify the argument.
+ (slime-repl-previous-input): Renamed from
+ slime-repl-previous-input-starting-with-current-input.
+ (slime-repl-next-input): Renamed from
+ slime-repl-next-input-starting-with-current-input
+ (slime-repl-forward-input): Renamed from slime-repl-next-input.
+ (slime-repl-backward-input): Renamed from
+ slime-repl-previous-input.
+ (slime-repl-history-pattern): Renamed from
+ slime-repl-matching-input-regexp.
+ (slime-repl-delete-from-input-history): Simplified.
+
+ (slime-repl-history-map)
+ (slime-repl-history-navigation-neutral-commands)
+ (slime-repl-jump-to-history-item)
+ (slime-repl-previous-or-next-input)
+ (slime-repl-starting-with-current-input-regexp)
+ (slime-repl-continue-search-with-last-pattern)
+ (slime-repl-previous-or-next-matching-input): Deleted.
+
+ (sldb-list-locals, sldb-list-catch-tags): Deleted. Aren't of much
+ use anymore.
+
+2007-01-12 Helmut Eller <heller at common-lisp.net>
+
+ * swank-clisp.lisp: Better classification on frames on the stack.
+ Make variables in eval frames accessible to the debugger.
+ (frame-type, *frame-prefixes*, frame-to-string, is-prefix-p)
+ (frame-string-type, boring-frame-p): New.
+ (%frame-count-vars, %frame-var-name, %frame-var-value)
+ (frame-venv, next-venv, venv-ref, %parse-stack-values): Replaces
+ old frame-do-venv.
+ (extract-frame-line, extract-function-name, split-frame-string)
+ (string-match): New code to print frames.
+ (frame-locals, frame-var-value): Use the new stuff.
+
+ (inspect-for-emacs): Fix various bugs.
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Don't wrap
+ everything in a compilation unit. If we abort on load errors and
+ it is confusing to see compiler warnings after the abort message.
+ (handle-loadtime-error): CLISP's format implements ~< differently
+ as everybody else, so use a explicit pprint-logical-block instead.
+
+ * swank.lisp (list-all-systems-in-central-registry): Don't
+ reference asdf directly, that leads to read errors in some
+ systems.
+
+2007-01-12 Juho Snellman <jsnell at iki.fi>
+
+ * slime.el (slime-read-expression-map): Switch the slime-mode-map
+ and minibuffer-local-map back the way they were. The previous change
+ was made due to a misunderstanding, caused by a keybinding for
+ [(return)] apparently being more specific than one for (kbd "RET"),
+ even when the former is in a parent keymap and the latter in the
+ child.
+
+2007-01-12 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (handle-request): Use 'abort as restart name, but
+ bind *sldb-quit-restart* to the restart returned by find-restart.
+ Also use a slighly friendlier message, because newbies seem to
+ invoke the ABORT restart instead of pressing q in the debugger.
+
+2007-01-12 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-find-asd): Remove file extension.
+
+ (slime-read-system-name): Use SWANK:LIST-ASDF-SYSTEMS.
+
+ * swank.lisp (list-all-systems-in-central-registry): Use only
+ pathname name.
+
+ (list-all-systems-known-to-asdf): New function.
+
+ (list-asdf-systems): New function.
+
+2007-01-12 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-keys): Remove binding of M-*, restore binding of
+ M-,.
+
+2007-01-11 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-repl-test-system, slime-repl-test/force-system):
+ New REPL shortcuts. Patch by Kevin Rosenberg
+ <kevin at rosenberg.net>.
+
+2007-01-11 Juho Snellman <jsnell at iki.fi>
+
+ * slime.el (slime-read-expression-map): restore tab completion in
+ the minibuffer. Switch the slime-mode-map and minibuffer-local-map
+ around, so that the minibuffer binding for return takes precedence
+ over the slime-mode one.
+
+2007-01-11 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (inspect-for-emacs integer): Don't die if the integer
+ can't be expressed as a float. Patch by Ariel Badichi
+ <abadichi at bezeqint.net>.
+
+ * slime.el (slime-keys): Removed binding of M-,
+
+2007-01-11 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Some cleanups for the debugger code: add some outline
+ sections and docstrings.
+
+ (sldb-setup): Always display the beginning of the condition
+ text. Previously, we always showed the beginning of the backtrace.
+
+ (sldb-prune-initial-frames): Do what the docstring says. Reverted
+ to Luke's version.
+
+ (sldb-dispatch-extras): Fix typo.
+
+ (sldb-insert-restarts, sldb-insert-frames)
+ (sldb-insert-frame, sldb-fetch-more-frames)
+ (sldb-toggle-details, sldb-show-frame-details)
+ (sldb-insert-locals): Simplified.
+ (sldb-frame-details): New.
+
+ (slime-save-coordinates, slime-coordinates)
+ (slime-restore-coordinate, slime-count-lines): New macro and its
+ helpers.
+ (sldb-recenter-region): Renamed from slime-maybe-recenter-region.
+
+ (sldb-enable-styled-backtrace, sldb-show-catch-tags)
+ (sldb-highlight): Deleted. Seem to be obsolete.
+ (sldb-add-face): Removed, because it is now the same as
+ slime-add-face.
+
+ (sldb-help-summary): Deleted. The docstring for sldb-mode is
+ already pretty terse.
+ (define-sldb-face): Renamed from def-sldb-face.
+
+ * swank-sbcl.lisp, swank-cmucl.lisp (condition-extras): Fix typo
+
+2007-01-10 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*sldb-printer-bindings*): Add *print-right-margin*.
+ (debug-in-emacs): Bind *sldb-printer-bindings* here ...
+ (backtrace, debugger-info-for-emacs, frame-locals-for-emacs):
+ ... and remove redundant bindings here.
+
+2007-01-10 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el: FIX: set-keymap-parents for GNU Emacs was bogus, fixed
+ by Ariel Badichi.
+
+2007-01-09 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-merge-histories): Use (setf (gethash ...)
+ instead of puthash, for Emacs 20.
+
+2007-01-09 Juho Snellman <jsnell at iki.fi>
+
+ SBCL 1.0.1.15 supports restart-frame natively, and uses a different
+ debug catch tag interface than earlier versions.
+
+ * swank-sbcl (sbcl-with-restart-frame): New function, detects SBCL
+ 1.0.1.15 or later.
+ (return-from-frame): Another version for 1.0.1.15, using
+ sb-debug:unwind-to-frame-and-call
+ (restart-frame): Another version for 1.0.1.15, using
+ sb-debug:unwind-to-frame-and-call
+
+2007-01-07 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (open-streams): Don't pass nil to make-fn-streams;
+ use a dummy function as workaround. Both arguments must be
+ functions and CMUCL checks the types.
+
+2007-01-06 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el: Added set-keymap-parents when not available (GNU
+ Emacs). Result: slime bindings while reading expressions from the
+ minibuffer.
+
+ * slime.el, swank.lisp: FIX: slime-insert-possibly-as-rectange and
+ sldb stuff on newer emacsen
+
+2007-01-04 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el: Added slime-insert-possibly-as-rectangle and use it
+ when inserting things here and there. The effect of this is that
+ multi-line strings coming from swank (e.g. stuff in sldb) are
+ inserted with insert-rectangle, so they are properly indented.
+
+ * swank.lisp: FIX: sort is destructive, call copy-seq at a few
+ places. FIX: bind *sldb-printer-bindings* also in
+ frame-locals-for-emacs.
+
+2007-01-03 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * swank.lisp: FIX: drop extra "Slots: " from standard-object's
+ inspector presentation
+
+ * swank.lisp: FIX: keyword symbols keep their : when travelling
+ from swank to slime
+
+ * slime.el: FIX: older Emacsen have no line-number-at-pos.
+
+ * slime.el: Convert some minibuffer reading defun's to defun* and
+ use keywords. Support extra arguments.
+
+ * slime.el: Use set-parent-keymaps when available (xemacs only for
+ now) when setting up slime-read-expression-map. The effect of this
+ is that the minibuffer will have all the slime-mode-map keys where
+ minibuffer-local-map is not overriding.
+
+ * slime.el, swank.lisp: Handle better the case when swank can not
+ read anything from the string sent to be inspected. Only bring up
+ the debugger when the inspect command is prefixed.
+
+2006-12-31 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Restore the nested-presentations feature.
+
+ * present.lisp (slime-stream-p): Allow sending presentations to
+ the repl-results stream.
+ (make-presentations-result): Removed.
+ (send-repl-results-to-emacs): New.
+
+ * swank.lisp (connection): New slot repl-results (a stream).
+ (make-output-function-for-target): New.
+ (open-streams): Use it here to also create a stream for REPL results.
+ (initialize-streams-for-connection): Store the stream.
+
+2006-12-29 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-find-asd, slime-read-system-name): Only offer
+ initial input if system is really in central registry.
+
+2006-12-29 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Simplify the REPL-results protocol. The results are now printed
+ using special :WRITE-STRING events from the Lisp side.
+
+ * slime.el (slime-repl-insert-prompt): Don't insert a result, only
+ the prompt.
+ (slime-repl-insert-result): Removed.
+ (slime-repl-eval-string, slime-repl-show-abort)
+ (slime-repl-set-package, slime-output-buffer)
+ (slime-repl-update-banner): Change all callers.
+ (slime-dispatch-event): Event :WRITE-STRING gets an
+ optional argument TARGET, which controls where the string is
+ inserted.
+ (slime-write-string): Handle targets NIL (regular process output)
+ and :REPL-RESULT.
+
+ * swank.lisp (make-presentations-result): Removed.
+ (send-repl-results-to-emacs): New function, sends :WRITE-STRING events.
+ (listener-eval): Use it here instead of make-presentations-result.
+
+2006-12-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Performance improvement for slime-autodoc-mode, in particular when
+ there are REPL results that are long lists.
+
+ * slime.el (slime-repl-mode-beginning-of-defun)
+ (slime-repl-mode-end-of-defun): New.
+ (slime-repl-mode): Use them as beginning-of-defun-function and
+ end-of-defun-function.
+ (slime-enclosing-operator-names): Bind
+ parse-sexp-lookup-properties to nil, don't parse more than 20000
+ characters before point, don't determine exact argument positions
+ larger than 64. Byte-compile this function.
+
+2006-12-24 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el, swank.lisp: Added customizable dwim lookup hook
+ support for inspect
+
+ * doc/slime.texi: Small doc fixes by Alfredo Beaumont
+
+ * swank.lisp: Change the order to [set value] [make unbound]. Sort
+ slot names in the inspector
+
+2006-12-23 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-clisp.lisp (make-weak-key-hash-table)
+ (make-weak-value-hash-table): Implement for CLISP, so that the
+ REPL results history does not cause "memory leaks".
+
+ * slime.el (slime-inspect): Add a dwim-mode keyword argument, move
+ all input handling into the interactive spec. Restore the
+ behavior of slime-inspect when point is within a presentation (no
+ prompting, no DWIM).
+ (slime-inspect-presentation-at-mouse): Don't do DWIM here, so the
+ presentation-retrieval expression does not end up on the inspector
+ stack.
+ (slime-inspector-position): New.
+ (slime-inspector-operate-on-point, slime-inspector-reinspect): Use
+ it here to make it work on GNU Emacs too.
+ (slime-open-inspector): Fix row-col addressing at end of buffer.
+
+2006-12-20 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el: FIX: inspecting presentations from the right click
+ menu broke in the inspect refactor
+
+ * slime.el: FIX: slime-fuzzy-target-buffer-completions-mode's
+ keymap must always precede other keymaps
+
+ * slime.el, swank.lisp: Extend :write-string with and &optional
+ presentation id and use this in present-in-emacs
+
+ * swank.lisp: Added present-in-emacs that prints a presentation of
+ the given object in the repl
+
+ * swank.lisp: Return the inspected object when inspecting from the
+ lisp side.
+
+ * swank.lisp: Turn off right margin for restart printing, too
+
+2006-12-19 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * HACKING: Added useful init.el piece into HACKING about
+ update-change-log
+
+ * swank.lisp: In all-slots-for-inspector pad slot names to be
+ equal length, so the result is more readable
+
+ * slime.el: Fix slime-insert-presentation to handle multi-line
+ presentations better (use insert-rectangle)
+
+ * swank.lisp: Properly bind *sldb-printer-bindings* and turn off
+ right margin while printing stuff in sldb
+
+ * slime.el: Smarten up the sldb heuristic that drops swank frames
+
+ * swank-allegro.lisp, swank-backend.lisp, swank-openmcl.lisp,
+ swank-sbcl.lisp, swank.lisp: Added hash-table-weakness and use it
+ in hash-table-inspecting
+
+ * swank.lisp: Hashtable inspecting: added [clear hashtable]
+ and [remove entry] actions
+
+ * slime.el, swank.lisp: FIX dwim inspecting to handle (setf
+ some-fun) functions, too
+
+ * slime.el: FIX: slime-sexp-at-point for foo::|bar::baz|
+
+ * slime.el: FIX: Properly keep track of slime-buffer-package in
+ the inspector
+
+ * swank.lisp: Small: get rid of notes and warnings
+
+ * slime.el, swank.lisp: Added dwim-mode to slime-inspect that
+ tries to be smart unless prefixed
+
+ * slime.el: Make slime-fuzzy-complete-symbol the default in the
+ belife that it's better for new users
+
+ * swank.lisp: Add (expt 1.2 length) higher scores for longer
+ matches in fuzzy completion. A good example: puts "make-instance"
+ before "make-string-input-stream" while completing "make-ins"
+
+ * slime.el: Set slime-fuzzy-completion-in-place enabled by default
+
+ * slime.el: Added (cons row col) addressing to
+ slime-open-inspector, use in slime-inspector-operate-on-point
+
+ * slime.el: FIX: operate the inspector in the debug thread when
+ started from sldb
+
+ * slime.el: Convert some inspector defuns to defun* and use
+ keywords. Other minor cleanups.
+
+2006-12-18 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-region-for-defun-at-point): end-of-defun and
+ beginning-of-defun modify match-data, added a save-match-data to
+ prevent this from affecting callers of
+ slime-region-for-defun-at-point.
+
+2006-12-15 Edi Weitz <edi at agharta.de>
+
+ * swank-lispworks.lisp (make-weak-key-hash-table): Weak hash
+ tables for Lispworks.
+ (make-weak-value-hash-table): Ditto.
+
+2006-12-14 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*sldb-printer-bindings*): *PRINT-LINES* is in
+ effect only if *PRINT-PRETTY* is non-NIL, so it better to enable
+ the pretty printer. Suggested by Madhu <enometh at meer.net>.
+
+ * slime.el (slime-expand-abbreviations-and-complete): Emacs
+ `choose-completion' (choosing a completion from the *Completions*
+ buffer) always replaces text upto (point). So the code which
+ figures out an `unambiguous-completion-length' and places the
+ point there in `slime-expand-abbreviations-and-complete' causes
+ problems: the replacement text gets garbled. Get rid of the bogus
+ `unambiguous-completion-length'. Patch by Madhu <enometh at meer.net>
+
+ * swank-cmucl.lisp (remove-gc-hooks): The variables
+ EXT:*GC-NOTIFY-AFTER* and EXT:*NOTIFY-BEFORE* should hold
+ functions and should be NIL. This affects the function
+ REMOVE-GC-HOOKS in swank-cmucl.lisp which sets them to
+ NIL, (should one happen to use it). Set them back to the original
+ parameters. Patch by Madhu <enometh at meer.net>
+
+ * slime.el (slime-repl-output-mouseover-face): Fix a pair of extra
+ parens. Patch by Madhu <enometh at meer.net>
+
+2006-12-14 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-search-buffer-package): Remove Xemacs special
+ casing. There's already a compatibility defun for
+ match-string-no-properties.
+
+2006-12-13 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * swank.lisp: FIX: fuzzy completion for M-V-B. Fix by Madhu.
+
+2006-12-12 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank.lisp (inspect-for-emacs integer): Pad the hex formatted
+ value to eight digits, "Code-char:" instead of "Corresponding
+ character:", "Integer-length:" instead of "Length:",
+ "Universal-time:" instead of "As time".
+ (inspect-object): Use TYPE-FOR-EMACS instead of TYPE-OF.
+ (inspect-in-emacs): New function, analogous to ED-IN-EMACS.
+
+ * swank-backend.lisp (type-for-emacs): New generic function,
+ defaults to TYPE-OF for non-integers, and returns FIXNUM or BIGNUM
+ for integers.
+
+ * slime.el (destructure-case): Indicate in the error message that
+ it was the Elisp destructure-case that failed to avoid confusion.
+ (slime-check-eval-in-emacs-enabled): More verbose error message.
+
+2006-12-11 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * swank.lisp: Added [set value] command for slot inspecting
+
+ * slime.el: Work on repl history navigation, restore old M-p/M-n
+ behaviour due to #lisp demand
+
+ Also print the current regexp in the minibuffer messages. M-p/M-n
+ takes the repl input up to the point not the entire input as it
+ did before.
+ slime-repl-previous/next-input-starting-with-current-input: new
+ names for the old M-p/M-n commands History navigation commands
+ jump to the end of buffer when point is before the prompt.
+
+ * slime.el: Fix/smarten up temp-buffer-quit
+
+ Now it tries its best to remember the original window config and
+ restore it at slime-temp-buffer-quit unless it was changed
+ meanwhile. IOW, fix "q" after macroexpand in a macroexpand buffer
+ not closing the temp window.
+ Also fix the compiler notes usage of the temp buffer.
+
+ * swank-backend.lisp, swank.lisp:
+ Added inspect-slot-for-emacs to let users customize it.
+
+ Use all-slots-for-inspector everywhere, render link to both the
+ effective and direct slots when both are available. Dropped
+ slot-value-using-class-for-inspector and friends. Added
+ slot-makunbound-using-class to the swank-mop package and added
+ a [make-unbound] action to the standard slot presentation.
+
+ * slime.el: FIX: slime-symbol-name-at-point for symbols like
+ foo::|bar::baz|
+
+ * .cvsignore, swank.lisp: FIX: Drop #\. and add #\, to escaped
+ symbol chars
+
+ * slime.el: Added slime-repl-delete-from-input-history that
+ deletes the current history entry when no input is supplied
+
+ * slime.el: slime-repl-kill-input kills the entire input when
+ point is at the prompt and resets the history navigation state
+
+ * slime.el:
+ Use a hashtable to remove duplicates in slime-repl-merge-histories
+
+2006-12-07 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (init-inspector): Added eval parameter. If NIL we
+ don't eval FORM but limit our selves to cl:read'ing it and
+ inspecting that value.
+
+ * slime.el (slime-inspect): If a prefix argument is provided pass
+ :eval nil to swank:init-inspector.
+
+2006-12-07 Paul Collins <paul at briny.ondioline.org>
+
+ * hyperspec.el (common-lisp-hyperspec): Strip all text properties
+ from the symbol-at-point to avoid problems with read-only text.
+
+2006-12-06 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-search-buffer-package): Don't call
+ match-string-no-properties if it's not defined (as is on some
+ xemacs')
+ (slime-repl-clear-buffer): Added optional prefix argument
+ specifying how many lines to leave.
+
+2006-12-06 Johan Bockgård <bojohan+sf at dd.chalmers.se>
+
+ * swank.lisp (fuzzy-completion-set): Don't mix for clauses and
+ body clauses in loop.
+
+2006-12-05 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (create-swank-server): Removed. Use create-server
+ instead.
+
+ * slime.el (slime-first-change-hook): Don't do anything if buffers
+ file doesn't exist.
+ (slime-start, slime-set-connection-info): Add support for a
+ :init-function which is called after the usual initialization of the
+ connection is completed.
+
+ * swank-source-file-cache.lisp (buffer-first-change): Always
+ return nil and remove the now redundant test with probe-file.
+
+ * swank-backend.lisp (guess-external-format): Return nil if the
+ file can't be opened. Previusly we wrongly read from stdin.
+
+2006-12-05 Juho Snellman <jsnell at iki.fi>
+
+ Real xref support for SBCL (requires SBCL 1.0.0.18).
+
+ * swank-sbcl.lisp (who-calls): New function, fetch xref data from
+ sb-introspect.
+ (who-binds): Ditto.
+ (who-sets): Ditto.
+ (who-references): Ditto.
+ (who-macroexpands): Ditto.
+ (defxref): New macro, create the above functions.
+ (source-location-for-xref-data): New, map from sb-introspect xref
+ format to the Swank xref format.
+ (sanitize-xrefs): Map PCL method names to something more readable.
+ (string-path-snippet): New function, finds a more accurate source
+ snippet for definition source locations which have both an
+ :emacs-string and a full source path available. Otherwise the xref
+ location would point to the toplevel form rather than the exact
+ form for functions compiled with C-c C-c.
+ (source-file-position): New function, somewhat like
+ source-path-file-position but uses the source-file cache, handles
+ missing form-paths more gracefully.
+ (make-definition-source-location): Use the above two functions.
+ (sbcl-with-xref-p): New function, detect whether SBCL has xref support
+ for backwards compability.
+
+2006-11-26 Juho Snellman <jsnell at iki.fi>
+
+ * swank-source-file-cache.lisp (buffer-first-change): Check
+ whether a file exists before trying load it into the source cache.
+
+2006-11-26 Juho Snellman <jsnell at iki.fi>
+
+ Restore the way M-n and M-p used to work in the REPL. (cherry-picked
+ from a patch with other changes, sent by Attila Lendvai).
+
+ * slime.el (slime-repl-previous-input-starting-with-current-input)
+ (slime-repl-next-input-starting-with-current-input): New functions,
+ work like the old slime-repl-previous-input / next-input.
+ (slime-repl-matching-input-regexp): Restore old version.
+ (slime-repl-mode-map): Bind s-r-p-i-s-w-c-i and s-r-n-i-s-w-c-i
+ to M-p and M-n respectively. slime-repl-previous-input and
+ slime-repl-next-input are still accessible with C-up / C-down.
+
+2006-11-25 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-read-break): Use a :emacs-interrupt message
+ instead of a RPC to swank:simple-break. Suggested by Taylor R
+ Campbell.
+
+2006-11-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-search-buffer-package): Prettify the package
+ name if it is written as string or keyword.
+
+2006-11-23 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-in-expression-p): Use `read' and `eq' to test
+ the first element of the list. Previuosly, the pattern (foo)
+ wrongly matched (foobar) because we used (looking-at <symbol>).
+
+ * swank-cmucl.lisp (setf-definitions): Also include defs which
+ were created with (defun (setf NAME) ...). Previously we only
+ found definitions created with defsetf or define-setf-expander.
+
+2006-11-22 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-edit-definition): Don't hide error messages.
+
+2006-11-21 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*coding-system*): "Coding systems" are now strings
+ instead of keywords.
+
+2006-11-19 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-compile-file): Let the Lisp side choose the
+ coding system.
+ (slime-coding): Deleted.
+
+ * swank.lisp (compile-file-for-emacs): Use guess-external-format.
+ (swank:create-server): no more accepts an :external-format 'enc ,
+ use :coding-system "enc" instead.
+
+ * swank-backend.lisp (find-external-format)
+ (guess-external-format): New.
+ (swank-compile-file): The external-format argument is now a
+ backend specific value returned by find-external-format.
+
+ * swank-cmucl.lisp, swank-sbcl.lisp, swank-clisp,
+ swank-lispworks.lisp, swank-allegro.lisp, swank-corman.lisp,
+ swank-ecl.lisp, swank-scl.lisp, swank-abcl.lisp, swank-openmcl:
+ Update implementations accordingly.
+
+ * swank-source-file-cache.lisp (read-file): Use guess-external-format.
+
+ * swank.lisp (*swank-wire-protocol-version*): Is now initialized
+ by the loader.
+ (wire-protocol-version): Removed, because it contained a reference
+ to swank-loader::*source-directory*.
+
+ * slime.el (slime-set-connection-info): On protocol version
+ mismatch, ask the user how to proceed.
+ (slime-protocol-version): New variable. Initialize it at compile
+ time to detect stale elc files.
+
+ * swank-loader.lisp (load-swank): Set the protocol version.
+
+2006-11-12 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-make-tramp-file-name): Added (require 'tramp)
+ since tramp-make-tramp-file-name is not an autoloaded function.
+
+2006-11-07 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-fuzzy-completion-time-limit-in-msec): Escaped
+ left parenthesis in doc string.
+
+2006-11-05 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-complete-keywords-contextually): Unused
+ variable, removed.
+
+2006-11-05 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (sldb-sexp-highlight-mode): Remove bloat.
+
+2006-11-04 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Support nested presentations in REPL results, when present.lisp is
+ loaded.
+
+ * swank.lisp (make-presentations-result): New, factored out from
+ listener-eval.
+ (listener-eval): Use it here.
+
+ * present.lisp (make-presentations-result): Override it here.
+
+2006-11-03 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (all-slots-for-inspector): Added declare ignore for
+ unused argument inspector (openmcl warns about this). Reindented.
+
+2006-11-01 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el (sldb-sexp-highlight-mode): New custom.
+ (slime-handle-repl-shortcut): Trigger slime-lookup-shortcut when
+ the point is anywhere before slime-repl-input-start-mark. IOW,
+ you can press "," anywhere before the prompt.
+ (slime-edit-definition): Handle the case when there are only such
+ entries returned from swank that have errors.
+ (slime-read-from-minibuffer): Allow overriding of the keymap.
+ (slime-repl-previous-matching-input): Similar behaviour like
+ isearch-forward.
+ (slime-repl-next-matching-input): Ditto. In more details: You can
+ freely navigate with slime-repl-previous/next-input with M-p and
+ M-n at any time among the history entries. When M-r is pressed,
+ which invokes slime-repl-previous-matching-input, the the
+ minibuffer is activated to read the regexp to search for and the
+ contents will default to the current repl input. Pressing M-r
+ again will start searching with the last pattern used no matter
+ what the content of the minibuffer is. Subsequent invocations of
+ M-r get the next match, and of course the same applies for M-s,
+ which is slime-repl-previous-matching-input.
+
+ * swank.lisp (fuzzy-completion-set): Fix on clisp.
+ (convert-fuzzy-completion-result): Fix symbol fbound and other
+ annotations.
+ (slot-value-using-class-for-inspector): New.
+ (slot-boundp-using-class-for-inspector): New.
+ (inspect-for-emacs): Use the special slot access methods so that
+ it's possible to customize the inspecting of complex
+ slots (e.g. computed-class at
+ http://common-lisp.net/project/computed-class/).
+ (all-slots-for-inspector): Converted to generic method.
+
+2006-11-01 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (*swank-wire-protocol-version*): Use a defvar to
+ declare the existence of tihs variable to the lisp (Reported by:
+ Jonathon McKitrick <jcm at FreeBSD-uk.eu.org>).
+
+2006-10-30 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (*dont-close*): New variable.
+ (defpackage :swank): Export *dont-close*.
+ (start-server, create-server): Use *dont-close* as the default
+ value of the :dont-close parameter.
+ (connection-info): Send the wire-protocol-version (supplied by the
+ swank-version.el file) to slime when connecting.
+ (wire-protocol-version): New function.
+
+ * slime.el (slime-global-variable-name-regexp): New variable.
+ (slime-global-variable-name-p): Use
+ slime-global-variable-name-regexp.
+ ("swank-version"): Load swank-version.el to get the wire protocol
+ version.
+ (slime-set-connection-info): Check the wire protocol version.
+
+2006-10-30 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-global-variable-name-p): Oops... need to handle
+ very long strings.
+
+2006-10-29 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el (slime-global-variable-name-p): Use defun* instead of
+ defun.
+
+2006-10-29 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-global-variable-name-p): Simplified.
+
+2006-10-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Add completion for character names.
+
+ * slime.el (slime-completions-for-character): New.
+ (slime-contextual-completions): Use it here.
+
+ * swank-backend.lisp (character-completion-set): New interface.
+
+ * swank-allegro.lisp (character-completion-set): Implement it.
+
+ * swank.lisp (completions-for-character): New slimefun.
+ (compound-prefix-match/ci/underscores)
+ (longest-completion/underscores, tokenize-completion/underscores)
+ (untokenize-completion/underscores): New functions.
+
+2006-10-28 Ivan Toshkov <ivan at toshkov.org>
+
+ * hyperspec.el: Missing Hyperspec links for ~| and ~~
+
+2006-10-27 Ivan Toshkov <ivan at toshkov.org>
+
+ * hyperspec.el: Missing Hyperspec links for ~% and ~&
+
+2006-10-27 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank-sbcl.lisp (make-weak-key-hash-table): Restore support
+ for older SBCLs without weak hash-tables.
+ (make-weak-value-hash-table): Ditto.
+
+2006-10-26 Utz-Uwe Haus <haus+slime at mail.math.uni-magdeburg.de>
+
+ * swank-allegro.lisp (sldb-break-at-start): Implement.
+
+2006-10-26 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el (slime-setup-command-hooks): Use make-local-hook.
+ (slime-repl-mode): Ditto.
+ (slime-fuzzy-choices-buffer): Ditto.
+ (sldb-mode): Ditto.
+ (slime-fuzzy-completion-limit): New variable.
+ (slime-fuzzy-completion-time-limit-in-msec): New variable.
+ (slime-fuzzy-next): Fix when at the end of the buffer.
+ (completion-output-symbol-converter): New to handle escaped
+ symbols for those who need to mess around with symbols like
+ layered-function-definers::|CONTEXTL::SLOT-VALUE-USING-LAYER|.
+ When a symbol is escaped then completion is case sensitive.
+ (completion-output-package-converter): New.
+ (mimic-key-bindings): New to easily define bindings by first
+ trying to look up bindings for an operation and only use the
+ provided default bindings if nothing was found in the source
+ keymap. Use it to set up fuzzy bindings. (Hint: if you have keys
+ like previous-line customized, then only load slime after they
+ have been set, and the fuzzy mode will mimic them.)
+ (slime-temp-buffer-quit): Always close the opened window, updated
+ docstring. Also made the fuzzy maps smarter, they now try to look
+ up keys with 'where-is-internal and map the functions on them.
+
+ * swank-sbcl.lisp
+ (make-weak-value-hash-table): New for sbcl.
+ (make-weak-key-hash-table): New for sbcl.
+
+ * swank.lisp (fuzzy-completions and friends): Added :limit and
+ :time-limit-in-msec keyword params. Used vectors instead of lists
+ that nearly doubled its speed (at least on sbcl). Also added some
+ declare optimize and type annotations.
+ (do-symbols*): New, uses a hash-table to visit only non-seen
+ symbols. Replaced various uses of do-symbols where it was
+ appropiate.
+
+2006-10-26 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-global-variable-name-p): Use a custom 'parser'
+ instead of string-match to avoid regexp overflow errors on very
+ long strings.
+
+2006-10-21 Helmut Eller <heller at common-lisp.net>
+
+ * swank-lispworks.lisp (initialize-multiprocessing): Don't init
+ MP if it is already running.
+
+ * test.sh: Run Emacs in Screen.
+
+2006-10-20 Helmut Eller <heller at common-lisp.net>
+
+ * swank-backend.lisp, swank-cmucl.lisp:
+ (startup-idle-and-top-level-loops): Deleted. Merged into
+ initialize-multiprocessing.
+
+2006-10-20 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el (slime-fuzzy-choices-buffer): Added kill-buffer-hook to
+ the completion buffer to slime-fuzzy-abort, so we get out from the
+ completion mode and key maps when the completion buffer is closed.
+
+2006-10-20 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-target-buffer-fuzzy-completions-map): Fix a bug
+ I introduced when applying levente's patch.
+
+2006-10-20 Martin Simmons <martin at lispworks.com>
+
+ * swank-backend.lisp (initialize-multiprocessing): New API to
+ support lisps where initialize-multiprocessing may not return (lispworks).
+
+ * swank.lisp (start-server): initialize-multiprocessing's API has changed.
+
+ * swank-lispworks.lisp (initialize-multiprocessing): Update for new API.
+
+ * swank-cmucl.lisp (initialize-multiprocessing): Update for new API.
+
+ * swank-allegro.lisp (initialize-multiprocessing): Update for new api.
+
+2006-10-20 Levente Mészáros <levente.meszaros at gmail.com>
+
+ Added "in-place" fuzzy completion GUI. See
+ slime-fuzzy-completions-map and
+ slime-target-buffer-fuzzy-completions-map for details.
+
+ * slime.el (slime-fuzzy-completion-in-place): New variable.
+ (slime-target-buffer-fuzzy-completions-mode): New keymap for
+ in-place fuzzy completions.
+ (slime-fuzzy-target-buffer-completions-mode): New minor mode for
+ in-place fuzzy completions.
+ (slime-fuzzy-current-completion-overlay): New overlay for
+ highlighting currently selected completion.
+ (slime-fuzzy-completions-map): Added new fuzzy completon keys
+ (slime-fuzzy-indent-and-complete-symbol): New function.
+ (slime-fuzzy-complete-symbol): Use new in-place fuzzy completion.
+ (slime-fuzzy-choices-buffer): Support in-place completion editing.
+ (slime-fuzzy-fill-completions-buffer): Highlight completions,
+ don't automatically jump to completion buffer.
+ (slime-fuzzy-enable-target-buffer-completions-mode,
+ slime-fuzzy-disable-target-buffer-completions-mode): New modes for
+ moving in/out of in-place fuzzy completion mode
+ (slime-fuzzy-next, slime-fuzzy-prev): Don't assume point is in the
+ completion buffer.
+ (slime-fuzzy-dehighlight-current-completion,
+ slime-fuzzy-highlight-current-completion): Manage completion
+ selection highlighting.
+ (slime-fuzzy-select-or-update-completions): New function.
+ (slime-fuzzy-process-event-in-completions-buffer): New function.
+ (slime-fuzzy-select-and-process-event-in-target-buffer): New function.
+ (slime-fuzzy-done): Changed to deal with in-place completion.
+
+2006-10-19 Helmut Eller <heller at common-lisp.net>
+
+ * swank-backend.lisp (ignored-xref-function-names): Deleted.
+
+ * swank.lisp (guess-package-from-string): Remove special case for
+ "#.". parse-package will handle that just fine.
+ (find-definitions-for-emacs): Don't filter errors out.
+ (sanitize-xrefs): Moved to swank-sbcl. The backend is supposed to
+ return sane values.
+
+ * swank-sbcl.lisp: See above.
+
+ * slime.el (slime-find-buffer-package): Simplify.
+
+2006-10-17 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-accept-process-output): The timeout arg can be
+ nil. Handle that case.
+
+2006-10-17 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime.el (slime-find-buffer-package): Handle #. forms.
+
+ * swank.lisp (guess-package-from-string): Handle #. forms.
+ (inspect-for-emacs standard-class): Handle non-string
+ :documentation slot contents.
+
+ * swank-sbcl.lisp (inspect-for-emacs weak-pointer ...): Added
+ method.
+
+2006-10-16 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (sldb-activate): Get debug-info from the correct
+ thread. Fixes bug reported by Dan Weinreb <dlw at itasoftware.com>.
+ (unwind-to-previous-sldb-level): New test.
+ (slime-init-command): Send a single form.
+ (slime-insert-presentation): Honor slime-repl-enable-presentations.
+ Presentations kill SLDB and the inspector in Emacs 20 (besides
+ being troublesome GC-wise).
+
+ * swank.lisp: Clean up global IO redirection.
+ (setup-stream-indirection): Turn macro into a
+ function and delay initialization after user init files are
+ loaded, so that we do nothing if *globally-redirect-io* is nil.
+ (*after-init-hook*, run-after-init-hook)
+ (init-global-stream-redirection): New.
+
+ (parse-symbol-or-lose): Lose loudly and early (instead of failing
+ silently).
+
+ * swank-loader.lisp: Abort on compile-time or load-time errors.
+ Don't try to load the source-file if COMPILE-FILE's 3rd return
+ value is true (it's true even for warnings).
+ (handle-loadtime-error): New function.
+
+ Run the after-init-hook.
+
+ * swank-cmucl.lisp (inspect-for-emacs): Don't break for
+ simple-strings.
+
+2006-10-11 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-presentation-syntax-table): New.
+ (slime-add-presentation-properties): Install it in a syntax-table
+ text property, so that #<...> is balanced in a presentation.
+ (slime-remove-presentation-properties): Remove the text property.
+ (slime-repl-mode): Respect the syntax text properties of
+ presentations in REPL buffers.
+
+2006-10-09 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (completions-for-keyword): Look up the operator names
+ in the right package. Return nil (rather than signalling an
+ error) when no valid operator name is present.
+
+2006-10-08 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-loader.lisp (lisp-version-string) [allegro]: Distinguish
+ between 32-bit and 64-bit version on the SPARC architecture.
+
+2006-10-03 Marco Baringer <mb at bese.it>
+
+ Change license statement to say that all files without an explicit
+ copyright notice are public domain. This change will allow SLIME
+ to moved out of debian's nonfree tree.
+
+ * README: Update license statement.
+
+2006-10-02 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-highlight-compiler-notes): New variable.
+ (slime-compilation-finished): Only highlight notes when
+ slime-highlight-compiler-notes is non-NIL.
+
+2006-09-28 Marco Baringer <mb at bese.it>
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Don't
+ ignore compile-time errors but drop into a debugger (it's not a
+ slime debugger but it's certainly better than ignoring the error).
+
+2006-09-27 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (*globally-redirect-io*): Change default value to T.
+
+2006-09-25 Juho Snellman <jsnell at iki.fi>
+
+ Fix Slime on SBCL 0.9.17.
+
+ * swank-backend.lisp (ignored-xref-function-names): New interface
+
+ * swank.lisp (sanitize-xrefs): Use ignored-xref-function-names
+ instead of having a #+sbcl special case.
+
+ * swank-sbcl.lisp (ignored-xref-function-names): Implement.
+ Filter out SB-C::STEP-VALUES, not just SB-C::STEP-FORM, as done by
+ the old sanitize-xrefs. Don't implement the interface at all if
+ SBCL is sufficiently new (those symbols don't exist any more, and
+ there's nothing in their place to be ignored).
+
+2006-09-21 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (find-definitions-for-emacs): Don't return locations
+ whose CAR is :error.
+ (xref): Process whatever is returned by the various xref functions
+ with the new sanitize-xrefs functions.
+ (sanitize-xrefs): Clean up the list of xrefs to remove duplicates.
+ Patch by Dan Weinreb <dlw at itasoftware.com>
+
+ * slime.el (slime-goto-first-note-after-compilation): New
+ variable. This controls the behaviour of (next|prev)-note
+ immediatly after a slime-compile-and-load-file.
+ (slime-compilation-just-finished): New variable.
+ (slime-compilation-finished): Update slime-compilation-finished.
+ (slime-next-note, slime-previous-note): Respect
+ slime-compilation-just-finished.
+ (slime-autodoc-use-multiline-p): Specify the type.
+ (slime-repl-grab-old-input): Typo in docstring.
+ (slime-cheat-sheet): Deal with multiple-bindings
+ (slime-cheat-sheet-table): Update as per #lisp's suggestions.
+
+2006-09-20 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-cheat-sheet): New function.
+ (slime-cheat-sheet-table): New variable which specifies what the
+ cheat sheet should list.
+ (slime-read-package-name): Set require to T in the call to
+ completing read, it doesn't make any sense to switch to an
+ inexistent package.
+
+ * doc/slime.texi: Added "Tips and Tricks" chapter (need a better
+ name for this).
+
+ * swank-sbcl.lisp (fallback-source-location): Use abort-request
+ instead of error.
+ (locate-compiler-note): Say, in the error message, what data
+ caused the error.
+
+2006-09-20 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (call-with-debugger-hook): use INVOKE-STEPPER
+ instead of calling the stepper hook manually
+
+2006-09-19 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (call-with-debugger-hook): make the stepper
+ also work with a threaded SBCL, by binding a handler for
+ sb-ext:stepper-condition instead of relying on the one that SBCL
+ establishes on the toplevel
+
+2006-09-19 Juho Snellman <jsnell at iki.fi>
+
+ Extend the stepper protocol to work nicely with the SBCL stepper.
+
+ If sldb is invoked on a condition that's sldb-stepper-condition-p,
+ the sldb functions sldb-step, sldb-next and sldb-out will invoke
+ the matching backend functions for stepping into the stepped form,
+ to the next form, or out of the current function. Otherwise the
+ functions will behave like sldb-step used to (call active-stepping and
+ select the continue restart).
+
+ * swank-backend.lisp (sldb-stepper-condition-p, sldb-step-into,
+ sldb-step-next, sldb-step-out): New interface functions
+
+ * swank-sbcl.lisp (activate-stepper, condition-extras,
+ sldb-stepper-condition-p, sldb-step-into, sldb-step-next,
+ sldb-step-out): Implemented (conditional on CVS SBCL)
+ (call-with-debugger-hook): bind sb-ext:*stepper-hook* to
+ a function that binds *stack-top-hint* and invokes the debugger
+ (conditional on CVS SBCL)
+
+ * swank.lisp (define-stepper-function): new macro for defining
+ stepper-related functions, since they all follow the same form
+ (sldb-step): redefine with define-stepper-function
+ (sldb-next, sldb-out): new functions
+ (*sldb-stepping-p*): typo in docstring
+
+ * slime.el (sldb-next, sldb-out): New commands
+ (sldb-mode-map): bind sldb-next to "x" and sldb-out to "o"
+
+2006-09-18 Dan Weinreb <dlw at itasoftware.com>
+
+ For those cases where SLIME can't complete a user request (like
+ loading an asdf system without asdf or describing an inexistent
+ symbol) instead of signaling an error SWANK should politely inform
+ the user and return normally.
+
+ * swank.lisp (eval-for-emacs): Handle request-abort conditions.
+ (decode-keyword-arg, get-repl-result, parse-symbol-or-lose): Use
+ abort-request instead of error.
+
+ * swank-backend.lisp (request-abort): New condition.
+ (abort-request): Convenience function for signaling request-abort
+ conditions.
+ (operate-on-system): Use abort-request instead of error
+ (:swank-backend): Export the symbols abort-request and
+ request-abort.
+
+ * slime.el (slime-rex): Update docstring.
+ (slime-eval, slime-eval-async): Added new REASON parameter sent
+ along with :abort message.
+
+2006-09-14 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-scl (arglist, function-arglist, spawn): update for the SCL.
+
+2006-09-13 Brandon Bergren <bdragon at mailsnare.net>
+
+ * slime.el (slime-filename-translations): Fix docstring
+
+2006-09-13 Bob Halley <halley at play-bow.us>
+
+ * swank.lisp (format-iso8601-time): Properly handle non integer
+ time zones.
+
+2006-09-13 Taylor R Campbell <campbell at mumble.net>
+
+ * slime.el (slime-init-output-buffer): Initial directory and
+ package stacks should be empty.
+ (slime-repl-push-package): Push the current package, as opposed to
+ the new package, and set the new package to whatever the user
+ specified.
+ (slime-repl-pop-package): Set the current package to the top of
+ the package stack, unless it's empty.
+
+2006-09-13 Daniel Koning <dkoning at seas.smu.edu>
+
+ * slime.el (slime-repl-disconnect): New repl shortcut.
+
+2006-09-13 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-open-inspector): Added a slime-part-number
+ property to the topline so that you can slime-inspector-copy-down
+ the object being inspected. There are some cases where we have an
+ object in the inspector and we'd like to dump it to the repl but
+ we can't get at it through other means (like in back-traces).
+ (slime-insert-xrefs): Specify which file the item is in (when that
+ information is available).
+
+ * swank.lisp (format-arglist-for-echo-area): Instead of using
+ let+first+rest to destructure a form use destructuring-bind.
+ (lookup-presented-object): Added (declare (special
+ *inspectee-parts*)) to silence openmcl's compiler.
+ (inspect-object): Generate, and send to emacs, an ID for the
+ object being inspected.
+
+2006-09-01 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * slime.el (slime-repl-matching-input-regexp): Use the portion
+ between slime-repl-input-mark and point for history search, not
+ the entire input. Patch by Ivan Shvedunov.
+
+ * swank-sbcl.lisp: Declaim SB-C:INSERT-STEP-CONDITIONS 0 for to
+ hide Swank while stepping and avoid endless mutex-acquisition
+ loops.
+
+2006-08-27 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (input-available-p, process-available-input): Use
+ READ-CHAR-NO-HANG instead of LISTEN because LISTEN suddenly
+ returns false in SBCL 0.9.?? even if we are called from a
+ fd-handler and the OPEN-STREAM-P returns true.
+
+2006-08-26 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-return-behaviour): Fix the defcustom type,
+ so Emacs 21.3 does not signal an error when creating a
+ customization buffer containing this variable.
+
+2006-08-25 Kai Kaminski <kai.kaminski at gmx.de>
+
+ * swank.lisp (lookup-presented-object): Fix for OpenMCL 1.0
+ [ppc32], which requires that the :NO-ERROR clause is last in
+ HANDLER-CASE.
+
+2006-08-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-ensure-presentation-overlay): Provide a
+ help-echo for presentations, showing the mouse bindings.
+ (slime-presentation-around-click): New function.
+ (slime-copy-or-inspect-presentation-at-mouse)
+ (slime-inspect-presentation-at-mouse)
+ (slime-copy-presentation-at-mouse)
+ (slime-describe-presentation-at-mouse)
+ (slime-pretty-print-presentation-at-mouse): New commands.
+ (slime-copy-presentation-at-point): Removed (misnomer).
+ (slime-presentation-map): Bind mouse-2 to
+ slime-copy-or-inspect-presentation-at-mouse, so the right thing is
+ done in REPL buffers and in Inspector and Debugger buffers.
+ (slime-menu-choices-for-presentation): Use the new commands here
+ instead of inline lambdas.
+ (sldb-inspect-in-frame): Use slime-read-object here, so if point
+ is in a presentation in the debugger buffer, inspect it
+ immediately just like slime-inspect does.
+ (slime-inspect-presented-object): Removed.
+ (slime-inspect): Don't expect that "swank:init-inspector" is
+ already part of the form. Accept an optional arg "no-reset".
+ (slime-read-object): Don't add "swank:init-inspector" to the read
+ form; slime-inspect now adds it.
+
+2006-08-21 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Make the values of local variables in debugger frames and values
+ of parts in the inspector accessible as presentations. In
+ particular, this allows to copy #<unreadable> values to the REPL
+ for further investigation. It also provides a context menu for
+ the values, offering to inspect, pretty-print, and describe them.
+
+ Note that the presentations are only valid as long as the
+ corresponding Inspector or Debugger buffer is open.
+
+ * swank.lisp (lookup-presented-object): Handle presentation ids
+ (:frame-var frame index), (:inspected-part part-index).
+ (init-inspector): New optional argument, reset.
+
+ * slime.el (slime-inspector-insert-ispec): Mark up all values of
+ inspected parts as presentations.
+ (sldb-insert-locals): Mark up the values of local variables as
+ presentations.
+ (slime-remove-presentation-properties): Fix for read-only buffers.
+ (slime-copy-presentation-at-point): Make it work when the current
+ buffer is not the REPL buffer.
+ (slime-menu-choices-for-presentation): Describe into a separate
+ buffer, not the REPL. New menu item, pretty-print.
+ (slime-presentation-expression): Handle presentation ids that are
+ not numbers.
+ (slime-inspect-presented-object): Don't reset the inspector if
+ already in the inspector buffer.
+
+2006-08-20 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (*nil-surrogate*): New.
+ (save-presented-object, lookup-presented-object): Distinguish
+ between a saved NIL and a garbage-collected object that was
+ replaced by NIL in the weak hash table.
+ (compute-enriched-decoded-arglist with-open-file): Add an IGNORE
+ declaration.
+
+2006-08-19 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-parse-extended-operator-name/apply): New.
+ (slime-extended-operator-name-parser-alist): Add it to the alist.
+
+ * swank.lisp (compute-enriched-decoded-arglist): Add method for
+ handling APPLY.
+
+2006-08-14 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-accept-process-output): Use brute-force to
+ detect whether accept-process-output can be called with a float as
+ timeout arg.
+
+ * swank-openmcl.lisp: Fix some breakage caused by the new
+ defimplementation.
+
+2006-08-11 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (close-connection, swank-error): Include backtraces
+ in our own errors.
+ (simple-serve-requests): Don't try to enter the
+ debugger if the connection is closed.
+
+ * slime.el (disconnect): Test disconnecting.
+
+ * swank-cmucl.lisp (startup-idle-and-top-level-loops): Initialize
+ MP only once.
+
+2006-08-10 Helmut Eller <heller at common-lisp.net>
+
+ * swank-allegro.lisp (fspec-definition-locations): Improve
+ handling of (:internal ... n) like fspecs.
+
+ * slime.el (slime-restart-inferior-lisp-aux): Remove the
+ interactive spec.
+
+ * swank-backend.lisp (definterface): Drop that incredibly
+ unportable CLOS stuff. Use plists and plain functions instead.
+ Update backends accordingly.
+
+2006-08-09 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-find-filename-translators): CL:MACHINE-INSTANCE
+ can return nil. Silently accept that case for now.
+
+ * swank.lisp (test-print-arglist): Print a message instead of
+ signalling an error. This should avoid startup problems, in
+ particular with CormanLisp.
+ (setup-stream-indirection): Disable it for now. We should fix it,
+ if there is a need for this functionality or just remove it.
+
+ * swank-backend.lisp (definterface): Bring the old implementation
+ based on NO-APPLICABLE-METHOD back. It avoids lots of redefintion
+ warnings (but it creates more "noise" in backtraces).
+
+ * swank-*.lisp (inspect-for-emacs): Don't use defimplementation
+ for real generics.
+
+2006-07-28 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-thread-quit): Call swank:quit-thread-browser.
+ Reported by Taylor R Campbell.
+
+2006-07-28 Willem Broekema <metawilm at gmail.com>
+
+ * swank-allegro.lisp: Profiling functions on Allegro (except for
+ profile-package).
+
+2006-07-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Add support for destructuring macro arglists in arglist display,
+ form completion, and keyword completion; in particular for
+ with-open-file.
+
+ * swank.lisp (find-valid-operator-name): New, factored out from
+ arglist-for-echo-area.
+ (arglist-for-echo-area): Use it here.
+ (print-arglist): New, factored out from decoded-arglist-to-string.
+ Handle recursive arglist structures that arise in destructuring
+ macro arglists.
+ (decode-required-arg, encode-required-arg): New, handle
+ destructuring patterns.
+ (decode-keyword-arg, encode-keyword-arg, decode-optional-arg)
+ (encode-optional-arg, decode-arglist, encode-arglist): Use them
+ here to handle destructuring patterns.
+ (print-decoded-arglist-as-template): Change interface, handle
+ destructuring patterns.
+ (decoded-arglist-to-template-string): Use it here.
+ (enrich-decoded-arglist-with-keywords): New, factored out from
+ enrich-decoded-arglist-with-extra-keywords.
+ (enrich-decoded-arglist-with-extra-keywords): Use it here.
+ (compute-enriched-decoded-arglist): New generic function, factored
+ out from arglist-for-insertion, form-completion. Add specialized
+ method for with-open-file.
+ (arglist-for-insertion, form-completion): Use it here.
+ (arglist-ref): New.
+ (completions-for-keyword): Change interface, handle destructuring
+ macro arglists.
+
+ * slime.el (slime-enclosing-operator-names): For nesting levels
+ without operator, record nil.
+ (slime-completions-for-keyword): New argument arg-indices.
+ (slime-contextual-completions): Pass all enclosing operators and
+ arg-indices to slime-completions-for-keyword.
+
+2006-07-16 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-edit-definition): Invoke the
+ slime-edit-definition-fall-back-function also in the case where
+ find-definitions-for-emacs returns an error message.
+ (slime-edit-definition-fallback-function): Fix typo (find-tag
+ rather than find-tags).
+
+2006-07-15 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (preferred-communication-style): Remove use of
+ linux_no_threads_p alien variable (the value has been hardcoded to
+ false for about a year), so that we can also remove it from from SBCL
+ in the future.
+ (*definition-types*): defcondition -> define-condition,
+ to make slime-show-definitions display condition FOO as
+ (DEFINE-CONDITION FOO) instead of (SWANK-BACKEND::DEFCONDITION FOO).
+
+2006-07-15 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-shared-lisp-mode-hook): New function, factored
+ out from slime-lisp-mode-hook.
+ (slime-lisp-mode-hook): Use it here.
+ (slime-scheme-mode-hook): New function, use
+ slime-shared-lisp-mode-hook.
+ (slime-setup): If scheme-mode is one of the slime-lisp-modes,
+ install our hook.
+
+2006-07-13 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (keywords-of-operator): New support function for
+ writing user-defined `extra-keywords' methods.
+
+2006-07-11 Helmut Eller <heller at common-lisp.net>
+
+ * swank-allegro.lisp (make-weak-key-hash-table): Use ACL's weak
+ hashtables.
+
+ * swank.asd: Set *source-directory* to the asdf component dir.
+
+2006-07-01 Luís Oliveira <loliveira at common-lisp.net>
+
+ * swank-sbcl.lisp (locate-compiler-note): Change first branch to
+ handle the changes introduced by the previous patch to
+ swank-compile-string.
+
+2006-06-26 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (find-definitions): Remove backward
+ compatibility code.
+
+2006-06-26 Luís Oliveira <loliveira at common-lisp.net>
+
+ * swank-sbcl.lisp (tmpnam, temp-file-name): New functions.
+ (swank-compile-string): Create temporary file with the string and
+ compile-file it instead of compiling an anonymous lambda, as
+ before, in order to better handle eval-when forms.
+
+2006-06-25 Helmut Eller <heller at common-lisp.net>
+
+ * swank-source-path-parser.lisp (suppress-sharp-dot): Return a
+ unique symbol to avoid multiple entries for nil at toplevel in the
+ source-map.
+
+ * slime.el (test compile-defun): Add a test for #. reader macro at
+ toplevel.
+ (slime-run-one-test): New command.
+ (sldb-activate): Recreate the sldb buffer if it doesn't
+ exist. (Can happen if someone kills the buffer manually.)
+ (slime-wait-condition): Add a dummy to slime-stack-eval-tags while
+ waiting so that the SLDB enters a recursive edit.
+
+2006-06-18 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-echo-arglist): Simplify, just use slime-autodoc.
+
+ * swank.lisp (arglist): Distinguish between provided actual args
+ and required formal args using the new slot provided-args.
+ (form-completion): Likewise.
+ (decoded-arglist-to-string): Use it here to display the argument
+ list (make-instance 'CLASS-NAME ...) rather
+ than (make-instance (quote CLASS-NAME) ...).
+
+ * swank.lisp (extra-keywords change-class): Don't drop the first
+ argument.
+
+ * slime.el (slime-parse-extended-operator-name): Don't move
+ point; fixes infinite loop.
+
+2006-06-17 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-parse-extended-operator-name/cerror): Handle
+ cerror and change-class with :make-instance.
+ (slime-extended-operator-name-parser-alist): Handle change-class.
+ (slime-parse-extended-operator-name)
+ (slime-enclosing-operator-names): Fix the case when point is
+ within the operator.
+
+ * swank.lisp (operator-designator-to-form): Handle cerror and
+ change-class with :make-instance.
+
+2006-06-16 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (operator-designator-to-form): Handle :cerror.
+ (extra-keywords cerror): Make it work.
+
+ * slime.el (slime-parse-extended-operator-name)
+ (slime-parse-extended-operator-name/make-instance)
+ (slime-parse-extended-operator-name/defmethod): New functions,
+ factored out from slime-enclosing-operator-names.
+ (slime-parse-extended-operator-name/cerror): New function.
+ (slime-extended-operator-name-parser-alist): New variable.
+ (slime-enclosing-operator-names): Use them here.
+
+2006-06-14 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-goto-definition): If all definitions of a name
+ have the same location, go there directly rather than presenting
+ an xref buffer.
+
+2006-06-11 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-scl (ext:stream-write-chars): update for SCL 1.3.
+
+2006-06-09 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-abcl: Update to cvs version of abcl and warnings errors
+ when compiling in a buffer will now be properly caught by slime vs
+ current behavior of always saying 0 errors 0 warnings and printing
+ them in the repl instead
+
+2006-05-31 Nathan Bird <nathan at acceleration.net>
+
+ * swank.lisp (*sldb-quit-restart*): New variable.
+ (throw-to-toplevel): Use the restart named by *sldb-quit-restart*
+ as opposed to hard coding abort-request.
+
+2006-05-30 Tobias Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-get-temp-buffer-create): New keyword REUSEP
+ which indicates whether an already-existing buffer named like the
+ buffer to be created should be reused, i.e. not killed, then
+ freshly created. Update docstring accordingly.
+ (slime-with-output-to-temp-buffer): Make &optional arg MODE an
+ &key keyword arg. Add REUSEP keyword.
+ (slime-macroexpansion-minor-mode-map): Make remapped `undo' update
+ highlighted edits in the macroexpansion buffer.
+ (slime-eval-macroexpand-in-place): Update highlighted edits when
+ macroexpanding in-place.
+ (slime-eval-macroexpand): Reuse macroexpansion buffer if it exists
+ already to preserve `undo' functionality.
+
+2006-05-30 Tobias Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-use-autodoc-mode): Fix typo in docstring.
+ (slime-use-highlight-edits-mode): New variable, analogous to
+ SLIME-USE-AUTODOC-MODE.
+ (slime-setup, slime-lisp-mode-hook): Make above variable
+ work. Also, activates the HIGHLIGHT-EDITS-MODE in proper way (thus
+ avoiding the nasty "Toggling ... off; better pass an explicit
+ argument." message.)
+
+ * slime.el: Fix typo in comment about communication protocol.
+
+2006-05-27 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank-abcl: slot-boundp-using-class slot-value-using-class so you
+ can inspect instances
+
+2006-05-26 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime.el (slime-eval-macroexpand-inplace): Fix out-of-range
+ error on in-place macroexpand when point is placed at a closing
+ parenthesis. In this case the sexp closed by that paren is
+ expanded.
+ Also make expanding of expressions work that are quoted like, for
+ instance, "'(FOO BAR)" if point is placed at the opening paren.
+
+2006-05-24 Brian Downing <bdowning at lavos.net>
+
+ * swank.lisp (recursively-compute-most-completions & friends):
+ Micro-optimize the fuzzy completion engine, improving performace
+ by a factor of about 4 on SBCL. However, it will only work on
+ simple-strings now, and CHAR= is burned in instead of being an
+ option. I don't think this is too much of a limitation. At this
+ point rendering the results on the emacs side takes much longer
+ than finding them for long result lists.
+
+2006-05-24 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank-abcl: Add some more mop functions to you can inspect classes,
+ generic functions, methods, slots.
+
+2006-05-16 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-repl-return-behaviour): New variable which
+ controls slime-repl-return's heaviour.
+ (slime-repl-return): Respect slime-repl-return-behaviour.
+
+2006-05-14 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-macroexpansion-minor-mode-map): Rebind 'undo' to
+ set buffer-read-only temporarily to t.
+ (slime-repl-return): Only send repl input if point is past a
+ complete form.
+
+2006-05-12 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (update-indentation-information): Fix for problem
+ with Allegro CL 8.0: If I type M-x slime-update-indentation,
+ Allegro CL starts growing until it hits a STORAGE-CONDITION or
+ even segfaults.
+
+2006-05-04 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-allegro.lisp (fspec-definition-locations): Handle
+ :top-level-form entries that appear in backtraces.
+
+2006-04-20 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp (toggle-trace): Implemented. Currently only
+ provides 'best effort' support, :labels and :flet are ignored,
+ :defmethod and :call are treated like a normal trace of the
+ operator.
+
+2006-04-20 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*use-dedicated-output-stream*): Make it nil by
+ default to avoid race conditions.
+
+2006-04-19 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * doc/Makefile (contributors.texi): use texinfo macros for
+ accented characters.
+
+ * ChangeLog: canonize Gabor Melis' spelling, otherwise he appears
+ twice in the "Hackers of the good Hack table"
+
+ * doc/slime.texi (nyorsko): delete
+ (EDITION): make it say 2.0
+
+2006-04-19 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank.lisp (decoded-arglist-to-string): if the keyword and the
+ variable are different, print the keyword name with escapes.
+ (encode-keyword-arg): get the keyword and the arg-name the same
+ way round as in lambda lists.
+ (appliable-methods-keywords): use
+ swank-mop:compute-applicable-methods-using-classes and
+ compute-applicable-methods in the AMOP-friendly way, to get EQL
+ specializers right.
+ (class-from-class-name-form, extra-keywords/slots): new.
+ (extra-keywords/make-instance): use new functions. Also get
+ keywords from SHARED-INITIALIZE (after Dan Barlow) and
+ ALLOCATE-INSTANCE.
+ (extra-keywords/change-class): new.
+ (extra-keywords (eql 'change-class)): new. Won't work at present,
+ just as the CERROR case doesn't work.
+
+2006-04-19 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank-sbcl.lisp (preferred-communication-style): Make it nil
+ under win32, for now.
+
+ * doc/slime.texi: document nil *communication-style*
+
+2006-04-18 Espen Wiborg <espenhw at grumblesmurf.org>
+
+ * swank-corman.lisp: Define a class file-stream to let swank.lisp
+ load.
+
+2005-04-17 Andras Simon <andras at renyi.hu>
+
+ * swank-abcl.lisp: (accept-connection): New argument: timeout.
+
+2006-04-14 Gerd Flaig <gefla at pond.sub.org>
+
+ * slime.el (slime-autodoc): Fix reference to unbound variable.
+
+2006-04-13 Martin Simmons <martin at lispworks.com>
+
+ * swank-loader.lisp (load-site-init-file, swank-source-files): Fix
+ pathname construction to take all unspecified components from the
+ directory pathname, in particular the drive letter on Windows.
+
+2006-04-13 Helmut Eller <helmut at common-lisp.net>
+
+ * slime.el (slime-find-filename-translators): Use assoc-if instead
+ of assoc-default for XEmacs compatibility.
+ (slime-show-note-counts): Don't show the highlighting bit as it
+ spills of the screen.
+ (slime-highlight-notes): Use with-temp-message.
+ (with-temp-message): Define it for XEmacs.
+ (slime-beginning-of-symbol): Use eq instead of char-equal as
+ char-equal signals an error at the beginning of a buffer.
+
+2006-04-13 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-scl (make-socket-io-stream): set the stream to ignore
+ character conversion errors, and to substitute the character #\?.
+ Without this the communication channel is prone to lockup when a
+ conversion error occurs.
+
+ * swank-scl (inspect-for-emacs function): correct the index into the
+ closure environment; it was reading off the end of the closure
+ environment and picking up a corrupting value.
+
+ * swank-scl (mailbox): rework the mailbox implementation to better
+ handle interruption. Use a polling loop rather than condition
+ variables because interrupting a condition variable wait leaves the
+ thread with the condition variable lock held and leads to a deadlock
+ error.
+
+2006-04-12 Robert Macomber <slime at rojoma.com>
+
+ * swank-backend.lisp (make-recursive-lock): New interface
+ function.
+ (call-with-recursive-lock-held): New interface function.
+
+ * swank-grey.lisp (class slime-output-stream): Added recursive
+ locking to class and generic functions specialized on it.
+ (clss slime-input-stream): Added recursive locking to class and
+ generic functions specialized on it.
+
+ * swank-sbcl.lisp (make-recursive-lock): Implement the new interface.
+ (call-with-recursive-lock): Implement the new interface.
+
+2006-04-01 Matthew D. Swank <akopa at charter.net>
+
+ * slime.el (slime-fontify-string): Use set-text-properties, not
+ propertize, for Emacs 20 compatibility.
+
+2006-03-30 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-init-command): Don't translate filenames since
+ the new scheme doesn't work without a connection.
+ (slime-to-lisp-filename,slime-from-lisp-filename): Remove some
+ redundancy.
+ (slime-macroexpansion-minor-mode): Make it Emacs 20 compatible.
+
+2006-03-29 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-mode): Enable autodoc-mode if
+ slime-use-autodoc-mode is true.
+
+2006-03-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (multiple-value-or): New macro.
+
+ * slime.el (slime-recently-visited-buffer): Ignore internal
+ buffers (starting with a space), to avoid selecting the
+ *slime-fontify* buffer. Reported by Andreas Fuchs.
+
+ * slime.el (slime-enclosing-operator-names): Handle forms similar
+ to make-instance (make-condition, error, etc.), to get extra
+ keywords based on the condition class.
+
+ * swank.lisp (operator-designator-to-form): Handle forms similar
+ to make-instance (make-condition, error, etc.)
+ (extra-keywords/make-instance): New function.
+ (extra-keywords): Specialize on operators make-condition, error,
+ signal, warn, cerror. Use multiple-value-or.
+
+2006-03-27 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-make-tramp-file-name): If emcas' tramp has
+ tramp-multi-methods then pass the method parameter to
+ tramp-make-tramp-file-name, otherwise don't.
+ (slime-create-filename-translator): Use
+ slime-make-tramp-file-name.
+
+2006-03-27 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * hyperspec.el (common-lisp-hyperspec-strip-cl-package): New
+ function.
+ (common-lisp-hyperspec): Don't get confused by a cl: or
+ common-lisp: package prefix.
+
+ * slime.el (slime-hyperspec-lookup): Don't get confused by a cl:
+ or common-lisp: package prefix.
+
+2006-03-26 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-enclosing-operator-names): Fix for situation
+ when point is at end of buffer, as it happens often in the REPL.
+
+2006-03-25 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (arglist-for-echo-area): New keyword arg,
+ print-lines.
+ (decoded-arglist-to-string): New function, implement argument
+ highlighting also for &optional and &rest/&body arguments.
+ (arglist-to-string): Use decoded-arglist-to-string.
+ (arglist): New slots aux-args, known-junk, unknown-junk.
+ (nreversef): New macro.
+ (decode-arglist, encode-arglist): Refine to handle more structure
+ in argument lists, including implementation-defined stuff like
+ &parse-body.
+ (format-arglist-for-echo-area): New keyword arg, print-lines.
+ Simplify the code as there is no need to fall back to the unparsed
+ arglist any more.
+
+ * slime.el (slime-fontify-string): Fix for arguments spanning
+ multiple lines.
+ (slime-autodoc-message-dimensions): New.
+ (slime-autodoc-thing-at-point): Use it here to either ask for a
+ one-line or a nicely formatted multi-line arglist.
+ (slime-enclosing-operator-names): Handle linebreaks.
+
+2006-03-24 Mikel Bancroft <mutandiz at yahoo.com>
+
+ * swank-allegro.lisp (set-default-directory): Fix for pathnames
+ without a trailing slash.
+
+2006-03-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-background-activities-enabled-p): Allow
+ "background activities" in sldb-mode.
+ (slime-autodoc-message-ok-p): Allow autodoc in sldb-mode.
+ (sldb-mode-syntax-table): New variable.
+ (sldb-mode): Enable autodoc-mode when slime-use-autodoc-mode is
+ true. Use sldb-mode-syntax-table to make #<...> balance like
+ parentheses. This enables autodoc-mode to match #<unreadable>
+ actual arguments in the backtraces with formal arguments of the
+ function.
+ (slime-beginning-of-symbol, slime-end-of-symbol): Handle
+ es::|caped| symbols.
+ (slime-enclosing-operator-names): Use syntax table to check
+ whether we are at the beginning of a balanced expression.
+
+2006-03-23 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank.lisp (ed-in-emacs): Allow conses as function names.
+ Ensure that there is a connection to emacs before sending the
+ :ed message.
+
+ * slime.el (slime-edit-definition): read names, not symbols.
+ (slime-ed): handle conses whose car is not a string as function
+ names.
+
+2006-03-23 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-qualify-cl-symbol-name): Strip leading colon
+ from package names for qualifying symbols.
+ (slime-call-defun): New command.
+ (slime-keys): Bind it to C-c C-y.
+ (slime-easy-menu): Show it in the menu.
+
+ * slime.el (slime-autodoc-use-multiline-p): New defcustom.
+ (slime-autodoc-message): Use it here. Fix bug that autodoc
+ messages exceeding one line could not be overwritten by later
+ autodoc messages.
+ (slime-autodoc-pre-command-refresh-echo-area): Use message
+ rather than slime-background-message.
+
+ * swank.lisp (casify): Removed.
+ (casify-char, tokenize-symbol-thoroughly): New functions.
+ (parse-symbol): Use tokenize-symbol-thoroughly, so as to handle
+ |escaped symbols|. This fixes arglist display for operators with
+ strange symbol names.
+
+2006-03-23 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-backend (accept-connection): add a 'timeout argument to
+ this function.
+
+ * swank-backend (set-stream-timeout): new implementation specific
+ function. Used to set the timeout for stream operations, which
+ can help make the network connection establishment more robust.
+
+ * swank (setup-server): ignore errors from the function 'serve to
+ allow another connection to be made.
+
+ * swank (serve-connection): ensure the listener socket is closed
+ when 'dont-close is false, even if the connection attempt fails.
+
+ * swank (accept-authenticated-connection): ensure the new
+ connection is closed if the connection establishment fails. Set a
+ short stream timeout to prevent denial of survice.
+
+ * swank (open-dedicated-output-stream): ensure the listener socket
+ is closed, even if unable to open the dedicated stream. Implement
+ a timeout while waiting for a connection for the dedicate stream
+ to prevent denial of service.
+
+ * swank (create-connection): ensure the new connection is closed
+ if not successful.
+
+2006-03-22 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (arglist-for-echo-area): Fix when arg-indices are
+ not given.
+
+ * slime.el (slime-ed): Handle (FILENAME :charpos CHARPOS).
+
+ * swank.lisp (inspect-for-emacs): Specialize on FILE-STREAM and
+ STREAM-ERROR, offering to visit the file at the current stream
+ position as an inspector action. Useful for dealing with reader
+ errors.
+
+2006-03-20 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-autodoc-pre-command-refresh-echo-area):
+ Show the last autodoc message again (movement commands clear it);
+ technique to avoid flickering, taken from eldoc.
+ (slime-autodoc-mode): Install it as a pre-command-hook.
+ (slime-autodoc-last-message): New variable.
+ (slime-autodoc-message): New function.
+ (slime-autodoc): Use them here.
+ (slime-autodoc-message-ok-p): OK to overwrite an autodoc message.
+
+ * slime.el (slime-handle-indentation-update): Also update
+ scheme-indent-function if slime-lisp-modes contains scheme-mode.
+
+2006-03-19 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Highlight the formal argument corresponding to the actual
+ argument around point in the echo-area arg-list display.
+ Works most impressively when slime-autodoc-mode is enabled
+ and when one has to deal with extremely long argument lists.
+
+ * slime.el (slime-space): First insert the space, then obtain
+ information.
+ (slime-fontify-string): Also handle argument highlights.
+ (slime-enclosing-operator-names): As a secondary value, return a
+ list of the indices of the arguments to the nested operator.
+ (slime-contextual-completions): Use changed interface of
+ slime-enclosing-operator-names.
+ (slime-function-called-at-point): Removed.
+ (slime-function-called-at-point/line): Removed.
+ (slime-autodoc-thing-at-point): New.
+ (slime-autodoc): Re-implement with slime-enclosing-operator-names
+ instead of slime-function-called-at-point.
+ (slime-echo-arglist): Pass the argument indices to
+ arglist-for-echo-area.
+ (slime-autodoc-message-ok-p): Autodoc is also OK in REPL buffers.
+
+ * swank.lisp (arglist-for-echo-area): New keyword argument
+ arg-indices.
+ (arglist-to-string): New keyword argument highlight.
+ (format-arglist-for-echo-area): Likewise.
+
+2006-03-18 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-goto-location-buffer): Avoid calling the
+ expensive function find-file-noselect when we are already in the
+ right buffer.
+
+ * swank.lisp (arglist-for-echo-area): Add keyword argument
+ print-right-margin.
+ (arglist-to-string, format-arglist-for-echo-area): Likewise.
+ * slime.el (slime-autodoc): Use it here to make use of the whole
+ width of the echo area for arglist display.
+
+2006-03-16 Gábor Melis <mega at hotpop.com>
+
+ * swank-allegro.lisp (inspect-for-emacs): Fix typo.
+
+2006-03-16 Gary King <gwking at metabang.com>
+
+ * swank-loader.lisp (lisp-version-string): Modified swank-loader
+ so that Allegro's alisp and mlisp programs get different
+ locations. Otherwise mlisp complains about alisp's files.
+
+2006-03-16 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-to-lisp-filename): Call expand-file-name before
+ passing the filename to the to-lisp function.
+
+2006-03-14 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-system-history): New variable.
+ (slime-read-system-name): Use a separate history list for ASDF
+ system names.
+ (slime-note-counts-message): New variable.
+ (slime-show-note-counts): Store the note counts message for later use.
+ (slime-highlight-notes, slime-list-compiler-notes): Show a
+ progress message, keeping note counts visible.
+ (slime-find-buffer-package): Handle IN-PACKAGE forms that appear
+ in SWIG/Allegro CL wrappers.
+
+ * swank-allegro.lisp (compile-from-temp-file): Suppress Allegro's
+ redefinition warnings; they are pointless when we are compiling
+ via a temporary file.
+ (profile-report): Implement.
+
+2006-03-06 Nathan Bird <nathan at acceleration.net>
+
+ * slime.el (slime-create-filename-translator): use the tramp
+ methods for dissecting and building filenames.
+
+2006-03-04 Wojciech Kaczmarek <wojtekk at kofeina.net>
+
+ * slime.el (slime-filename-translations): Typo in example.
+ (slime-create-filename-translator): Typo in generated lambdas.
+
+2006-03-03 Marco Baringer <mb at bese.it>
+
+ Allow per-host (per machine-instance actually) filename
+ translation functions.
+
+ * slime.el (slime-translate-to-lisp-filename-function): removed.
+ (slime-translate-from-lisp-filename-function): removed.
+ (slime-filename-translations): New variable.
+ (slime-to-lisp-filename): Rewrote to search through available
+ transalations.
+ (slime-from-lisp-filename): idem.
+ (slime-create-filename-translator): New function.
+ (slime-add-filename-translation): New function.
+
+2006-02-27 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-eval-macroexpand-inplace): Indent the inserted
+ macroexpansion.
+
+2006-02-27 Marco Baringer <mb at bese.it>
+
+ Provide functions for performing macroexpansion inplace, use these
+ functions in the *SLIME macroexpansion* buffer.
+
+ * slime.el (slime-macroexpansion-minor-mode): Attempt to map
+ -inplace functions to the same keys as their regular contureparts
+ in slime-mode-map.
+ (slime-eval-macroexpand-inplace): New function.
+ (slime-macroexpand-1-inplace): New function.
+ (slime-macroexpand-all-inplace): New function.
+ * doc/slime.texi: Document new macroexpansion mode.
+
+2006-02-26 Douglas Crosher <dcrosher at common-lisp.net>
+ * swank-scl.lisp: (ext:stream-read-chars): Correct the updating of
+ the buffer index. Fixes slime input stream problems.
+
+2006-02-25 Helmut Eller <heller at common-lisp.net>
+
+ * swank-loader.lisp (default-fasl-directory): Previously we return
+ only the directory-namestring which breaks SCL, because it loses
+ the host and device components. Return the complete pathname
+ instead. Patch by Douglas Crosher.
+
+ * slime.el (slime-lisp-host): New variable. Replace all references
+ to "127.0.0.1" with the variable.
+
+2006-02-25 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-backend.lisp (operate-on-system): symbol case fix for
+ SCL's lowercase mode.
+
+ * swak.lisp (setup-stream-indirection)
+ (globally-redirect-io-to-connection)
+ (revert-global-io-redirection): symbol case fixes.
+
+ * swank-scl.lisp: (inspect-for-emacs): Fixes for the inspect
+ standard-objects, and inspect array. Plus misc symbol case fixes.
+
+2006-02-22 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-send-input): Don't include the final
+ newline in the slime-repl-input-face overlay, thus avoid showing the
+ "Evaluation aborted" message in boldface. Don't set non-existent
+ "rear-nonsticky" overlay property; overlay stickiness is
+ controlled by make-overlay arguments.
+
+2006-02-20 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Use argument list information to complete keywords contextually.
+ Example: (find 1 '(1 2 3) :s <M-TAB> --completes--> :start
+ rather than suggesting all ever-interned keywords starting with ":s".
+
+ * slime.el (slime-complete-keywords-contextually): New
+ customizable variable.
+ (slime-enclosing-operator-names): New optional argument
+ max-levels.
+ (slime-completions-for-keyword): New.
+ (slime-contextual-completions): New.
+ (slime-expand-abbreviations-and-complete): Use it instead of
+ slime-completions.
+
+ * swank.lisp (operator-designator-to-form): New, factored out from
+ arglist-for-echo-area.
+ (arglist-for-echo-area): Use it here.
+ (completions-for-keyword): New.
+ (find-matching-symbols-in-list): New.
+
+2006-02-19 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-expand-abbreviations-and-complete): Scroll the
+ completions buffer if the TAB key is pressed another time, like
+ Emacs minibuffer completion does.
+
+2006-02-18 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-macroexpansion-minor-mode): New minor mode for
+ macroexpansion buffer. Exactly like slime-temp-buffer-mode but
+ with slime-macroexpand-again bound to "g".
+ (*slime-eval-macroexpand-expression*): New variable. introduced
+ for slime-macroexpand-again, used by slime-eval-macroexpand as
+ well.
+ (slime-eval-macroexpand): Added optional string argument which
+ defaults to (slime-sexp-at-point-or-error).
+ (slime-macroexpand-again): New function, redoes the last
+ macroexpansion.
+ (slime-sexp-at-point-or-error): New function. Like
+ slime-sexp-at-point but signals an error when slime-sexp-at-point
+ would return nil.
+ * swank-openmcl.lisp (swank-mop:compute-applicable-methods-using-classes):
+ Implement.
+
+2006-02-16 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * sbcl-pprint-patch.lisp: New file, adds the annotations feature
+ to the SBCL pretty printer. This is needed for sending
+ presentations through pretty-printing streams.
+ * present.lisp [sbcl]: Load it here.
+ (slime-stream-p, write-annotation) [sbcl]: Handle pretty-streams.
+
+2006-02-10 Helmut Eller <heller at common-lisp.net>
+
+ * swank-allegro.lisp, swank-lispworks.lisp (inspect-for-emacs):
+ Use the backend specific method to inspect standard-objects
+ because {slot-boundp,slot-value}-using-class don't conform to the
+ MOP spec in LW and ACL.
+
+ * swank.lisp (macro-indentation): Don't count '&optional as
+ argument.
+
+ * swank-loader.lisp (default-fasl-directory): Include the SLIME
+ version.
+ (slime-version-string): New.
+
+2006-02-06 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Show enriched arglists for DEFMETHOD in the echo area when the
+ user types SPC after the generic function name.
+
+ * swank.lisp (arglist-to-template-string): Unused, removed.
+ (extra-keywords): Indicate which part of the actual arglist was
+ used to determine the extra keywords. For MAKE-INSTANCE, don't
+ signal an error if the class does not exist.
+ (enrich-decoded-arglist-with-extra-keywords): Indicate which part
+ of the actual arglist was used to determine the extra keywords,
+ and whether any extra keywords were added.
+ (form-completion): Generalize to handle display of enriched formal
+ arglists.
+ (read-incomplete-form-from-string): New, factored out from
+ complete-form. Handle end-of-file.
+ (complete-form): Use it here.
+ (format-arglist-for-echo-area): Use form-completion, so as to
+ show enriched formal arglists for MAKE-INSTANCE and DEFMETHOD
+ calls.
+ (arglist-for-echo-area): Handle MAKE-INSTANCE and DEFMETHOD
+ calls.
+
+ * slime.el (slime-enclosing-operator-names): Represent
+ MAKE-INSTANCE calls by (:make-instance "CLASS-NAME"), handle
+ DEFMETHOD too.
+
+2006-02-05 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-complete-form): Indent the inserted template.
+
+2006-02-04 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-fontify-string): New.
+ (slime-echo-arglist, slime-arglist, slime-autodoc): Use it here to
+ fontify echo-area arglists.
+
+2006-02-02 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp: Added imports for slot-boundp-using-class,
+ slot-value-using-class and finalize-inheritance.
+
+2006-02-01 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-abcl.lisp: define with-compilation-hooks (= funcall for now), so that you can do slime-oos
+
+2006-01-30 Ian Eslick <eslick at csail.mit.edu>
+
+ Show slot values for metaclasses that override the default storage
+ locations for objects slots (i.e. where the default slot-boundp
+ returns nil) in the inspector.
+
+ * swank.lisp (inspect-for-emacs standard-object): Use
+ slot-value-using-class and slot-boundp-using-class.
+
+ * swank-backend.lisp: Add slot-value-using-class and
+ slot-boundp-using-class to the swank-mop package.
+
+2006-01-26 Luís Oliveira <loliveira at common-lisp.net>
+
+ * slime.el (slime-enclosing-operator-names): detect make-instance
+ forms and collect the class-name argument if it exists and is a
+ quoted symbol.
+
+ * swank.lisp (arglist-for-echo-area): handle pairs of of the form
+ ("make-instance" . "<class-name>") by passing them to
+ format-initargs-and-initforms-for-echo-area.
+ (class-initargs-and-iniforms): New function.
+ (format-initargs-and-initforms-for-echo-area): New function.
+
+2006-01-20 Mészáros Levente <melevy at freemail.hu>
+
+ * swank-sbcl.lisp (restart-frame): Provide an implementation even
+ if it doesn't quite do what it's supposed to do.
+
+2006-01-19 Helmut Eller <heller at common-lisp.net>
+
+ Return to the previous loading strategy: load everything when
+ swank-loader is loaded. It's just to convenient to give that up.
+ To customize the fasl directories, the new variable
+ swank-loader:*fasl-directory* can be set before loading
+ swank-loader.
+
+ * swank-loader.lisp (*fasl-directory*, *source-directory*): New
+ variables.
+ (load-swank): Call it during loading.
+
+2006-01-14 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-compile-defun): If point was at the opening
+ paren we wrongly used the preceding toplevel form. Fix it.
+ Reported by Chisheng Huang and Liam M. Healy.
+
+ * swank.lisp (spawn-threads-for-connection): Fix a race condition:
+ Don't accept input before all threads are ready.
+
+ Make the fasl directory customizable: load-swank must now be
+ called explicitly so that we can supply the fasl dir as argument.
+
+ * swank-loader.lisp (load-swank): New entry point.
+
+2006-01-14 Andreas Fuchs <asf at boinkor.net>
+
+ * slime.el (slime-selector ?r): Call slime instead of slime-start
+ to pick up the usual defaults.
+
+2005-12-31 Harald Hanche-Olsen <hanche at math.ntnu.no>
+
+ * slime.el (slime-open-stream-to-lisp): Inherit the
+ process-coding-system from the current connection.
+
+2005-12-27 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-abcl. (backtrace-as-list-ignoring-swank-calls): remove the
+ swank calls from the backtrace to make it easier to use.
+ (frame-locals): Fix a typo that caused entry into the debugger if
+ you tried to look at frame locals. Now you don't error out, but
+ you still don't see frame locals because I don't know how to get
+ them :(
+
+2005-12-27 Helmut Eller <heller at common-lisp.net>
+
+ Keep a history of protocol events for better bug reports.
+
+ * swank.lisp (log-event): Record the event in the history buffer.
+ (*event-history*): Buffer for events.
+ (dump-event-history): New function.
+ (close-connection): Escape non-ascii strings and include the event
+ history in the error message.
+
+2005-12-22 Helmut Eller <heller at common-lisp.net>
+
+ Make highlighting of modified text a minor mode. Also use
+ after-change-functions instead of rebinding all self-inserting
+ keys.
+
+ * slime.el (slime-highlight-edits-mode): New minor mode.
+ (slime-self-insert-command): Deleted.
+ (slime-before-compile-functions): New hook to decouple edit
+ highlighting from compilation.
+ (slime-highlight-edits-face): Renamed from slime-display-edit-face.
+
+2005-12-20 Marco Baringer <mb at bese.it>
+
+ When inspecting classes, methods and generic functions show all
+ the slots in the case that what we're inspecting is a subclass of
+ the standard class and has extra user defined slots.
+
+ * swank.lisp (all-slots-for-inspector): New function.
+ (inspect-for-emacs): Use all-slots-for-inspector.
+
+2005-12-19 Peter Seibel <peter at gigamonkeys.com>
+
+ * slime.el (slime-self-insert-command): Got rid of message about
+ setting up face and skipping edit-hilights when in a comment.
+
+2005-12-18 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * slime.el (slime-mode-hook): Bind simple characters to
+ slime-self-insert-command only if there was no previous local
+ binding, and the major mode is _not_ slime-repl-mode. This
+ restores keybindings of slime-xref-mode and prevents us from
+ stomping on user bindings. The hilighting also makes no sense in
+ the REPL.
+
+2005-12-16 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * slime.el (slime-selector-method: ?r): If no connection offer to
+ start Slime.
+
+ * swank.lisp (to-string): Handle errors from printing objects.
+ Among other things makes the inspector more robust in the face of
+ objects with unbound slots and print-methods that fail to cope.
+
+2005-12-16 William Bland <doctorbill.news at gmail.com>
+
+ Added hilighting of tetx which has been edited but not yet
+ compilied.
+
+ * slime.el (slime-display-edit-hilights): New variable.
+ (slime-display-edit-face): New face.
+ (slime-compile-file, slime-compile-defun, slime-compile-region):
+ Remove edits overlay.
+ (slime-remove-edits): New function.
+ (slime-self-insert-command): New function.
+ (slime-mode-hook): Rebind simple characters to
+ slime-self-insert-command.
+
+2005-12-07 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-allegro.lisp (find-definition-in-file)
+ (find-fspec-location, fspec-definition-locations): Allegro CL
+ properly records all definitions made by arbitrary macros whose
+ names start with "def". Use excl::find-source-file and
+ scm:find-definition-in-definition-group (rather than
+ scm:find-definition-in-file) to find them.
+
+ * slime.el (slime-load-file): Change the default to be the buffer
+ file name with extension. This is more convenient for files like
+ .asd files that do not have the default source file extension.
+ (slime-save-some-lisp-buffers, slime-update-modeline-package):
+ Handle all files with major mode in slime-lisp-modes, not just
+ lisp-mode.
+
+2005-12-06 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (function-source-location,
+ safe-function-source-location): Oops, define these functions also
+ for the >0.9.6 case. Fixes broken sldb-show-source on SBCL 0.9.7.
+
+2005-12-05 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-find-coding-system): Use check-coding-system
+ only if it's actually fbound.
+
+2005-11-22 Marco Monteiro <masmxx at gmail.com>
+
+ * slime.el (slime-connect): Use slime-net-coding system if the
+ optional arg coding-system was not supplied.
+
+2005-11-22 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-compile-file): Call 'check-parens before
+ compiling.
+ (slime-compile-file): Call 'check-parens before compiling.
+ (slime-find-coding-system): Return nil if the coding system
+ isn'tvalid instead of singalling an error.
+ (slime-repl-history-file-coding-system): Use
+ slime-find-coding-system to find the default.
+
+ * swank-cmucl.lisp (accept-connection): Remove fd-handlers if the
+ encoding isn't iso-latin-1.
+
+2005-11-21 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-start): Don't set slime-net-coding-system ..
+ (slime-read-port-and-connect): .. read it from the inferior lisp args.
+ (slime-connect): Take the coding-system as third argument.
+ (slime-repl-history-file-coding-system): New user option.
+ (slime-repl-safe-save-merged-history): New function. Use it in
+ hooks so that bad coding systems don't stop us from exiting.
+ (slime-repl-save-history): Include the coding-system which was
+ used to save the buffer.
+ (repl-shoctut change-package): Add alias ,in and ,in-package.
+ (slime-eval-macroexpand): Error out early if there's no sexp at
+ point.
+ (slime-compiler-macroexpand): New command.
+ (slime-inspector-pprint): New command.
+
+ * swank-cmucl.lisp (inspect-for-emacs): Add support for
+ funcallable instances.
+
+ * swank.lisp (pprint-inspector-part, swank-compiler-macroexpand): New.
+
+ * swank-backend.lisp (compiler-macroexpand)
+ (compiler-macroexpand-1): New functions.
+
+2005-11-14 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-scl.lisp (accept-connection): handle the :buffering argument.
+
+2005-11-13 Andras Simon <andras at renyi.hu>
+
+ * swank-abcl.lisp: (accept-connection): New argument: buffering.
+
+2005-11-13 Andras Simon <andras at renyi.hu>
+
+ * swank-abcl.lisp: Steal auto-flush stuff from swank-sbcl.lisp
+
+2005-11-11 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*dedicated-output-stream-buffering*): New variable
+ to customize the buffering scheme. For single-threaded Lisps we
+ disable buffering because lazy programmers forget to call
+ finish-output.
+ (open-dedicated-output-stream): Use it.
+
+ * swank-backend.lisp, swank-allegro.lisp, swank-lispworks.lisp,
+ swank-openmcl.lisp, swank-cmucl.lisp, swank-sbcl.lisp,
+ swank-clisp.lisp, swank-abcl.lisp, swank-corman.lisp,
+ swank-ecl.lisp (accept-connection): New argument: buffering.
+
+ * slime.el (slime-repl-save-history): When the history exceeds
+ slime-repl-history-size remove the old not the new entries.
+ Some renaming:
+ slime-repl-read-history -> slime-repl-load-history,
+ slime-repl-read-history-internal -> slime-repl-read-history.
+ (slime-eval-macroexpand): Call font-lock-fontify-buffer
+ explicitly, because with certain Emacs versions the buffer doesn't
+ get fontified immediately.
+
+2005-11-07 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-eval-macroexpand): Use lisp-mode (and
+ font-lock-mode) when dispaying the expansion. Suggested by Jan
+ Rychter.
+
+ * swank-source-path-parser.lisp (make-source-recording-readtable):
+ Suppress the #. reader-macro.
+
+2005-11-06 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (find-definitions, make-source-location-specification
+ make-definition-source-location, source-hint-snippet): As of
+ SBCL 0.9.6.25 SB-INTROSPECT has better support for finding
+ source locations. Use as much of it in swank-sbcl as possible.
+ (Original version left reader-conditionalized for older SBCLs).
+
+2005-11-04 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (connection-info): Docfix.
+
+ * slime.el (slime-set-connection-info): Generate a new connection
+ name only if the implementation-name and the inferior-lisp-name
+ are different.
+
+2005-10-31 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-start, slime-lookup-lisp-implementation)
+ (slime-set-connection-info): Add a :name property for the
+ implementation and use it to derive the connection-name.
+ (slime-lisp-implementation-name): Renamed from
+ slime-lisp-implementation-type-name.
+
+ * swank.lisp (simple-serve-requests): Add an extra abort restart.
+ (connection-info): Rename :type-name to :name.
+
+2005-10-30 Andras Simon <andras at renyi.hu>
+
+ * swank-abcl.lisp (inspect-for-emacs): Track mop changes in ABCL.
+
+2005-10-30 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-eval): Ensure that the connection is open before
+ waiting for input.
+
+ * swank.lisp (simple-serve-requests): Close the connection at the
+ end.
+
+2005-10-23 Harald Hanche-Olsen <hanche at math.ntnu.no>
+
+ * slime.el (slime-init-keymaps): Use vectors when defining keys,
+ because e.g. (define-key (string ?\C-c) ...) doesn't work in the
+ emacs-unicode-2 branch.
+
+2005-10-23 Stefan Kamphausen <skampi at gmx.net>
+
+ * slime.el (slime-repl-history-size, slime-repl-history-file): Use
+ defcustom to declare the variables.
+
+2005-10-23 Gábor Melis <mega at hotpop.com>
+
+ * swank-backend.lisp (install-debugger-globally): new interface
+ function
+
+ * swank.lisp (install-debugger): call install-debugger-globally
+
+ * swank-sbcl.lisp (install-debugger-globally): set
+ sb-ext:*invoke-debugger-hook* too
+
+2005-10-23 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (make-stream-interactive): Spawn a thread to
+ flush interactive streams in reasonably short intervals.
+ Remove the old backward-compatible threading implementation.
+
+ * swank.lisp (package-string-for-prompt): Respect *print-case*.
+
+2005-10-21 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-start-swank-server): Avoid comint-send-input
+ here as it seems to trigger a bug in ansi-color-for-commit-mode.
+
+2005-10-18 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank.lisp (canonical-package-nickname): always return the
+ package name as a STRING if found. This restores the printing of
+ package names as strings.
+
+2005-10-17 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (eval-in-emacs): Instead of taking a string and
+ attempting to parse it emacs side the function now takes a form
+ and converts it to a string internally. This should allow users of
+ the function to not have to worry about quoting issues and emacs'
+ different printed represenation for, among other things,
+ characters.
+ (process-form-for-emacs): New function. Converts a list into a
+ string for passing to emacs.
+
+ * slime.el (slime-eval-for-lisp): New API. This function now takes
+ a single string, representing the form to evaluate, and uses
+ emacs' read function to convert it into a form before eval'ing it.
+ (slime-dispatch-event): The :eval event now passes a single
+ string (instead of a string and something looking kind of like a
+ form).
+
+2005-10-15 Douglas Crosher <dcrosher at common-lisp.net>
+
+ * swank-scl.lisp: Support for Scieneer Common Lisp.
+
+ * swank-backend.lisp (*gray-stream-symbols*) Scieneer Common Lisp
+ implements stream-line-length.
+
+ * swank-loader.lisp: Support for Scieneer Common Lisp:
+ (*sysdep-pathnames*) use swank-scl.
+ (*impl ementation-features*) add :scl.
+ (*os-features*) add :hpux.
+ (*architecture-features*) add :amd64, :i686, :i486, :sparc64, :sparc,
+ :hppa64, and :hppa.
+
+ * swank.lisp: (*canonical-package-nicknames*) use lowercase
+ symbols to name the packages. This supports CL implementations
+ with lowercase default symbol names, such as Scieneer Common Lisp,
+ while still being compatible with ANSI-CL.
+
+2005-10-11 Stefan Kamphausen <skampi at gmx.net>
+
+ * slime.el: Persistent REPL history. The history from REPL
+ buffers is now saved to the file ~/.slime-history.eld. The file
+ is read on startup and saved when a REPL buffer gets killed or
+ when Emacs exits. There are also commands to save or read the
+ history file.
+ (slime-repl-save-merged-history, slime-repl-merge-histories)
+ (slime-repl-read-history, slime-repl-save-history): New functions.
+ (slime-repl-history-file, slime-repl-history-size): New vars.
+ (slime-repl-mode): Add hooks to load and save the history.
+
+2005-10-11 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-read-interactive-args): Split the string
+ inferior-lisp-program to get the values for :program and
+ :program-args. Also let slime-lisp-implementations take
+ precedence if non-nil.
+ (slime-lisp-implementations): Renamed from
+ slime-registered-lisp-implementations.
+
+ * swank.lisp (force-user-output): There seems to be a bug in
+ Allegro's two-way-streams. As a workaround we use force-output for
+ the user-io stream. (finish-output *debug-io*) still triggers the
+ bug.
+
+2005-10-10 Svein Ove Aas <svein.ove at aas.no>
+
+ * swank-allegro.lisp (find-external-format): Translate :utf-8-unix
+ to :utf8, which Allegro 7.0 understands.
+
+2005-10-09 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime, slime-start): Introduce a separate function for
+ the non-interactive case. `slime-start' takes lots of keyword
+ arguments and `slime' is reserved for interactive use.
+ (slime-read-interactive-args): New function.
+ (slime-maybe-start-lisp, slime-inferior-lisp)
+ (slime-start-swank-server): Pass all arguments needed to start
+ the subprocess as a property list. Also store this list in a
+ buffer-local var in the inferior-lisp buffer, so that we can
+ cleanly restart the process.
+ (slime-registered-lisp-implementations): Change the format and
+ document it. M-- M-x slime can now be used select a registered
+ implementation.
+ (slime-symbolic-lisp-name): Deleted. And updated all the functions
+ which passed it along.
+ (slime-set-connection-info): Use the new format.
+ (slime-output-buffer): Don't re-initialize buffer-local variables
+ if the buffer already exists. This saves the history. From Juho
+ Snellman.
+
+ * swank-cmucl.lisp (sis/in): Use finish-output instead of
+ force-output.
+
+ * swank.lisp (connection-info): Include the initial package and
+ a more self-descriptive format.
+
+2005-10-01 Juho Snellman <jsnell at iki.fi>
+
+ * swank-backend (*gray-stream-symbols*): Add :STREAM-LINE-LENGTH
+ to *GRAY-STREAM-SYMBOLS* on implementations that support this
+ extension to gray streams. Reported by Matthew D Swank.
+
+2005-09-29 Luke Gorrie <luke at synap.se>
+
+ * swank-scheme48: Removed due to excessive whining.
+
+2005-09-28 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-multiprocessing): Deleted. No longer needed.
+ (slime-init-command): Updated accordingly.
+ (slime-current-package): Add a special case for Scheme.
+ (slime-simple-completions, slime-apropos): Quote the package,
+ because in can be a plain symbol in Scheme.
+ (slime-inspector-reinspect): Use a proper defslimefun.
+
+ * swank.lisp (inspector-reinspect): New function.
+ (start-server): Call initialize-multiprocessing before starting
+ the server and startup-idle-and-top-level-loops afterwards.
+ Calling startup-idle-and-top-level-loops here shouldn't be a
+ problem because start-server is only invoked at startup via stdin.
+
+ * swank-scheme48/source-location.scm: New file. For M-.
+ * swank-scheme48/module.scm (list-all-package): New function.
+ * swank-scheme48/interfaces.scm (module-control-interface): Export it.
+ * swank-scheme48/inspector.scm: Add methods for records and hashtables.
+ (swank:arglist-for-echo-area): Implement it. Only works for
+ functions with enough debug-data (ie. only user-defined functions).
+ * swank-scheme48/completion.scm: New file.
+ (swank:simple-completions, swank:apropos-list-for-emacs): Implemented.
+ * swank-scheme48/load.scm, swank-scheme48/defrectypeX.scm: Renamed
+ the file from defrectype*.scm
+ * swank-scheme48/packages.scm (swank-general-rpc): Don't use
+ posix-process because it doesn't work on Windows, and we don't need
+ it for a mulithreaded server.
+
+2005-09-22 Helmut Eller <heller at common-lisp.net>
+
+ * swank-backend.lisp (*gray-stream-symbols*): Collect the needed
+ symbols here, so that we don't need to mention them in every
+ backend.
+ (import-from). New function.
+
+ * swank-sbcl.lisp, swank-allegro.lisp, swank-lispworks.lisp,
+ swank-openmcl.lisp, swank-ecl.lisp: Use *gray-stream-symbols* when
+ importing the needed symbols.
+
+ * swank-gray.lisp (stream-fresh-line): Define a method, so that
+ Allegro passes our tests.
+
+2005-09-21 Aleksandar Bakic <a_bakic at yahoo.com>
+
+ * swank.lisp (accept-authenticated-connection): Minor fix. Ensure
+ that the decoded message is a string before calling string= on it.
+
+2005-09-21 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-setup-command-hooks): Make
+ after-change-functions a buffer-local variable; it's by default
+ global in XEmacs.
+
+ * swank.lisp (throw-to-toplevel): Invoke the `abort-restart'
+ request instead of throwing to the `slime-toplevel' catch tag.
+ (handle-request): Rename the restart from abort to abort-request.
+ (call-with-connection): Remove the slime-toplevel catch tag
+ because with-connection is used in far to many places which aren't
+ at "toplevel".
+
+ * present.lisp (presentation-start, presentation-end): Use
+ finish-output instead of force-output.
+
+ * swank-gray.lisp, swank-cmucl.lisp: Improve stream efficiency by
+ buffering more output. stream-force-output simply does nothing, if
+ the output buffer was flushed less than 200 millisecons before.
+ stream-finish-output can still be used to really flush the buffer.
+ (slime-output-stream): New slot last-flush-time.
+ (stream-finish-output): New function. Do what stream-force-output
+ did previously.
+ (stream-force-output): Buffer more output.
+
+ * slime.el (slime-process-available-input): Oops, don't start a
+ timer for every event.
+ (slime-write-string): Renamed from slime-output-string.
+ (slime-dispatch-event): Rename :read-output to :write-string.
+ (slime-io-speed-test): New command.
+ (slime-open-stream-to-lisp): Fix parens. The coding system should
+ also be set if presentations are disabled.
+
+ * swank.lisp (make-output-function): Rename :read-output to
+ :write-string.
+ (eval-for-emacs, interactive-eval, eval-region): Use finish-output
+ not force-output.
+
+ * swank-sbcl.lisp, swank-openmcl.lisp, swank-allegro.lisp,
+ swank-lispworks: Import `stream-finish-output'.
+
+ * swank-scheme48/io.scm (empty-swank-output-buffer): Rename
+ :read-output to :write-string.
+
+ * swank-scheme48/load.scm (slime48-start): Fix '() vs. #f bug.
+
+2005-09-19 Luke Gorrie <luke at synap.se>
+
+ * nregex.lisp: Released into the public domain by Lawrence E. Freil.
+
+2005-09-19 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime48): New command.
+
+2005-09-19 Taylor Campbell <campbell at mumble.net>
+
+ * swank-scheme48/: New backend.
+
+2005-09-18 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * bridge.el: cl is required at macro expansion time (because of
+ `block'). Reported by Matthew D Swank.
+
+2005-09-18 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp: Move presentation menu protocol here from present.lisp.
+
+2005-09-15 Alan Ruttenberg <alanr-l at mumble.net>
+ * slime.el (slime-repl-return) don't copy presentation to input if
+ already in input area.
+
+2005-09-15 Helmut Eller <heller at common-lisp.net>
+
+ * swank-clisp.lisp (compute-backtrace): Include only "function
+ frames" in the backtrace. I hope that makes some sense.
+ (sldb-backtrace, function-frame-p): New functions.
+ (*sldb-backtrace*, call-with-debugging-environment, nth-frame):
+ Compute and remember the backtrace when entering the debugger.
+ (arglist): If the function has a function-lambda-expression, fetch
+ the arglist from there.
+ (find-encoding): Use strings instead of 'charset:foo symbols to
+ avoid compile time problems if the charset is not available.
+ Suggested by Vaucher Laurent.
+
+ * swank.lisp (eval-in-emacs): Fix a race condition which occurred
+ with sigio.
+ (*echo-area-prefix*): New variable.
+
+ * slime.el (slime-process-available-input): Simplify it a bit and
+ make it easier to debug read errors.
+ (slime-net-close): Don't kill the buffer if the new optional arg
+ `debug' is true.
+ (slime-run-when-idle): Accept arguments for the function.
+ (slime-init-connection-state): Close over the proc variable. It
+ was lost when the async evaluation returned.
+ (slime-output-buffer, slime-connection-output-buffer): Make
+ slime-output-buffer faster by keeping the buffer in a connection
+ variable.
+ (slime-restart-inferior-lisp-aux, slime-quit-lisp): Disable the
+ process filter to avoid errors in XEmacs.
+
+2005-09-14 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el (slime-menu-choices-for-presentation), (slime-presentation-menu)
+ Fix loss after refactoring. xemacs can't handle lambda forms in
+ the menu spec given to x-popup-menu, only symbols, so save the
+ actions in a hash table keyed by a gensym, give x-popup-menu the
+ gensym and then call the gensym. Haven't checked that it actually
+ works in xemacs because my xemacs is hosed in os x Tiger. Could
+ someone let me know...
+
+ * swank.lisp (inspect-factor-more-action)
+ rename (inspect-show-more-action) Prompt before reading how many
+ more. Would be nicer to prompt in the minibuffer...
+
+2005-09-14 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-presentation-expression): Remove handling of
+ cons presentation-ids.
+
+2005-09-13 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el (defcustom slime-ed-use-dedicated-frame ... vs defvar
+
+ (defcustom slime-when-complete-filename-expand: Use
+ comint-replace-by-expanded-filename instead of
+ comint-dynamic-complete-as-filename to complete file names
+
+ * swank.lisp (run-repl-eval-hooks .. finally (return vs no return
+
+ inspector-call-nth-action Allow second value :replace for inspector actions
+
+ (defvar *slime-inspect-contents-limit* default nil. How many elements of
+ a hash table or array to show by default. If table has more than
+ this then offer actions to view more. Set to nil for no limit. Probably should
+ set default to reasonable value - I like 200.
+
+ (inspect-for-emacs ((ht hash-table) inspector)) - banner line is hash table object.
+ Respect *slime-inspect-contents-limit*
+
+ (defmethod inspect-for-emacs ((array array) inspector)
+ Respect *slime-inspect-contents-limit*
+
+ * swank-openmcl.lisp inspector for closures shows closed-over
+ values. To be fixed: inspector-princ needs to be loaded earlier
+ since swank package not available when compiling
+
+2005-09-13 Helmut Eller <heller at common-lisp.net>
+
+ * present.lisp (menu-choices-for-presentation-id): Use
+ lookup-presented-object secondary return value instead of
+ *not-present*.
+ (execute-menu-choice-for-presentation-id, presenting-object-1):
+ Remove references to *can-print-presentation*.
+
+ * slime.el (slime-current-output-id): Remove this ugly klugde.
+ (slime-repl-insert-result): New function. Handle the presentations
+ and other special cases cleaner.
+ (slime-repl-insert-prompt): Use it. The `result' arg is now a
+ structured list; update callers accordingly.
+ (slime-repl-return): Make the prefix arg work again.
+ (package-updating): The result of swank::listener-eval changed a
+ bit. Update the test.
+
+ Remove some unnecessary uses of `defun*' and reindent it to 80
+ columns.
+
+ * swank.lisp: Simplify the object <-> presentation-id mapping.
+ (save-presented-object): Remove the optional `id' arg.
+ (lookup-presented-object): Id should be a fixnum not some cons
+ with fuzzy/non-documented meaning. Use the secondary return value
+ to test for absence of the id. Update callers accordingly.
+ (*not-present*): Deleted.
+
+ Remove the repl result special cases, let the general presentation
+ machinery handle it.
+ (*last-repl-result-id*, add-repl-result, *current-id*)
+ (clear-last-repl-result): Deleted.
+ (listener-eval): Don't *current-id* to tag result values.
+
+ (*can-print-presentation*): Deleted. Nobody quite knows whether
+ it's still needed so let just try without it. Updated referrers
+ accordingly.
+
+ (eval-region, run-repl-eval-hooks): Move the eval hook stuff to
+ a separate function.
+
+ * swank-loader.lisp (lisp-version-string)[cmu]: Replace spaces
+ with underscores.
+
+2005-09-12 NIIMI Satoshi <sa2c at sa2c.net>
+
+ * swank.lisp, slime.el, swank-clisp.lisp, swank-sbcl.lisp: add
+ EUC-JP as coding system. This patch eliminates the requirement of
+ Mule-UCS to use Japanese characters. (Nice for pre-22 Emacs
+ users.)
+
+2005-09-10 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-enable-evaluate-in-emacs): Resurrected.
+ (slime-dispatch-event): Respect slime-enable-evaluate-in-emacs for
+ messages :eval-no-wait and :eval.
+
+2005-09-09 Alan Ruttenberg <alanr-l at mumble.net>
+ * slime.el (slime-choose-overlay-region). Don't try to overlay a
+ note if location is nil.
+
+2005-09-08 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * bridge.el Fix bug in bridge filter where a bridge message which
+ straddled a packet would be mishandled. Sometimes this would
+ result in spurious bridge message text being inserted with the
+ presentation and the presentation not being sensitive. In other
+ cases there would be an actual error. Introduce bridge-leftovers
+ to save the last, unfinished bit for the next call, and prepend it
+ before processing a chuunk. Also, fix the parentheses so that the
+ unwind protect cleanup forms are actually in the cleanup section.
+ In openmcl, where apparently communication with slime is done in
+ 2k chunks, you can trigger the bug with something like this:
+ (swank::presenting-object 'foo t
+ (dotimes (i 2040) (write-char #\:)))
+
+ * swank-openmcl.lisp (handle-compiler-warning). Don't create a
+ location if the condition doesn't have a filename. If it does,
+ make sure you pass a string rather than a pathname object
+ otherwise you get a net-read error
+
+2005-09-07 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * present.lisp (menu-choices-for-presentation): The
+ Inspect/Describe/Copy items are now provided from the Emacs side.
+ Implement all pathname menu items without having Emacs evaluate a
+ form. Fix for Lisps where ".lisp" is parsed as :name ".lisp".
+
+ * slime.el (slime-menu-choices-for-presentation): New function,
+ return a menu with Inspect/Describe/Copy plus the items that come
+ from the menu protocol.
+ (slime-presentation-menu): Security improvement for the
+ presentation menu protocol: Don't eval arbitrary forms coming from
+ the Lisp. Minor cleanup: Use x-popup-menu in the normal Emacs way,
+ associating a command with each menu item.
+
+2005-09-05 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp (background-message): New function. Forward the
+ call to the front end.
+ (pre-gc-hook, post-gc-hook): Use it.
+ (swank-sym, sending-safe-p): Deleted.
+
+ * swank.lisp (y-or-n-p-in-emacs): Simplify arglist.
+ (evaluate-in-emacs, dispatch-event, send-to-socket-io): Remove
+ evaluate-in-emacs stuff.
+ (to-string): Undo last change. to-string is not to supposed to
+ ignore errors. Bind *print-readably* instead.
+ (background-message): New function.
+ (symbol-external-p): Simplify it a little.
+
+ * slime.el (slime-setup-command-hooks): Add after-change-functions
+ only if presentations are enabled.
+ (slime-dispatch-event, slime-enable-evaluate-in-emacs)
+ (evaluate-in-emacs): Remove evaluate-in-emacs stuff. It was not
+ used and redundant.
+ (slime-save-some-lisp-buffers): Renamed from
+ save-some-lisp-buffers.
+ (slime-choose-overlay-region): Ignore :source-form locations.
+ (slime-choose-overlay-for-sexp): Ignore errors when stepping over
+ forms.
+ (slime-search-method-location, slime-goto-location-position): Move
+ all this regexpery to its own function.
+ (slime-recenter-if-needed, slime-repl-return): Factor some
+ duplicated code into its own function.
+ (slime-presentation-bounds, slime-presentation-around-point)
+ (slime-presentation-around-or-before-point): Minor cleanups.
+
+2005-09-04 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-ensure-presentation-overlay): New.
+ (slime-add-presentation-properties): Don't add face, mouse-face,
+ keymap text properties. Call slime-ensure-presentation-overlay to
+ implement them via overlays.
+ (slime-remove-presentation-properties): Don't remove these text
+ properties. Delete the right overlay.
+ (slime-after-change-function): Add overlays for presentations if
+ necessary.
+ (slime-copy-presentation-at-point): Don't add face text property.
+ (slime-repl-grab-old-output): Likewise.
+
+2005-08-31 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (to-string): Handle errors during printing of objects.
+
+2005-08-30 Alan Ruttenberg <alanr-l at mumble.net>
+ * slime.el (slime-mark-presentation-start/end-handler) modify
+ regexp to recognize negative presentation ids to make
+ presenting-object work with bridge mode.
+
+2005-08-30 Luke Gorrie <luke at synap.se>
+
+ * present.lisp: Added public domain dedication (OK'd by Alanr and
+ Matthias on the list).
+
+2005-08-29 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-lispworks.lisp (env-internals:confirm-p): Use new function
+ y-or-n-p-in-emacs rather than eval-in-emacs.
+
+ * swank-cmucl.lisp (eval-in-emacs): Removed.
+ (send-to-emacs): New.
+ (pre-gc-hook, post-gc-hook): Use new protocol message
+ :background-message rather than eval-in-emacs.
+
+ * swank.lisp (dispatch-event, send-to-socket-io): Handle new
+ messages :y-or-n-p, :background-message.
+ (y-or-n-p-in-emacs): New function.
+
+ * slime.el (slime-dispatch-event): Handle new messages :y-or-n-p,
+ :background-message.
+ (slime-y-or-n-p): New.
+
+2005-08-29 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el (sldb-insert-condition) - Add tooltip for long
+ condition string which otherwise falls off the right of the screen
+ * swank.lisp (list-threads) - thread name might be a symbol - pass
+ the symbol name when that happens
+
+2005-08-29 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp (make-weak-key-hash-table): Remove the
+ implementation; SBCL doesn't actually support weak hash-tables.
+
+2005-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-repl-kill-input): New command.
+ (slime-repl-mode-map): Bind it to C-c C-u, like in comint.
+ (slime-repl-easy-menu): Include it in the REPL menu.
+ (slime-repl-mode-hook): Show the SLIME menu in the REPL too.
+
+ * swank-backend.lisp (make-weak-key-hash-table)
+ (make-weak-value-hash-table): New interfaces.
+ * swank-cmucl.lisp (make-weak-key-hash-table): Implement it.
+ * swank-sbcl.lisp (make-weak-key-hash-table): Implement it.
+ * swank-openmcl.lisp (make-weak-key-hash-table)
+ (make-weak-value-hash-table): Implement it.
+
+ * swank.lisp (*object-to-presentation-id*)
+ (*presentation-id-to-object*): Use new functions
+ make-weak-key-hash-table, make-weak-value-hash-table.
+
+ * slime.el (slime-enable-evaluate-in-emacs): New variable.
+ (evaluate-in-emacs): Security improvement: If
+ slime-enable-evaluate-in-emacs is nil (the default), don't
+ evaluate forms sent by the Lisp.
+
+ * swank.lisp (send-to-socket-io): Handle :evaluate-in-emacs.
+
+2005-08-27 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-presentation-menu): When an object is no longer
+ recorded, remove text properties from the presentation.
+
+2005-08-15 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-openmcl.lisp (condition-source-position)
+ ccl::compiler-warning-stream-position is sometimes nil, so placate
+ this function by making it (or .. 0). Wrong but I don't have
+ enough time now to figure out what the right thing is.
+
+
+2005-08-24 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (fuzzy-find-matching-symbols): When completing the
+ string "package:" present a list of all the external symbols in
+ package (completing "package::" lists internal symbols as well).
+ (inspect-for-emacs standard-class): List all the slots in the
+ class (as per standard-object). The previous method of hard coding
+ the slots in the inspector's code made inspecting custom
+ meta-classes useless.
+
+2005-08-24 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank-sbcl.lisp (method-definitions): present qualifiers (if
+ any).
+
+2005-08-23 Taylor R. Campbell <campbell at bloodandcoffee.net>
+
+ * slime.el (slime-goto-location-position): Added a second regexp
+ for the :function-name case which matches "(def... ((function-name
+ ..." (with N opening parens preceding the function name). This is
+ to allow scheme48 style function names and definitions.
+
+2005-08-22 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp (fspec-pathname): Cope with CVS CLISP's
+ (documentation symbol 'sys::file) returning a list. Return either
+ a list of start and end line positions or nil as second value.
+ (fspec-location): Use it. Also, if we have to guess the name of a
+ source file make sure that it actually exists.
+
+ (with-blocked-signals, call-without-interrupts): Don't add
+ :linux to *features* since this changes the return value of
+ unique-directory-name in swank-loader.lisp.
+ Comment out with-blocked-signals.
+
+ Update some comments at the top of the file.
+ State the licence in the same terms as slime.el does.
+
+2005-08-21 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * present.lisp (menu-choices-for-presentation-id): Check against
+ the gensym in *not-present* instead of :non-present.
+
+2005-08-20 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank-sbcl.lisp (preferred-communication-style): guard against
+ non-Linux non-linkage-table platforms (and assume that they won't
+ have dodgy threads) with #+linux.
+
+2005-08-20 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Enable nested presentations.
+
+ * slime.el (slime-presentation): Remove slots start-p, stop-p.
+ (slime-add-presentation-properties): Use a new text property
+ layout. Also add an overlay to enable nested highlighting.
+ (slime-remove-presentation-properties): New.
+ (slime-presentation-whole-p): Changed interface.
+ (slime-presentations-around-point): New.
+ (slime-same-presentation-p): Removed.
+ (slime-presentation-start-p, slime-presentation-stop-p): New.
+ (slime-presentation-start, slime-presentation-end): Changed to use
+ new text property layout.
+ (slime-presentation-bounds): New.
+ (slime-presentation-around-point): Reimplemented to handle nested
+ presentations.
+ (slime-for-each-presentation-in-region): New.
+ (slime-after-change-function): Use
+ slime-remove-presentation-properties and
+ slime-for-each-presentation-in-region.
+ (slime-copy-presentation-at-point): Complain if no presentation.
+ (slime-repl-insert-prompt): Don't put rear-nonsticky text property.
+ (slime-reify-old-output): Handle nested presentations.
+ (slime-repl-return): Use slime-presentation-around-or-before-point.
+
+ Enable reification of presentations in non-REPL buffers.
+
+ * slime.el (slime-buffer-substring-with-reified-output): New,
+ factored out from slime-repl-current-input.
+ (slime-repl-current-input): Use it here.
+ (slime-last-expression): Use it here.
+
+ (slime-add-presentation-properties): Add text properties
+ modification-hooks et al. to enable self-destruction of incomplete
+ or edited presentations in non-REPL buffers.
+
+2005-08-15 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el (slime-goto-location-position) fix so the :method locator
+ regexp so that it can find eql specializers, (setf foo) methods, and to
+ allow (a single) newline between arguments in the arglist.
+
+ * swank-openmcl.lisp (specializer-name) patch from Gary Byers and
+ Bryan O'Conner to fix complaint about certain classes slipping
+ through the etypecase
+
+2005-08-14 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-mark-presentation-end): Really remove the
+ presentation-start entry from the hash table.
+
+ Merge some code from present.lisp, removing code duplication.
+ Minor code clean-up.
+
+ * swank.lisp (*object-to-presentation-id*)
+ (*presentation-id-to-object*, clear-presentation-tables)
+ (*presentation-counter*, lookup-presented-object): Move here from
+ present.lisp.
+ (save-presented-object): Likewise. Assign negative numbers only,
+ so as not to clash with continuation ids.
+
+ * swank.lisp (*repl-results*): Removed.
+
+ * swank.lisp (get-repl-result, clear-repl-results): Use new
+ implementations from present.lisp.
+ (add-repl-result): Likewise, don't take the negative of the id.
+ (*last-repl-result-id*): New variable.
+ (clear-last-repl-result): Use it here.
+
+ * slime.el (slime-repl-insert-prompt): Don't take the negative of
+ the id.
+ (slime-presentation-expression): New, take care to handle
+ arbitrary *read-base* settings.
+ (reify-old-output): Use it here.
+ (slime-read-object): Use it here.
+
+2005-08-12 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (substring-no-properties): Fix to handle non-zero start
+ argument correctly.
+
+ Patch to remove use of the slime-repl-old-output text property in
+ favor of the slime-repl-presentation text property, in order to
+ simplify the code.
+
+ * slime.el (slime-presentation-whole-p): Generalize to work with
+ strings too.
+ (slime-presentation-start, slime-presentation-end): Likewise.
+ (slime-presentation-around-point): Likewise.
+ (slime-presentation-around-or-before-point): New.
+
+ * slime.el (reify-old-output): Use slime-repl-presentation
+ property and slime-presentation-around-point function rather than
+ slime-repl-old-output property.
+ (slime-repl-return): Use slime-repl-presentation rather than
+ slime-repl-old-output.
+ (slime-repl-grab-old-output): Use
+ slime-presentation-around-or-before-point.
+ (slime-read-object): Use slime-presentation-around-point.
+
+ * slime.el (toplevel): Don't handle slime-repl-old-output text
+ property.
+ (slime-add-presentation-properties): Likewise.
+ (slime-after-change-function): Likewise.
+
+2005-08-12 Yaroslav Kavenchuk <kavenchuk at jenty.by>
+
+ * swank-clisp.lisp (fspec-pathname): Use the documentation
+ function instead of accessing clisp internals.
+
+2005-08-11 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp (transpose-lists): Fixed it.
+
+2005-08-10 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el move slime-repl-add-to-input-history to
+ slime-repl-send-input so we can see the presentations we copied to
+ input when we reuse history rather than #.(blah...)
+ [Thanks Matthias! - was very busy and just returned to see your
+ changes merged. Most excellent.]
+
+2005-08-10 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-presentation-around-point): Change interface,
+ return presentation as primary return value.
+ (slime-copy-presentation-at-point): Use
+ slime-presentation-around-point. Copying now also works when the
+ first character is clicked and when the REPL buffer is not current.
+ (slime-presentation-menu): Use slime-presentation-around-point.
+
+2005-08-10 Martin Simmons <martin at lispworks.com>
+
+ * swank-lispworks.lisp (defadvice compile-file): Return all values
+ from the real compile-file.
+
+2005-08-10 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp (transpose-lists): Replaced with much nicer function
+ by Helmut Eller.
+
+2005-08-09 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-read-object): Handle ids that are conses.
+ Patch by "Thas" on #lisp.
+
+2005-08-09 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp (transpose-lists): Reimplemented without APPLY so we
+ don't have problems with CALL-ARGUMENTS-LIMIT.
+
+2005-08-08 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (undo-in-progress): Define for XEmacs compatibility.
+ Reported by Friedrich Dominicus.
+
+2005-08-07 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Fix for the presentations menu. Reported by Aleksandar Bakic.
+
+ * present.lisp (lookup-presented-object): Handle ids that are
+ conses.
+ (execute-menu-choice-for-presentation-id): Use equal for comparing
+ ids, to handle the cons case.
+ (menu-choices-for-presentation): Quote the presentation id, as it
+ can be a cons.
+ * slime.el (slime-presentation-menu, slime-presentation-menu)
+ (slime-inspect-presented-object): Quote the presentation id.
+
+2005-08-06 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (form-completion): New generic function, factored out
+ from complete-form.
+ (complete-form): Factor out form-completion.
+ (form-completion): Specialize on defmethod forms to insert arglist
+ of generic function.
+
+ * doc/slime.texi (Programming Helpers): Document C-c C-s,
+ slime-complete-form.
+
+2005-08-04 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Improvements to the presentations feature. Parts of presentations
+ can be copied reliably using all available Emacs facilities (not
+ just kill-ring-save), and they are no longer "semi-readonly" (in
+ the sense that keypresses are silently ignored). Whenever a user
+ attempts to edit a presentation, it now simply turns into plain
+ text (which is indicated by changing the face); this can be
+ undone. Presentations are now also supported if
+ *use-dedicated-output-stream* is nil. It is now possible to
+ access the individual values of multiple-value results. For some
+ systems (Allegro CL and upcoming CMUCL snapshots), presentations
+ can be reliably printed through pretty-printing streams.
+
+ * present.lisp (slime-stream-p) [allegro]: Allow printing
+ presentations through pretty printing streams.
+ [cmu]: Allow printing presentations through pretty printing
+ streams, if CMUCL has annotations support and we are using the
+ bridge-less protocol.
+ [sbcl]: Allow printing presentations through indenting streams.
+
+ * present.lisp (write-annotation): New function.
+ (presentation-record): New structure.
+ (presentation-start, presentation-end): New functions, supporting
+ both bridge protocol and bridge-less protocol.
+ (presenting-object-1): Use them here.
+
+ * present.lisp [sbcl, allegro]: Add printer hooks for unreadable
+ objects and pathnames.
+
+ * swank.lisp (*can-print-presentation*): New variable, moved here
+ from present.lisp.
+ * swank.lisp (interactive-eval, listener-eval, backtrace)
+ (swank-compiler, compile-file-for-emacs, load-file)
+ (init-inspector): Bind *can-print-presentation* to an appropriate
+ value.
+ * present.lisp: Remove code duplication with swank.lisp for the
+ functions above.
+
+ * swank.lisp (encode-message): Don't use the pretty printer for
+ printing the message length.
+
+ * slime.el (slime-dispatch-event): New events :presentation-start,
+ :presentation-end for bridge-less presentation markup.
+ * swank.lisp (dispatch-event, send-to-socket-io): Likewise.
+
+ * swank.lisp (listener-eval): Store the whole values-list with
+ add-repl-result.
+ * slime.el (slime-repl-insert-prompt): Accept a list of strings,
+ representing individual values of a multiple-value result. Mark
+ them up as separate presentations.
+ (reify-old-output): Support reifying individual values of a
+ multiple-value result.
+
+ * slime.el (slime-pre-command-hook): Don't call
+ slime-presentation-command-hook.
+ (slime-post-command-hook): Don't call
+ slime-presentation-post-command-hook.
+ (slime-presentation-command-hook): Removed.
+ (slime-presentation-post-command-hook): Removed.
+
+ * slime.el (slime-presentation-whole-p): New.
+ (slime-same-presentation-p): New.
+ (slime-presentation-start, slime-presentation-end): New.
+ (slime-presentation-around-point): New.
+ (slime-after-change-function): New.
+ (slime-setup-command-hooks): Install slime-after-change-function
+ as an after-change-function.
+
+ * slime.el (slime-repl-enable-presentations): Make
+ slime-repl-presentation nonsticky.
+ (slime-mark-presentation-start, slime-mark-presentation-end): New
+ functions.
+ (slime-mark-presentation-start-handler): Renamed from
+ slime-mark-presentation-start.
+ (slime-mark-presentation-end-handler): Renamed from
+ slime-mark-presentation-end.
+ (slime-presentation): New structure.
+ (slime-add-presentation-properties): New function.
+ (slime-insert-presentation): New function.
+
+2005-08-03 Zach Beane <xach at gwi.net>
+
+ * swank-sbcl.lisp (swank-compile-string): Restore honoring of
+ *trap-load-time-warnings*.
+
+2005-08-03 Juho Snellman <jsnell at iki.fi>
+
+ * swank-sbcl.lisp: Remove SBCL 0.9.1 support.
+ (swank-compile-string): Funcall the compiled function outside
+ with-compilation-hooks to prevent runtime warnings from
+ popping up a *compiler-notes* buffer.
+
+2005-07-29 Marco Baringer <mb at bese.it>
+
+ * doc/slime.texi (Other configurables): Document
+ *dedicated-output-stream-port*.
+
+ * swank.lisp (*dedicated-output-stream-port*): New variable.
+ (open-dedicated-output-stream): Open the stream on the port
+ *dedicated-output-stream-port*.
+
+ * slime.el (slime-set-default-directory): Fix typo in doc string.
+
+2005-07-26 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank.lisp (inspect-for-emacs): Don't make whitespace
+ surrounding :action buttons part of the highlighted region.
+
+ * slime.el (slime-goto-location-buffer): Put "SLIME Source Form"
+ buffer into Lisp mode.
+
+2005-07-26 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (compile-file-for-emacs): Accept optional
+ external-format arg. I frogot to commit this file on 2005-07-05.
+
+ * slime.el (slime-input-complete-p): Skip over strings too.
+
+2005-07-26 Zach Beane <xach at xach.com>
+
+ * swank-sbcl.lisp (swank-compile-string): Revert to old string
+ compilation behavior to fix compiler note annotations. Code from
+ Juho Snellman.
+
+2005-07-24 Tom Pierce <tlpierce at gmail.com>
+
+ * swank.lisp (format-iso8601-time): New functions. Properly
+ formats a universal-time as an iso8601 string.
+ (inspect-for-emacs integer): Use the new
+ format-iso8601 function when printing an integer as a date.
+
+2005-07-22 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp (frame-catch-tags): Remove some debugging
+ forms which were "polluting" the repl buffer when viewing an sldb
+ buffer.
+ (function-source-location): Make :error messages have the proper
+ form (exactly one string argument). This fix also removes the
+ issues with sending unreadble lists (containing #<...> to emacs).
+
+2005-07-14 Helmut Eller <heller at common-lisp.net>
+
+ * swank-allegro.lisp (find-external-format): Fix typo.
+
+2005-07-06 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-send-sigint): Use the symbol SIGINT stead of the
+ signal number. Suggested by Joerg Hoehle.
+ (slime-compile-file): XEmacs needs the buffer as argument to
+ local-variable-p. Reported by Andy Sloane.
+
+2005-07-05 Helmut Eller <heller at common-lisp.net>
+
+ The file variable slime-coding can now be used to specify the
+ coding system to use for C-c C-k. E.g., if the file contains
+ -*- slime-coding: utf-8-unix -*- Emacs will tell the Lisp side
+ to call COMPILE-FILE with an external-format argument.
+
+ * slime.el (slime-compile-file): Send the coding system if
+ the buffer local variable `slime-coding' is bound.
+
+ * swank-backend.lisp, swank-sbcl.lisp, swank-clisp.lisp,
+ swank-lispworks.lisp, swank-cmucl, swank-allegro.lisp,
+ swank-abcl.lisp, swank-corman.lisp
+ (swank-compile-file): New optional argument `external-format'.
+
+ * swank-clisp.lisp (getpid): Undo the last change.
+
+ * swank-corman.lisp (spawn, thread-alive-p): More thread tweaking.
+
+2005-07-03 Joerg Hoehle <hoehle at users.sourceforge.net>
+
+ * swank-clisp (describe-symbol-for-emacs): Report :setf and :type
+ where appropriate.
+
+2005-07-03 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (next-single-char-property-change)
+ (previous-single-char-property-change) [xemacs]: Only define them
+ if not present.
+ (next-char-property-change, previous-char-property-change): Define
+ if needed.
+
+ * README: Show examples for the filenames instead of the general
+ "/the/path/to/this/directory". Suggested by Brandon J. Van Every.
+
+ * swank-corman.lisp (default-directory): Return a namestring
+ instead of the pathname.
+ (inspect-for-emacs, inspect-structure): Teach the inspector how to
+ deal with structures.
+ (spawn, send, receive): Implement rudimentary threading support.
+ It's now possible to connect with the :spawn communication style
+ and to bring up a listener. Unfortunately, debugging the
+ non-primary threads doesn't work at all. Still no support for
+ interrupt-thread.
+
+ * slime.el (slime-start-swank-server): Send an extra newline
+ before the "(swank:start-server ...". I don't know why, but this
+ seems to fix the problem when starting CLISP/Win32. Interrupting
+ CLISP/W32 is still horribly broken.
+
+ * swank-loader.lisp (compile-files-if-needed-serially) [corman]:
+ force-output after each file.
+
+2005-07-02 Marco Baringer <mb at bese.it>
+
+ * slime.el (save-some-lisp-buffers): New Function.
+ (slime-repl-only-save-lisp-buffers): New customizable variable.
+ (slime-repl-compile-and-load): Use save-some-lisp-buffers.
+ (slime-oos): Use save-some-lisp-buffers.
+
+2005-07-01 Gábor Melis <mega at hotpop.com>
+
+ * swank-sbcl.lisp (threaded stuff): make SBCL 0.9.2.9+ work while
+ retaining support for 0.9.2
+
+2005-06-28 Gábor Melis <mega at hotpop.com>
+
+ * swank-sbcl.lisp (threaded stuff): horrible hack to make threaded
+ SBCL 0.9.2 work. (also, Happy Birthday Christophe!)
+
+2005-06-21 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp (find-matching-packages): Also use nicknames.
+
+2005-06-13 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp (list-all-systems-in-central-registry): Delete
+ duplicates.
+
+ * swank-lispworks.lisp (unmangle-unfun): If you rename a package
+ you should rename it everywhere...
+
+2005-06-12 Alexey Dejneka <adejneka at comail.ru>
+
+ * slime.el (slime-with-xref-buffer): fix "pgk" typo.
+
+2005-06-12 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank.lisp (ed-in-emacs): allow strings as well as pathnames;
+ don't call emacs for things that the emacs editor doesn't know how
+ to deal with. Return T if we called emacs and NIL if not.
+
+ * slime.el (slime-ed): Change a listp to consp, so that NIL
+ arguments are correctly handled.
+
+2005-06-11 Nikodemus Siivola <nikodemus at random-state.net>
+
+ * swank-sbcl.lisp: Patched for SBCL HEAD: utilize the new
+ :source-plist functionality; maintain compatibility with 0.9.1
+ till 0.9.2 is out. Removed cruft left over from previous
+ excercises in supporting both HEAD and latest release.
+
+ * doc/slime.texi: Document Slime as supporting the latest official
+ release of SBCL, as opposed to a specific version number which
+ would need to be updated monthly.
+
+2005-06-10 Helmut Eller <heller at common-lisp.net>
+
+ * nregex.lisp (slime-nregex): Rename package to avoid name clashes
+ with other version of this file.
+
+ * swank.lisp (compiled-regex): Use the new package name.
+
+ * slime.el (slime-with-xref-buffer): Gensym package too, to avoid
+ problems when switching to buffers with -*- package: ... -*- file
+ variables. From Antonio Menezes Leitao.
+ (slime-property-bounds): Use the prop argument instead of the
+ hardcoded 'slime-repl-old-output. From Andras Simon.
+
+2005-06-07 Espen Wiborg <espenhw at grumblesmurf.org>
+
+ * swank-corman.lisp: Convert to Unix line-endings.
+ (create-socket): Pass through the port argument unmodified,
+ gettting a random port if 0. Requires supporting change in
+ <ccl>/modules/sockets.lisp.
+ (inspect-for-emacs): defimplementation instead of defmethod.
+
+2005-06-06 Espen Wiborg <espenhw at grumblesmurf.org>
+
+ * doc/slime.texi, PROBLEMS: Added notes about CCL.
+
+2005-06-03 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-background-activities-enabled-p): Allow
+ background stuff in repl-mode buffers too.
+
+ * swank-cmucl.lisp (sis/misc): Return t for :interactive-p.
+
+2005-06-01 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-load-system, slime-oos): Fix bug related to file
+ locking. Don't bind the variable system-name. system-name is a
+ predefined Emacs variable and is used among other things for lock
+ filenames.
+
+2005-06-01 Joerg Hoehle <hoehle at users.sourceforge.net>
+
+ * swank-clisp (getpid): Updates for current CLISP versions. Use
+ defimplementation. Define always (slime needs it).
+
+2005-06-01 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-background-activities-enabled-p): Return nil
+ instead of signalling an error if there is a open but no default
+ connection.
+ (slime-current-connection): New helper function.
+ (slime-connection): Use it.
+ (slime-first-change-hook): Only run when
+ slime-background-activities-enabled-p.
+
+2005-06-01 Joerg Hoehle <hoehle at users.sourceforge.net>
+
+ * swank-cmucl.lisp, swank-sbcl.lisp, swank-clisp.lisp
+ (describe-symbol-for-emacs): Distinguish macro and special
+ operators from functions.
+
+ * slime.el (slime-print-apropos): Must keep in sync with above,
+ therefore added :macro and :special-operator properties.
+
+ * swank.lisp (present-symbol-before-p): Make it conform to its
+ specification -- sort first by package and then by symbol name.
+
+ * swank-clisp.lisp (describe-symbol-for-emacs): Report :alien-type
+ when the name is known as foreign type.
+
+2005-06-01 Espen Wiborg <espenhw at grumblesmurf.org>
+
+ * swank-loader.lisp: Redefine compile-files-if-needed-serially for
+ Corman Lisp to load everything from source.
+
+2005-05-27 Espen Wiborg <espenhw at grumblesmurf.org>
+
+ * swank-corman.lisp: New file, swank for Corman Lisp.
+
+ * swank.lisp (simple-announce-function): force-output after
+ announcing.
+ (symbol-external-p): Be extra paranoid about the symbol's package;
+ find-symbol barfs on a nil package in Corman Lisp.
+
+ * swank-loader.lisp: Add Corman Lisp support.
+
+2005-05-24 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el text-property-default-nonsticky not defined in
+ xemacs. oops.
+
+2005-05-24 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el meta-w now removes properties before insertion if you
+ cut just a portion of the presentation. Added xemacs
+ support. Enabled in xemacs.
+
+2005-05-23 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el slime-presentation-menu - use with-current-buffer, so
+ that menus work even if you are not in the buffer with the
+ presentation.
+
+ * present.lisp More menu items for pathnames. Remember last
+ slime-stream-p value. *can-print-presentation* t during
+ swank-compiler and during presentation menu action.
+
+2005-05-22 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * present.lisp. (slime-stream-p) check if a stream is destined for
+ output in a slime listener. (checks *connections* looks into pretty-print
+ streams in openmcl and cmucl)
+ Don't present unless (slime-stream-p stream).
+
+ Variable *enable-presenting-readable-objects* The only readable object
+ which is presented are pathnames (e.g. pathnames printed when loading
+ and *load-verbose* is t). Try the useful menu :)
+ More to come if this doesn't cause problems. (nil this if it does)
+
+ *can-print-presentation* t around compile-string-for-emacs,
+ load-file, interactive-eval.
+
+ In cmucl, use fwrappers to modify behaviour rather than redefinition.
+
+2005-05-22 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * present.lisp. mouse-3 now gives a menu for actions on the
+ presentation. See documentation in file for information about how
+ to define menus. Also, disable presentations in inspector. Initial bits
+ of dealing with the possibility of presenting readable objects.
+
+ * slime.el support menu. Xemacs users beware this uses x-popup-menu,
+ which may be fsf specific.
+
+2005-05-20 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank.lisp make repl output presentation work even if
+ present.lisp not loaded
+
+2005-05-20 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-repl-enable-presentations): Default is enabled
+ in GNU Emacs but disabled in XEmacs. Feature is not portable yet.
+ Brutally 80-column'ified alanr's latest changes :-)
+
+2005-05-20 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * bridge.el new file. from ilisp cvs distribution to collect
+ in-band messages using process filter mechanisms. One edit which
+ calls bridge-insert with process argument as well as output
+
+ * present.lisp new file. Enough code to do the following:
+ (swank::presenting-object object stream (print "This is really
+ object")). This makes the string "This is really object" behave
+ like old repl input for the object. Sample code for openmcl and
+ cmucl that hooks this into the printing of unreadable objects This
+ should be part of swank.lisp (and lisp specific files) but I am
+ too chicken to merge yet. For now you have to load this file
+ manually.
+
+ * slime.el changes to support above:
+ slime-repl-enable-presentations: customize to enable this stuff.
+ Default value t. Set to nil to turn it off.
+ slime-presentation-start-to-point: map object ids to the (point)
+ where they start to print out. slime-mark-presentation-start,
+ slime-mark-presentation-end. handlers for the bridge messages.
+ slime-open-stream-to-lisp: When enabled start the bridge and
+ define the handlers.
+
+2005-05-19 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el slime-presentation-map
+
+2005-05-20 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (clear-repl-results): Fixed unbalanced parens. Thanks
+ Lawrence Mitchell.
+
+2005-05-19 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el (slime-presentation-command-hook) new function for
+ nicer behaviour for presentations.
+ (slime-pre-command-hook) do slime-presentation-command-hook
+ (slime-post-command-hook) put pre-command-hook back if goes away
+ (slime-copy-presentation-at-point) mouse-2 copies previous output to point
+ slime-repl-output-mouseover-face what the old output looks like when the mouse moves over it
+ default: box around it like on lispm
+ (slime-repl-insert-prompt) add mouseover face, mouse action. newline after output not propertized.
+ (slime-property-bounds) adjust for lack of propertized newline
+ to fix: presentation region behaviour should be attach to generic property like
+ (:acts-as-token t ) rather than tying to repl-output property
+
+2005-05-19 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (*record-repl-results*): Variable to enable/disable
+ recording of REPL results. True by default.
+ (*repl-results*): Renamed from ****.
+
+ * slime.el (slime-property-bounds): Factored out this common part
+ of slime-repl-grab-old-{input,output}.
+ (slime-read-object): Avoid inline CL code.
+
+2005-05-18 Antonio Menezes Leitao <aml at gia.ist.utl.pt>
+
+ * slime.el (slime-repl-inputed-output-face): new face.
+ (slime-current-output-id): New variable.
+ (slime-dispatch-event): Bind slime-current-output-id when
+ neccessary.
+ (slime-repl-insert-prompt): Add the neccessary text properties to
+ the result.
+ (reify-old-output): New function which makes sure swank sees
+ \(swank::get-**** ...) while the user sees the printed
+ representation of the object.
+ (slime-repl-return): When called on a old output (as per the
+ slime-repl-old-output text property, call
+ slime-repl-grab-old-output.
+ (slime-repl-send-input): Added the slime-repl-old-input text
+ property.
+ (slime-repl-grab-old-input): Keep the old input's text
+ properties (unwanted text properties are removed later).
+ (slime-repl-grab-old-output): New function.
+ (slime-repl-clear-buffer): Added call to swank::clear-****
+ (slime-repl-clear-output): Added call to swank::clear-**** and
+ bind inhibit-read-only to nil.
+ (slime-inspect): Call slime-read-object to get the value to
+ inspect.
+ (slime-read-object): New function which either reads an object
+ from the minibuffer or returns the object at point if it has the
+ slime-repl-old-output text property.
+
+ * swank.lisp (*current-id*, ****): New variables.
+ (add-****, get-****, clear-last-****, clear-****): New functions
+ for manipulating the repl history.
+ (listener-eval): Add * to ****.
+
+2005-05-12 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank.lisp Add ability to customize behavior of the repl. To do
+ so, add a function to the list swank::*slime-repl-eval-hooks*.
+ This function is passed the form typed into the repl. The function
+ should decide whether it wants to handle evaluation of the
+ form. If not, call (repl-eval-hook-pass) and the next hook is
+ tried. Otherwise the values the function returns are used instead
+ of calling eval. Inside the body of the function you can also
+ suppress having the repl print the result by calling
+ (repl-suppress-output) and/or suppress the advancement of the
+ history variables (*** ** * /// // /) by calling
+ (repl-suppress-advance-history).
+
+
+2005-05-11 Tim Daly Jr. <tim at tenkan.org>
+
+ * swank-source-path-parser.lisp (read-and-record-source-map):
+ Ensure that at least the toplevel form is in the source-map.
+
+2005-05-11 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-remove-old-overlays): Remove overlays in all
+ slime buffers not only in the current buffer.
+ (slime-filter-buffers): New helper.
+ (slime-display-completion-list): Take the completed prefix as
+ additional argument to initialize completion-base-size. This is
+ apparently needed to make mouse-selection working.
+ (slime-maybe-complete-as-filename): Factor for common code in
+ slime-complete-symbol* and slime-simple-complete-symbol.
+
+2005-05-06 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-openmcl.lisp specializer-name didn't handle
+ structure-class which caused meta-. of methods specialized on
+ defstruct arguments to fail.
+
+2005-05-06 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp (post-gc-hook): Include the elapsed time and
+ the size distribution.
+
+2005-05-05 Edi Weitz <edi at agharta.de>
+
+ * swank-lispworks.lisp (unmangle-unfun): New function to convert
+ strange symbols in SETF package to SETF function names.
+ (signal-undefined-functions): Use it.
+
+2005-05-04 Edi Weitz <edi at agharta.de>
+
+ * swank-lispworks.lisp (call-with-compilation-hooks): Provide
+ better implementation.
+ (compile-file-and-collect-notes): Advice for COMPILE-FILE so
+ pathname information for undefined functions can be recorded.
+ (*within-call-with-compilation-hooks*): New special variable used
+ by CALL-WITH-COMPILATION-HOOKS.
+ (*undefined-functions-hash*): New special variable to record
+ pathname information for undefined functions.
+ (signal-error-database): Make LOCATION parameter optional, use
+ FILENAME info from error database if not provided.
+ (signal-undefined-functions): Make LOCATION parameter optional,
+ use info from *UNDEFINED-FUNCTIONS-HASH* if not provided.
+
+2005-05-03 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (slime-secret): Removed #+unix conditional, suggested
+ by Edi Weitz.
+
+2005-05-02 Mark Wooding <mdw at nsict.org>
+
+ * swank.lisp: If ~/.slime-secret exists then insist that Emacs
+ sends the contents (as a password) during initial handshaking.
+ (announce-server-port): Use :IF-EXISTS :ERROR to prevent bad guys
+ from slipping a symlink into /tmp and reading what port Lisp is
+ listening on.
+
+ * slime.el: If ~/.slime-secret exists then send it, as per above.
+
+2005-05-01 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-inspector-reinspect): New function which
+ reinspects the current object.
+ (slime-inspector-mode-map): Bind slime-inspector-reinspect to g.
+
+2005-04-29 Dan Pierson <dlp at itasoftware.com>
+
+ * slime.el (slime-parse-context): Fix method parsing so that
+ pressing, say, C-c C-t when point is on a '-' in a symbol name
+ won't break.
+ (slime-browser-map): New variable. Add support for the common 'q'
+ keystroke to quit out of the xref.
+ (slime-fetch-browsable-xrefs): New function. Remove the (FLET ...)
+ entries which appear on at least CMUCL. I don't believe you can
+ actually expand them on any current implementation and they just
+ mess up the browse tree. Use only the method name when looking
+ up (METHOD ...) entries on CMUCL. This really shouldn't be here,
+ but I can't see how to avoid the error thrown by swank:xref.
+ (slime-expand-xrefs): Use it.
+ (slime-call-with-browser-setup): Initialize slime-buffer-package
+ properly. Previously, lisp-mode was called after setting it, but
+ lisp-mode clears all local variables, use lisp-mode-variables
+ instead.
+
+ * swank-cmucl.lisp (toggle-trace): Be more carefully when tracing
+ methods: try both (METHOD ...) and (PCL:FAST-METHOD ...).
+
+2005-04-27 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp (+header-type-symbols+): Drop the third arg to
+ apropos-list; it's no longer supported in recent CMUCLs.
+
+2005-04-21 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (arglist-to-string): Rolled back the previous change
+ because it interferred with values appearing in parameter lists.
+
+2005-04-20 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (arglist-to-string): Bind *PRINT-ESCAPE* to NIL. This
+ way symbols in arglists are printed as with PRINC, i.e. without
+ package qualifier.
+
+ * swank-sbcl.lisp (preferred-communication-style): Use
+ `linux_no_threads_p' alien variable to decide whether to use
+ :SPAWN. From dan_b for compatibility with new SBCLs.
+
+2005-04-19 Helmut Eller <heller at common-lisp.net>
+
+ * PROBLEMS: Warn about old kernels.
+
+ * swank-backend.lisp: Fix some typos.
+
+ * swank-sbcl.lisp (preferred-communication-style): Don't test for
+ sb-futex, it has lost its meaning in 0.8.21.
+
+2005-04-18 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (inferior-lisp-program): Defvar it here, in case it is
+ not defined in loaddefs and inf-lisp is not loaded. (That's the
+ case in XEmacs.)
+
+ * mkdist.sh: update version number.
+
+ * doc/slime.texi: Update version numbers for SBCL and ACL.
+
+2005-04-17 Peter Seibel <peter at gigamonkeys.com>
+
+ * swank-loader.lisp (*implementation-features*): Added features
+ for GCL and ECL ...
+ (lisp-version-string): ... and code to compute version
+ string. (Supplied by someone who's email I've misplaced.)
+
+2005-04-14 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-selector): Discard input after sleeping.
+
+2005-04-09 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (sldb-get-buffer): Create a fresh buffer if there's no
+ buffer for the connection (and don't reuse an existing buffer even
+ if it has a matching name).
+ (slime-buffer-visible-p, slime-ir1-expand): Delete unused
+ functions. Mark some others as unused, but leave them there
+ because they are potentially useful.
+
+ * swank.lisp (with-io-redirection, with-connection)
+ (with-buffer-syntax): Implement macros with `call-with' functions
+ to avoid some code bloat.
+ (call-with-connection, maybe-call-with-io-redirection)
+ (call-with-buffer-syntax): New functions.
+ (interactive-eval): Use from-string instead of read-from-string to
+ avoid problems whit *read-suppress*.
+
+ * swank-sbcl.lisp: Add a few comments.
+
+ * swank-abcl.lisp (print-frame): Trim whitespace to make the
+ backtrace look a bit terser.
+
+2005-04-07 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-net-coding-system): More fixes for
+ non-mule-XEmacsen.
+ (slime-net-coding-system): Even more fixes to make it for
+ mule-XEmacs.
+
+2005-04-05 Juergen Gmeiner <gj at gjdv.at>
+
+ * swank-lisworks.lisp (find-top-frame): If we can't find an
+ invoke-debugger frame we take any old frame at the top.
+
+2005-04-04 James McIlree <ovrskeek at mac.com>
+
+ * slime.el (find-coding-system, check-coding-system)
+ (process-coding-system, set-process-coding-system): Dummy
+ functions for no-mule-XEmacsen.
+
+2005-04-04 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-show-maximum-output): New
+ function. Immitate the scrolling behavior of a terminal.
+ (slime-with-output-end-mark, slime-repl-return)
+ (slime-repl-send-input, slime-display-output-buffer): Use it
+ (slime-lisp-implementation-version, slime-machine-instance): New
+ connection variables. Suggested by Eduardo Muñoz.
+ (slime-set-connection-info): Initialize them.
+
+ * swank.lisp (connection-info): Include version and hostname in
+ the result.
+
+ * swank-cmucl.lisp (breakpoint-values): Fixes for CMUCL-2005-03
+ snapshot.
+
+ * doc/slime.texi: Fix spelling errors.
+
+ * cl-indent.el: Remove the file. Let the Emacs developers
+ maintain it.
+
+2005-04-01 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (sldb-get-buffer): Initialize the buffer local
+ variables slime-buffer-connection and slime-current-thread when
+ creating a fresh buffer.
+
+ * swank.lisp (spawn-repl-thread): Use
+ *default-worker-thread-bindings* just like spawn-worker-thread.
+ (wrap-sldb-vars): New function. Rebind *sldb-level* to avoid
+ confusion with recursive errors during eval-in-frame.
+ (eval-string-in-frame, pprint-eval-string-in-frame): Use it.
+
+ * swank-allegro.lisp (eval-in-frame): Allegro's
+ eval-form-in-context does nothing special with lexical variables
+ in the frame. Wrap an explicit LET around the form to get similar
+ behavior as in the other Lisps.
+ (inspect-for-emacs (structure-object)): Remove structure related
+ methods. It's already covered by the general case with
+ allegro-inspect.
+ (common-seperated-spec): Deleted
+
+2005-04-01 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-xref-mode): Summarise the most important
+ bindings in the mode description.
+
+ * metering.lisp: Now supports only CLISP and OpenMCL.
+ Removed a lot of really ugly reader-conditionalized code, much of
+ it for archaic lisps (#+cltl2, #+lcl3.0, #+mcl1.3.2, etc).
+
+ * swank-source-path-parser.lisp (check-source-path): Signal an
+ error if a source path is malformed. SBCL sometimes gives (NIL).
+ (source-path-stream-position): Use it.
+
+ * slime.el (slime-goto-definition): Handle :error locations here
+ before any window/buffer changes are made.
+
+2005-04-01 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-keys): Bind slime-edit-definition-other-window
+ to `C-x 4 .' and slime-edit-definition-other-frame to `C-x 5 .',
+ shadowing the equivalent find-tag... bindings.
+ (slime-goto-definition): In the other-window and other-frame cases,
+ make sure point does not move in the originating window, even when
+ the definition is found in the same buffer.
+
+2005-03-31 Luke Gorrie <luke at synap.se>
+
+ * doc/slime.texi (slime-selector): New section.
+ (Inspector): Updated for the post-1.0 inspector.
+
+ * slime.el (slime-selector): Removed unneeded "the" prefixes in
+ descriptions of what the selector methods do.
+
+2005-03-27 Helmut Eller <heller at common-lisp.net>
+
+ * PROBLEMS, NEWS, doc/slime.texi: Some updates for the upcoming
+ release.
+
+2005-03-27 Russell McManus <russell_mcmanus at yahoo.com>
+
+ * swank-clisp.lisp (getpid): Try sys::process-id if
+ sys::program-id doesn't exist.
+
+2005-03-23 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (commit-edited-value): Read a backquated string,
+ instead of quating the result of read. This allows one to put
+ ,(form) into edit-value buffers.
+
+2005-03-22 Helmut Eller <heller at common-lisp.net>
+
+ * swank-lispworks.lisp (swank-compile-string): Bind *print-radix*
+ to t, to avoid problems if somebody uses different values for
+ *print-base* and *read-base*. Reported by Alain Picard.
+ (emacs-connected): Add default methods for
+ environment-display-notifier and environment-display-debugger.
+
+2005-03-21 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (locate-compiler-note): Handle errors in macros
+ better.
+ (source-file-source-location): Read the snippet at the right
+ position.
+
+ * swank-source-file-cache.lisp (read-snippet): Take the start
+ position as optional argument.
+
+2005-03-21 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (quit-lisp): If we are running multithreaded,
+ terminate all other threads too. (still broken in 0.8.20.27; used
+ to work in ~0.8.20.2.)
+ (with-debootstrapping, call-with-debootstrapping): Remove ugly
+ backward compatibility code.
+ (sbcl-source-file-p, guess-readtable-for-filename): New utilities.
+ (function-source-location): Handle work off to helper functions.
+ (find-function-source-location): New function. Use the
+ shebang-readtable for SBCL source files.
+ (function-source-position, function-source-filename)
+ (function-source-write-date, function-toplevel-form-number)
+ (function-hint-snippet, function-has-start-location-p)
+ (function-start-location): New helpers.
+ (safe-source-location-for-emacs): Don't catch errors if
+ *debug-definition-finding* is true.
+ (inspect-for-emacs): Minor beautifications.
+
+ * swank.lisp (commit-edited-value): Use buffer syntax.
+ (compile-file-for-emacs, compile-string-for-emacs): Bind
+ *compile-print* to nil.
+
+ * swank-cmucl.lisp (call-with-debugging-environment): Rebind
+ kernel:*current-level* 0. Useful for debugging pretty printer
+ code.
+ (inspect-for-emacs): Show details of interpreted functions.
+
+2005-03-21 Luke Gorrie <luke at synap.se>
+
+ * swank-sbcl.lisp (function-source-location): For definitions
+ compiled in Emacs buffers, include the :emacs-string as a :snippet
+ hint for search-based M-. lookup.
+
+2005-03-21 Edi Weitz <edi at agharta.de>
+
+ * swank-loader-lisp (*implementation-features*, *os-features*,
+ *architecture-features*): LispWorks was completely missing.
+
+2005-03-18 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-complete-symbol*-fancy): Now nil by default.
+
+2005-03-18 Helmut Eller <heller at common-lisp.net>
+
+ * swank-source-path-parser.lisp (make-source-recording-readtable):
+ Ignore non-ascii chars.
+
+ * swank-sbcl.lisp (swank-compile-string): Re-implemented. This
+ time with temp-files and proper source-location tracking.
+ (install-debug-source-patch, debug-source-for-info-advice): Patch
+ SBCL's debug-source-for-info so that we can dump our own bits of
+ debug info.
+ (function-source-location, code-location-source-path): Rewritten
+ to handle C-c C-c functions. Also use the source-path to locate
+ the position.
+ (locate-compiler-note): Renamed from resolve-note-location.
+ (temp-file-name, call/temp-file): New utilities.
+ (file-source-location, lisp-source-location)
+ (temp-file-source-location, source-file-source-location)
+ (string-source-position, code-location-debug-source-info)
+ (code-location-debug-source-name, code-location-debug-source-created,)
+ (code-location-debug-fun-fun, code-location-from-emacs-buffer-p)
+ (function-from-emacs-buffer-p, function-debug-source-info)
+ (info-from-emacs-buffer-p, code-location-has-debug-block-info-p)
+ (stream-source-position): Lots of new helper functions.
+ (with-debootstrapping): Moved upwards so that it can be used for
+ source location searching.
+ (source-location-for-emacs): Deleted
+
+2005-03-16 Helmut Eller <heller at common-lisp.net>
+
+ * slime/swank.lisp (*macroexpand-printer-bindings*): New user
+ variable.
+ (apply-macro-expander): Use it.
+ (call-with-bindings): Bind variables in reverse order. Thit makes
+ it easer to cons or push a new binding at the front the list.
+ (with-bindings): New macro.
+
+ * slime.el (slime-run-when-idle): New function to hide
+ Emacs/XEmacs differences.
+ (slime-process-available-input): Use it.
+
+ * swank-loader.lisp (unique-directory-name): Rewritten to avoid
+ the rather irritating warning that (warn "Don't know ...") is
+ unreachable.
+
+2005-03-13 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-dispatch-event): Use `slime-busy-p' to control
+ the "; pipelined request" message. This way it takes requests
+ blocked in the debugger into account and avoids spurious messages.
+
+ * swank.lisp (inspect-for-emacs symbol): Add an "unintern it"
+ action for symbols.
+
+ * swank-source-file-cache.lisp (read-snippet): Skip comments and
+ whitespace in SBCL. The source-positions reported by SBCL are not
+ adjusted to skip over whitespace before the definition.
+
+ * swank-sbcl.lisp (function-source-location): Updated for revised
+ sb-introspect patch:
+ s/DEFINITION-SOURCE-CREATED/DEFINITION-SOURCE-WRITE-DATE/
+
+ * swank-loader.lisp (*os-features*): Added :mswindows. Thanks Will
+ Glozer.
+
+2005-03-12 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-edit-value): New function on `C-c E'. Prompts
+ for a Lisp expression, evaluates and displays the result in a new
+ buffer for editing, and then setf's the edited value in Lisp after
+ you press C-c C-c. Usage example: `C-c E asdf:*central-registry*'
+ Minor docstring and pull-down-menu changes.
+
+ * swank.lisp (value-for-editing, commit-edited-value): New
+ functions for slime-edit-value.
+
+ * swank-allegro.lisp (toggle-trace): Fix from Antonio Menezes
+ Leitao.
+
+ * swank-sbcl.lisp: Use swank-source-file-cache to find snippets of
+ definitions. M-. is now much more robust to modifications in the
+ source file.
+ NOTE: To be effective requires a patch to sb-introspect that I
+ have posted to sbcl-devel.
+
+ * swank-source-file-cache.lisp: Factored this into its own file,
+ from swank-cmucl.lisp.
+
+ * swank-loader.lisp, swank-cmucl.lisp: Updated for the above.
+
+2005-03-10 Antonio Menezes Leitao <aml at gia.ist.utl.pt>
+
+ * slime.el (slime-toggle-trace-fdefinition): If there is no symbol
+ at point then prompt for one.
+
+2005-03-09 Peter Seibel <peter at gigamonkeys.com>
+
+ * swank-loader.lisp (*architecture-features*): Added :pc386 for CLISP.
+ (unique-directory-name): Change ERROR to WARN.
+
+ * slime.el (slime-register-lisp-implementation): Add facility for
+ registering lisp implementations with symbolic names that can be
+ passed to C-u M-x slime.
+
+2005-03-08 Peter Seibel <peter at gigamonkeys.com>
+
+ * doc/Makefile (clean): added clean and really_clean targets.
+ (all): and added slime.pdf to all prerequisites.
+
+ * swank-loader.lisp (*implementation-features*): Whoops. Forgot
+ CLISP.
+ (*architecture-features*): Added :x86-64 for SBCL on AMD64 (thanks
+ Vincent Arkesteijn)
+
+2005-03-07 Peter Seibel <peter at gigamonkeys.com>
+
+ * swank-loader.lisp (unique-directory-name): Replaced *lisp-name*
+ variable with more sophisticated version that accounts for impl,
+ impl version, os, and hardware architecture.
+
+2005-03-07 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp: Fixed parenthesis-balancing problem.
+
+2005-03-06 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-easy-menu): Add menu item for
+ slime-complete-form.
+
+ * swank.lisp (format-arglist-for-echo-area): Use extra-keywords to
+ enrich the list of keywords.
+ (arglist-to-string): Remove extraneous whitespace.
+ (keyword-arg, optional-arg): New structures.
+ (decode-keyword-arg, decode-optional-arg): Return structure
+ objects rather than multiple values.
+ (encode-keyword-arg, encode-optional-arg, encode-arglist): New
+ functions.
+ (arglist): New slot key-p.
+ (decode-arglist): Handle &whole, &environment. Store more
+ information on optional and keyword args, set arglist.key-p.
+ (values-equal?): Removed.
+ (print-decoded-arglist-as-template): If keyword is
+ not a keyword symbol, quote it in the template.
+ (extra-keywords): Return a secondary value (allow-other-keys).
+ For make-instance, try to finalize the class if it is not
+ finalized yet (fix for Allegro CL 6.2). If class is not
+ finalizable, use direct slots instead of slots and indicate that
+ the keywords are not complete.
+ (enrich-decoded-arglist-with-extra-keywords): New function, use
+ the secondary value of extra-keywords.
+ (arglist-for-insertion, complete-form): Use it here.
+ (remove-keywords-alist): New variable.
+ (remove-actual-args): When the keyword :test is provided, don't
+ suggest :test-not and vice versa.
+
+ * swank-backend.lisp (:swank-mop package): Export
+ finalize-inheritance.
+
+2005-03-06 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp: Export *LOG-OUTPUT*.
+
+2005-03-05 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-net-sentinel): Always print a message when the
+ lisp disconnects.
+ (slime-inferior-lisp): Don't display the buffer. Let callers do
+ that.
+ (slime): Display the inferior buffer here.
+ (slime-quit-lisp, slime-quit-sentinel): Use set a special sentinel
+ and do most of the cleanups there.
+ (slime-repl-sayoonara): Use slime-quit-lisp.
+ (slime-restart-inferior-lisp, slime-restart-inferior-lisp-aux)
+ (slime-restart-sentinel): Use a special sentinel to restart
+ processes.
+ (slime-hide-inferior-lisp-buffer): Do the windows arrangement a
+ bit differently. Related to restart-lisp.
+ (slime-repl-buffer): Take the connection as second optional
+ argument. Useful for rearranging windows for dead processes.
+
+ * swank-allegro.lisp (call-with-debugging-environment)
+ (find-topframe): Hide the first 2 frames. Those are created
+ by swank-internal functions.
+
+2005-03-04 Antonio Menezes Leitao <aml at gia.ist.utl.pt>
+
+ * swank-allegro.lisp (process-fspec-for-allegro, toggle-trace):
+ Handle setf functions.
+ (tracedp): Fix free variable.
+
+ * slime.el (slime-trace-query): The :defgeneric query was bogus.
+ (slime-extract-context): Don't skip over the method name if we are
+ already at the end of the name.
+
+2005-03-03 Nikodemus Siivola <tsiivola at cc.hut.fi>
+
+ * swank-sbcl.lisp: Fixed for latest SBCL HEAD revision and
+ temporarily backwards-compatible with the current release.
+
+2005-03-02 Marco Baringer <mb at bese.it>
+
+ * swank-loader.lisp Look for a file in the same directory as
+ swank-loader.lisp called site-init.lisp. If it exists we load that
+ instead of attempting to load ~/.swank.lisp.
+ (user-init-file): Superseded by load-user-init-file.
+ (load-user-init-file): New function.
+ (load-site-init-file): New function.
+
+2005-03-01 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-who-bindings): Bind who-specializes to C-c W a.
+ (slime-extract-context): Renamed from name-context-at-point.
+ (slime-beginning-of-list): Renamed from out-first.
+ (slime-slime-parse-toplevel-form): Renamed from definition-name.
+ (slime-arglist-specializers): Renamed from parameter-specializers.
+ (slime-toggle-trace-function, slime-toggle-trace-defgeneric)
+ (slime-toggle-trace-defmethod, slime-toggle-trace-maybe-wherein)
+ (slime-toggle-trace-within): Deleted. Everything is now handled
+ by slime-trace-query.
+ (slime-calls-who): For symmetry with silme-who-calls.
+ (slime-edit-definition-with-etags): Better intergration with TAGS.
+ (slime-edit-definition-fallback-function): Mention it in the
+ docstring.
+
+ * swank-backend (calls-who, toggle-trace): New functions.
+ (toggle-trace-function, toggle-trace-generic-function-methods,
+ (toggle-trace-method, toggle-trace-fdefinition-wherein): Replaced
+ by toggle-trace.
+
+ * swank.lisp (*sldb-printer-bindings*, *swank-pprint-bindings*):
+ New variables. The alists replace the variables which where
+ previously hidden with the define-printer-variables macro.
+ (define-printer-variables, with-printer-settings): Deleted,
+ because the variable names where not visible in the source code.
+ (swank-toggle-trace): Renamed from toggle-trace-fdefinition.
+
+ * swank-cmucl.lisp, swank-lispworks, swank-sbcl.lisp,
+ swank-allegro.lisp (toggle-trace): Update tracing code for new
+ interface.
+
+2005-02-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-dispatch-event): Add :eval-no-wait and :eval
+ events.
+ (slime-eval-for-lisp): New function.
+ (sldb-buffers): Delete the variable. Use buffer-list instead.
+
+ * swank.lisp: (eval-for-emacs): Use the new backend function
+ call-with-debugger-hook.
+ (eval-in-emacs): Cleaned up. Add support for synchronous RPCs.
+ (receive-eval-result): New function.
+ (dispatch-event, read-from-socket-io, send-to-socket-io): New
+ :eval event. Rename :%apply to :eval-no-wait.
+ (read-user-input-from-emacs, evaluate-in-emacs): Increment
+ *read-input-catch-tag* instead of re-binding it. Reduces the
+ danger of throwing to the wrong tag a bit.
+
+ * swank-backend.lisp (call-with-debugger-hook): New function.
+ Useful if the backend needs special incantations for BREAK.
+ (toggle-trace-function): Add a default implementation for simple
+ symbols.
+
+ * swank-lispworks.lisp (slime-env): New class.
+ (call-with-debugger-hook): Use env:with-environment to pop up our
+ debugger on a BREAK.
+ (toggle-trace-method, parse-fspec, tracedp, toggle-trace):
+ Implement method tracing.
+
+ * swank-sbcl.lisp (call-with-debugger-hook): Bind
+ sb-ext:*invoke-debugger-hook* instead of setting it in
+ emacs-connected.
+ (emacs-connected): Deleted.
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Reduce
+ verbosity by setting the :print argument for compile-file to nil.
+
+2005-02-23 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-startup-animation, slime-repl-update-banner):
+ Put the animation back in to keep the kids quiet.
+ (slime-kill-without-query-p): Change default to nil.
+ (slime-eval-describe, slime-eval-region)
+ (slime-pprint-eval-last-expression): Fix typos in docstrings.
+ (slime-eval/compile-defun-dwim): Deleted. We never had a key
+ binding anyway.
+
+2005-02-22 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-complete-form): Emacs 20 compatibility fix.
+ (slime-repl-update-banner): Remove animation stuff.
+ (slime-startup-animation): Deleted.
+
+ * swank-lispworks.lisp (compute-applicable-methods-using-classes):
+ Implement it.
+
+2005-02-20 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Supersede the command slime-insert-arglist with the new command
+ slime-complete-form and bind it to C-c C-s. The command completes
+ an incomplete form with a template for the missing arguments.
+ There is special code for discovering extra keywords of generic
+ functions and for handling make-instance. Examples:
+
+ (subseq "abc" <C-c C-s>
+ --inserts--> start [end])
+ (find 17 <C-c C-s>
+ --inserts--> sequence :from-end from-end :test test
+ :test-not test-not :start start :end end :key key)
+ (find 17 '(17 18 19) :test #'= <C-c C-s>
+ --inserts--> :from-end from-end
+ :test-not test-not :start start :end end :key key)
+ (defclass foo () ((bar :initarg :bar)))
+ (defmethod initialize-instance :after ((object foo) &key blub))
+ (make-instance 'foo <C-c C-s>
+ --inserts--> :bar bar :blub blub initargs...)
+
+ * swank.lisp (arglist): New struct for storing decoded arglists.
+ (decode-arglist): New function.
+ (arglist-keywords, methods-keywords, generic-function-keywords,
+ applicable-methods-keywords): New functions.
+ (decoded-arglist-to-template-string,
+ print-decoded-arglist-as-template): New functions.
+ (arglist-to-template-string): Rewrite using above functions.
+ (remove-actual-args): New function.
+ (complete-form): New slimefun.
+
+ * swank.lisp (extra-keywords): New generic function.
+
+ * swank-backend.lisp (:swank-mop package):
+ Export compute-applicable-methods-using-classes.
+
+ * swank.lisp (arglist-for-insertion): Use extra-keywords to
+ enrich the list of keywords.
+
+ * swank.lisp (valid-operator-symbol-p): New function.
+ (valid-operator-name-p): Use valid-operator-symbol-p.
+
+ * slime.el (slime-complete-form): New command.
+ (slime-keys): Bind C-c C-s to slime-complete-form rather than
+ slime-insert-arglist.
+
+2005-02-18 Antonio Menezes Leitao <aml at gia.ist.utl.pt>
+
+ Improve the trace mechanism (on lisps that support it). SLIME is
+ now able to trace/untrace flet/labels functions, methods and, of
+ course, regular and generic functions.
+
+ In the process support for sending code to emacs form the lisp was
+ added. The code, elisp forms, is sent over the wire like normal
+ lisp code, evaluated in emacs and the return value is returned
+ back to the lisp.
+
+ * slime.el (slime-dispatch-event): Added the :evaluale-in-emacs
+ dispatch state which simply parses the message and class
+ evaluate-in-emacs.
+ (evaluate-in-emacs): New function.
+ (complete-name-context-at-point, name-context-at-point, out-first,
+ definition-name, parameter-specializers,
+ slime-toggle-trace-fdefinition, slime-toggle-trace-function,
+ slime-toggle-trace-defgeneric, slime-toggle-trace-defmethod,
+ slime-toggle-trace-maybe-wherein, slime-toggle-trace-within): New
+ functions implementing the new intelligent slime trace.
+
+ * swank-backend.lisp (toggle-trace-function,
+ toggle-trace-generic-function-methods, toggle-trace-method,
+ toggle-trace-fdefinition-wherein,
+ toggle-trace-fdefinition-within): New backend functions
+ for the new trace facility.
+
+ * swank.lisp (dispatch-event): Handle the :evaluate-in-emacs
+ message type.
+ (evaluate-in-emacs): New function.
+
+ * swank-allegro.lisp (toggle-trace-generic-function-methods,
+ toggle-trace, toggle-trace-function, toggle-trace-method,
+ toggle-trace-fdefinition-wherein,
+ toggle-trace-fdefinition-within): Implement.
+ (process-fspec-for-allegro): New function.
+
+ * swank-cmucl.lisp (toggle-trace-generic-function-methods,
+ toggle-trace-function, toggle-trace-method,
+ toggle-trace-fdefinition-wherein): Implement.
+ (toggle-trace, process-fspec): New functions.
+
+ * swank-sbcl.lisp (toggle-trace-generic-function-methods,
+ toggle-trace-function, toggle-trace-method,
+ toggle-trace-fdefinition-wherein): Implement.
+ (toggle-trace, process-fspec): New functions.
+
+2005-02-02 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Require the timer package explicitly.
+
+2005-02-02 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-repl-send-input): Move some properties
+ of old REPL input (e.g. read-only) from text properties into an
+ overlay, so that kill/yank will leave them behind. Left
+ `slime-repl-old-input' as a text properties because it's more
+ convenient to lookup that way.
+ (slime-repl-return): Ignore `slime-repl-old-input' property if the
+ point is in front of the current REPL prompt, i.e. if the user has
+ copy&pasted some old REPL input into the current input area.
+
+2005-01-30 Bryan O'Connor <bryan-slime at lunch.org>
+
+ * slime.el (slime-goto-location-position): Changed the regexp to
+ require the function-name to be followed by a
+ non-symbol-constituent character \S_. Previously, a function-name
+ of "find" first matched find-if-not if it occured earlier in the
+ file.
+
+2005-01-27 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-busy-p): Ignore debugged continuations to enable
+ arglist lookup while debugging. Suggested by Lynn Quam.
+ (sldb-continuations): New buffer local variable in sldb buffers to
+ keep track of debugged continuations.
+ (sldb-debugged-continuations): New function.
+ (sldb-buffers): Renamed from sldb-remove-killed-buffers.
+ (slime-eval-print): New function to insert the stream output and
+ the result of an evaluation in the current buffer.
+ (slime-eval-print-last-expression): Use it.
+ (slime-interactive-eval): Use slime-eval-print when a prefix
+ argument was given.
+
+ * swank.lisp (*pending-continuations*, eval-in-emacs)
+ (debugger-info-for-emacs): Keep track of debugged continuation the
+ new variable *pending-continuations* and include the list of
+ active continuations in the debugger info for Emacs.
+ (eval-and-grab-output): New function. Used by slime-eval-print.
+ (*log-output*): Renamed from *log-io*. Use *standard-error* as
+ initial value instead of *terminal-io*. CMUCL opens its own tty
+ and that makes it hard to redirect to output with a shell.
+ *standard-error* writes its output to file descriptor 2.
+ (*canonical-package-nicknames*): Fix typo.
+
+2005-01-20 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (parse-symbol): Don't break if the package doesn't
+ exist. Reported by Lynn Quam.
+
+2005-01-20 Ian Eslick <eslick at csail.mit.edu>
+
+ * swank-allegro.lisp (restart-frame): Handle frames with arguments
+ better.
+
+2005-01-20 Edi Weitz <edi at agharta.de>
+
+ * swank-allegro.lisp (handle-undefined-functions-warning): Prevent
+ breakage if the undefined function is called at multiple
+ locations.
+
+2005-01-19 Helmut Eller <heller at common-lisp.net>
+
+ * swank-gray.lisp (stream-unread-char): If the char argument
+ doesn't match the contents in the buffer, ignore it and emit a
+ warning instead.
+
+2005-01-19 Utz-Uwe Haus <haus+slime at merkur.math.uni-magdeburg.de>
+
+ * swank-cmucl.lisp (breakpoint): Add a slot for return values to
+ make return values inspectable in the debugger.
+ (signal-breakpoint): Initialize the new slot.
+
+2005-01-19 Matthias Koeppe <mkoeppe at merkur.math.uni-magdeburg.de>
+
+ * slime.el (slime-insert-arglist): Inserts a template for a
+ function call instead of the plain arglist; this makes a
+ difference for functions with optional and keyword arguments.
+
+ * swank.lisp (arglist-to-template-string): New function.
+ (arglist-for-insertion): Use it
+ (decode-keyword-arg, decode-optional-arg): New functions.
+
+2005-01-19 Lars Magne Ingebrigtsen <larsi at gnus.org>
+
+ * slime.el (slime-header-line-p): Customize variable to
+ enable/disable the header-line in the REPL.
+
+2005-01-18 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-complete-symbol*-fancy): New variable to enable
+ extra bells and whistles with slime-complete-symbol*. Currently
+ controls whether to use arglists semantically. Default is t.
+ (slime-complete-symbol*-fancy-bit): Factored out this function.
+ Only do "semantic" completion when the symbol is in
+ function-position, avoid interning argument names in Emacs, and
+ don't display arglists if the minibuffer is active.
+
+2005-01-14 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-repl-send-input): Make old input read-only using
+ an overlay instead of a text property. This way if you copy&paste
+ the input elsewhere it will become editable (overlay is associated
+ with the buffer region and not the text).
+
+2005-01-14 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-complete-symbol*): Maybe insert closing
+ parenthesis or space (depending on arglist) after symbol
+ completion has finished. Optionally also show arglist.
+
+2005-01-13 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp (create-socket): The byte-order of the :host
+ argument for CREATE-INET-LISTENER was changed in the Jan 2005
+ snapshot. Test whether the symbol 'ext:socket-error exists to
+ decide if we are in a older version.
+ (resolve-hostname): Return the address in host byte-order.
+
+2005-01-12 Robert Lehr <bozzio at the-lehrs.com>
+
+ * slime.el (slime-changelog-date): Return nil if the ChangLog file
+ doesn't exits.
+ (slime-repl-update-banner): Write "ChangeLog file not found" if
+ the ChangeLog doesn't exist.
+
+2005-01-12 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime.el (slime-inspector-operate-on-click): New command for
+ inspecting the value value at the clicked-at position or invoking
+ an inspector action.
+ (slime-inspector-mode-map): Bind it to mouse-2.
+ (slime-inspector-insert-ispec): Add mouse-face properties for
+ clickable values and action buttons.
+
+2005-01-12 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*default-worker-thread-bindings*): New variable to
+ initialize dynamic variables in worker threads.
+ (spawn-worker-thread, call-with-bindings): New helper functions.
+ (thread-for-evaluation): Use them.
+
+2005-01-10 Utz-Uwe Haus <haus+slime at merkur.math.uni-magdeburg.de>
+
+ * swank-sbcl.lisp (profile-package): Add implementation for SBCL.
+
+2005-01-10 Eduardo Muñoz <emufer at terra.es>
+
+ * swank.lisp (inspect-for-emacs-list): LispWorks has a low args
+ limit for apply: use reduce instead of apply.
+
+2005-01-10 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-conservative-indentation): The default is now
+ nil. Suggested by Travis Cross.
+
+2005-01-10 Matthias Koeppe <mkoeppe at merkur.math.uni-magdeburg.de>
+
+ * slime.el (slime-inspector-next-inspectable-object): Accept a
+ prefix argument and make wrapping around more reliable. The code
+ is adapted from `widget-move'.
+ (slime-inspector-previous-inspectable-object): New command.
+ (slime-inspector-mode-map): Bind to S-TAB.
+
+2004-12-16 Martin Simmons <martin at xanalys.com>
+
+ * swank-lispworks.lisp (create-socket): Work around bug in
+ comm::create-tcp-socket-for-service on Mac OS LW 4.3.
+
+2004-12-16 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-complete-symbol*): Bind
+ comint-completion-addsuffix so unambiguous or exact completion
+ closes the string automatically.
+
+2004-12-16 Matthias Koeppe <mkoeppe at merkur.math.uni-magdeburg.de>
+
+ * slime.el (slime-keys): Bind M-* to
+ slime-pop-find-definition-stack for compatibility with standard
+ Emacs conventions.
+
+2004-12-16 Helmut Eller <heller at common-lisp.net>
+
+ * swank-source-path-parser.lisp (read-source-form): New function
+ which uses *read-suppress* properly. Common code from
+ source-path-stream-position and form-number-stream-position.
+ (source-path-stream-position): Use it.
+
+ * swank-cmucl.lisp (form-number-stream-position): Use
+ read-source-form.
+
+ * swank.lisp (frame-for-emacs): Print the frame number a little
+ nicer with ~2D.
+
+2004-12-15 Matthias Koeppe <mkoeppe at merkur.math.uni-magdeburg.de>
+
+ * slime.el (slime-lisp-modes): New variable to make C-c C-k
+ customizable and usable in scheme-mode.
+ (slime-compile-file): Use it.
+
+2004-12-15 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp, swank-backend.lisp (frame-package): Delete it.
+ Include the package name for local variables because it is utterly
+ confusing if `eval-in-frame' doesn't work due to missing package
+ prefixes.
+
+ * swank-source-path-parser.lisp (source-path-stream-position):
+ Bind *read-suppress* to nil before calling
+ read-and-record-source-map.
+
+ * swank-clisp.lisp (*buffer-name*, *buffer-offset*): Move
+ definitions upward before the first use.
+
+2004-12-15 Bryan O'Connor <bryan-slime at lunch.org>
+
+ * slime.el (slime-edit-definition): Switch to the other frame if
+ the `where' is 'frame.
+ (slime-edit-definition-other-frame): New function.
+
+2004-12-15 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-send-input): Make the input read-only to
+ avoid confusion.
+ (slime-make-region-read-only): New function.
+
+2004-12-13 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-mode-map): Bind <home> to slime-repl-bol.
+ Suggested by Chris Capel.
+ (slime-repl-grab-old-input): Remove the 'old-input text-property
+ from the copied text. Reported by Tim Oates.
+ (slime-repl-grab-old-input): Append the old input to the current
+ input by default. If the new `replace' argument is true, replace
+ the current input. Suggested by Antonio Menezes Leitao.
+ (slime-repl-return): Pass the prefix argument to
+ slime-repl-grab-old-input.
+
+2004-12-09 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (*sldb-print-pretty*, *sldb-print-circle*)
+ (*sldb-print-length*, *sldb-print-level*, *sldb-print-lines*)
+ (*sldb-print-pprint-dispatch*): Export those symbols.
+
+2004-12-05 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-global-variable-name-p): Also return true for
+ names of constants like +foo+. Suggested by Christian Lynbech.
+
+ * swank-allegro.lisp (handle-compiler-warning): Handle
+ undefined-functions warnings by looking the fromat-arguments of
+ the condition.
+ (compiler-undefined-functions-called-warning-p)
+ (location-for-warning, handle-undefined-functions-warning): New
+ functions.
+
+ * swank-cmucl.lisp (*install-gc-hooks*): New user variable.
+ (sending-safe-p): New predicate.
+ (pre-gc-hook, post-gc-hook): Use it.
+
+ * swank.lisp (eval-region): Use a simple loop.
+
+2004-12-02 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp: (inspect-for-emacs (symbol)): Handle non-interned
+ symbols.
+
+ * slime.el (slime-repl-clear-buffer, slime-repl-clear-output): Fix
+ docstrings.
+
+2004-11-29 Lynn Quam <quam at ai.sri.com>
+
+ * slime.el (slime-global-variable-name-p): Allow optional
+ "<package-name>:" or "<package-name>::".
+
+2004-11-29 Chris Capel <pdf23ds at gmail.com>
+
+ * swank.lisp (macro-indentation): Ignore &whole, &aux, and
+ &environment args.
+
+2004-11-29 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-repl-wrap-history): New user variable.
+ (slime-repl-history-replace): Implement wrap around.
+ (slime-repl-easy-menu): Fix binding for "Next Input". Reported by
+ Surendra Singhi.
+
+ * swank-lispworks.lisp (list-callers-internal): Return the
+ function if dspec:object-dspec returns nil.
+ (xref-results): Previously, functions for which
+ dspec:dspec-definition-locations returned nil were ignored.
+ Include them with a unknown source-location.
+
+ * swank-abcl.lisp, swank-allegro.lisp, swank-clisp.lisp,
+ swank-cmucl.lisp, swank-openmcl.lisp, swank-sbcl.lisp,
+ swank-lispworks (accept-connection): The :external-format argument
+ defaults now to :iso-latin-1-unix.
+
+2004-11-26 Helmut Eller <heller at common-lisp.net>
+
+ * swank-cmucl.lisp (read-into-simple-string): Use #-cmu19 instead
+ of #+cmu18e.
+
+2004-11-25 Chris Capel <pdf23ds at gmail.com>
+
+ * slime.el (slime-indent-and-complete-symbol): Echo the arglist if
+ there's no symbol before point. Don't complete after parens.
+ (slime-echo-arglist): Factorized from slime-space.
+ (slime-space): Use it.
+ (slime-repl-history-replace): Clear the input at the end of the
+ history.
+
+ * swank.lisp (arglist-to-string): Don't show &whole, &aux and
+ &environment args.
+ (clean-arglist): New function.
+
+2004-11-25 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-net-coding-system): Emacs does funky encoding
+ for `raw-text-unix' use `binary' instead.
+ (slime-safe-encoding-p): New function.
+ (slime-net-send): Use it and don't try to send stuff which can't
+ be decoded by Lisp.
+ (slime-inferior-lisp-program-history): XEmacs compatibility:
+ declare it as a variable.
+ (slime-xref-mode): In Emacs 21, set delayed-mode-hooks to nil
+ because we don't want to run the lisp-mode-hook. Reported by
+ Chris Capel.
+
+ * swank.lisp (dispatch-loop): Catch errors and close the
+ connection. It's almost impossible to run the debugger inside the
+ control-thread, so let it crash instead. A backtrace would be
+ nice, though.
+ (cleanup-connection-threads): Can now be called in the
+ control-thread. Add a check to avoid thread suicide.
+ (start-swank-server-in-thread): Fix the call to start-server.
+
+ * swank-sbcl.lisp (%thread-state-slot, %thread-state): Refactored
+ from thread-status.
+ (thread-status): Use it.
+ (all-threads): Exclude zombies.
+
+2004-11-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-start-and-load): Use vanilla comint instead of
+ inf-lisp. Let's try that for a while.
+ (slime): Ask for the coding system when invoked with C-u C-u.
+ (slime-net-coding-system, slime-net-valid-coding-systems): Add
+ some alternatives for older Emacsen.
+ (slime-find-buffer-package): Skip quotes. Old code looks
+ sometimes like (in-package 'foo).
+ (slime-repl-mode-map): Inhibit C-c C-z. Avoids accidental loading
+ inf-lisp.
+ (slime-net-coding-system): Use find-coding-system in XEmacs.
+ coding-system-p means something different here.
+ (slime-repl-mode-map): XEmacs compatibility: use (kbd "C-<up>")
+ instead of [C-up].
+
+ * swank.lisp (inspect-for-emacs-list): subseq on improper lists
+ breaks in Lispworks. Handle that case better.
+
+ * swank-sbcl.lisp (inspect-for-emacs)[code-component]: Disassemble
+ code-components too.
+
+ * swank-backend.lisp (import-swank-mop-symbols): Better error
+ message for the assertion.
+
+ * swank-cmucl.lisp (debug-var-value): Return #:invalid or
+ #:unknown instead of :<not-available>.
+ (swank-compile-file): Load the fasl file only if load-p is true.
+ (inspect-for-emacs, inspect-alien-record, inspect-alien-pointer):
+ Add inspector support for some alien types.
+
+ * swank-lispworks.lisp (emacs-connected): Set the sigint handler
+ only for single threaded operation. I.e. when
+ *communication-style* is nil.
+
+ * swank-allegro.lisp (set-external-format): New function. Use LF
+ as eol mark.
+ (call-with-compilation-hooks): Trap compiler-notes too.
+
+2004-11-24 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-repl-mode-map): Add C-up and C-down to move
+ through history. Consistent with comint-mode.
+ (slime-repl-mode-map): Add slime-load-file on `C-c C-l' and
+ slime-compile-file on `C-c C-k'. This is mostly to override
+ unwanted inf-lisp bindings in lisp-mode-map.
+ (slime-load-file): Handle (buffer-file-name) being nil.
+
+2004-11-20 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (make-socket-io-stream): Add some #+sb-unicode.
+
+2004-11-20 Travis Cross <travis at crosswirecorp.com>
+
+ * swank-sbcl.lisp (thread-status): Fix unbalanced parenthesis.
+
+2004-11-20 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp (make-stream-interactive): Only add ouptut
+ streams (subclasses of ccl:fundamental-output-stream) to
+ ccl::*auto-flush-streams*.
+
+2004-11-19 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-net-coding-system): New variable. Specifies the
+ coding system to use for network communication. The default is
+ iso-latin-1 and should work for all Lisps. Only a small set of
+ coding systems is currently supported.
+ (slime-net-valid-coding-systems): New variable. A list of coding
+ systems which may be used.
+ (slime-check-coding-system, slime-coding-system-mulibyte-p)
+ (slime-coding-system-cl-name): New utility function for coding
+ systems.
+ (slime-net-connect, slime-make-net-buffer,
+ slime-open-stream-to-lisp): Use it.
+ (slime-net-decode-length, slime-net-encode-length): Renamed from
+ slime-net-read3 and slime-net-enc3. The length is now encoded as
+ a 6 char hex string.
+
+ * swank.lisp (*coding-system*): New variable.
+ (start-server): Accept external-format as argument.
+ (create-server, create-swank-server, setup-server)
+ (serve-connection, open-dedicated-output-stream)
+ (create-connection): Ditto.
+ (defstruct connection): Add external-format slot.
+ (decode-message-length): New function for new length encoding.
+ (decode-message): Use it.
+ (encode-message): Use new encoding.
+
+ * swank-cmucl.lisp (accept-connection): Accept external-format
+ argument.
+ (inspect-for-emacs): Add CMUCL specific versions for array and
+ vectors.
+
+ * swank-sbcl.lisp, swank-openmcl.lisp, swank-lispworks.lisp,
+ swank-clisp.lisp, swank-backend.lisp, swank-allegro.lisp,
+ swank-abcl.lisp (accept-connection): Accept :external-format as
+ argument.
+
+2004-11-19 Matthew Danish <mrd+nospam at cmu.edu>
+
+ * swank-allegro.lisp: (count-cr): New function. Convert
+ file-offsets to match Emacs' eol-conventions.
+ (find-definition-in-file): Use it.
+
+ * slime.el (slime-insert-xrefs): Display the multi-line label much
+ more cleanly.
+
+2004-11-19 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (thread-status): Decode the thread-state-slot
+ instead of returning ???.
+
+ * swank-allegro.lisp (swank-mop:slot-definition-documentation):
+ ACL 7 says documentation should have 2 args. So, pass t as second
+ argument.
+ (fspec-primary-name): Recurse until we have a symbol.
+ (allegro-inspect): New function. Mostly reverse engineered from
+ ACL's native inspector.
+ (inspect-for-emacs (t), inspect-for-emacs (function)): Use it.
+
+ * swank.lisp (inspect-for-emacs array): Use row-major-aref instead
+ of a displaced array. I hope that does the same.
+ (inspect-for-emacs integer): Ignore errors in
+ decode-universal-time. Negative values and, in SBCL, also small
+ values cannot be decoded.
+ (list-threads): Include the thread-id. Useful for SLIME debugging.
+
+ * slime.el (slime-list-threads, slime-thread-insert): Show the
+ thread-id.
+ (slime-thread-control-mode-map): Remove the binding for the
+ no-longer-existent slime-thread-goahead command.
+
+2004-11-18 Alexey Dejneka <adejneka at comail.ru>
+
+ * swank.lisp (inspect-for-emacs): Fix bug in handling of arrays
+ with fill-pointers.
+
+2004-11-15 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: The REPL commands ,quit and ,sayoonara are now
+ distinct. Previously Quit killed all Lisps an all buffers. The
+ new Quit command kills only the current Lisp.
+ (slime-quit-lisp): New function.
+ (repl-command quit): Use it. Don't delete all buffers.
+ (repl-command sayoonara): No longer an alias for ,quit.
+ (slime-connection-list-mode-map): Bind C-k to slime-quit-lisp.
+ (slime-communication-style): New connection variable.
+ (slime-use-sigint-for-interrupt): Is no longer a connection local
+ variable. It's derived from the new slime-communication-style.
+ (slime-inhibit-pipelining): New user option.
+ (slime-background-activities-enabled-p): New predicate to control
+ various background activities like autodoc and arglist fetching.
+ (slime-space, slime-autodoc-message-ok-p): Use it.
+ (slime-search-call-site): Use hints provided to search a call-site
+ in a defun. Useful for the show-frame-source command.
+ (slime-goto-source-location): Use it.
+ (slime-quit): Deleted, as it was broken. May come back later.
+ (slime-inspector-label-face, slime-inspector-value-face)
+ (slime-inspector-action-face, slime-reader-conditional-face):
+ Provide better defaults for Emacsen which don't support :inherited
+ faces.
+
+ * swank-backend.lisp (emacs-connected): Don't pass the stream as
+ argument. make-stream-interactive is a better place for setting
+ buffering options.
+
+ * swank-cmucl.lisp (emacs-connected): Install GC hooks to display
+ GC messages in the echo area.
+ (sos/misc :flush-output): There seem to be funny signal safety
+ issues if the dedicated output stream is not used. So, lets first
+ reset the buffer index before sending the buffer to the underlying
+ stream.
+
+ * swank-lispworks.lisp (frame-source-location-for-emacs): Pass the
+ function name of the next (newer) frame as a hint to Emacs. This
+ way we can highlight the call site in some cases, instead of the
+ entire defun.
+ (frame-location): Renamed from function-name-location. The
+ argument is now a dspec, not only a name. Also include hints for
+ Emacs.
+ (lispworks-inspect): Simplified from old code.
+ (inspect-for-emacs): Use it for also for simple functions.
+ (emacs-connected, make-stream-interactive): Move the
+ soft-force-output stuff to make-stream-interactive.
+
+ * swank-abcl.lisp (emacs-connected): Deleted. The default
+ implementation should be good enough.
+
+ * swank-sbcl.lisp (emacs-connected): Updated for new interface.
+
+ * swank-openmcl.lisp (emacs-connected, make-stream-interactive):
+ Move buffering stuff to make-stream-interactive.
+
+ * swank.lisp (defstruct connection): Add new slot:
+ communication-style for convenience.
+ (create-connection): Initialize the new slot.
+ (connection-info): Send the communication-style to Emacs.
+ (install-fd-handler, simple-serve-requests): Sending
+ :use-sigint-for-interrupt is no longer necessary.
+
+2004-11-11 Raymond Toy <raymond.toy at ericsson.com>
+
+ * slime.el (slime-activate-font-lock-magic): Add XEmacs support.
+ (slime-reader-conditional-face): New face.
+
+2004-11-10 Marco Baringer <mb at bese.it>
+
+ * swank-backend.lisp (definterface): Eliminate unused variable
+ received-args.
+ (emacs-connected, make-stream-interactive, condition-references,
+ condition-extras, buffer-first-change): Add (declare (ignore X))
+ for unused arguments in default implementations.
+ (inspect-for-emacs): Remove (declare (ignore)) for inexistent
+ variable inspection-mode. Added T qualifiers in method arguments.
+
+ * swank-openmcl.lisp (inspect-for-emacs): Use definterface so
+ SLIME knows we implement this.
+ (arglist function): Use ccl:arglist, not ccl::arglist-from-map.
+ (inspect-for-emacs): Added support for inspecting the uvector
+ objects under lisp datums.
+
+2004-11-09 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (features-for-emacs): New function to avoid
+ keyword/string confusion. Case doesn't matter since Emacs will
+ downcase them anyway.
+ (connection-info, sync-features-to-emacs): Use it. Should fix
+ highlighting bug reported by Edi Weitz.
+
+ * slime.el (slime-eval-feature-conditional): Convert AND, OR, and
+ NOT to lowercase keywords.
+ (slime-net-read3): Silly optimization: give char-after the offset
+ as argument to avoid save-excursion and forward-char.
+
+2004-11-07 Brian Downing <bdowning at lavos.net>
+
+ * slime.el (slime-fuzzy-explanation): Added line to describe
+ flags (:boundp, :fboundp, :macro, etc), which are now reported in
+ the fuzzy-completion output.
+ (slime-fuzzy-insert-completion-choice): Added flags.
+ (slime-fuzzy-choices-buffer): Added flags header.
+
+ * swank.lisp (fuzzy-completions): Changed docstring to describe
+ new flags in the completion results.
+ (convert-fuzzy-completion-result): New function to marshall the
+ results from the completion core into something Emacs is
+ expecting. Added flags.
+ (fuzzy-completion-set): Use the above.
+ (compute-completion): Removed.
+ (score-completion): Cleaned up a little bit.
+ (highlight-completion): Use destructive nstring-upcase.
+
+2004-11-01 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-easy-menu): Add item for
+ slime-update-indentation. Suggested by Lynn Quam.
+ (slime-severity-faceslime-show-note-counts)
+ (slime-most-severe, slime-choose-overlay-region): Handle
+ read-errors.
+ (slime-show-buffer-position): New function.
+ (slime-show-source-location): Use it.
+
+ * swank-backend.lisp (deftype severity): Add read-errors.
+
+ * swank-cmucl.lisp (severity-for-emacs): Special case read-errors.
+ (read-error-location): Add the offset to the buffer start.
+
+ * swank.lisp (assign-index): Avoid linear search.
+
+2004-10-30 Helmut Eller <heller at common-lisp.net>
+
+ * swank-source-path-parser.lisp (source-path-stream-position):
+ Bind *read-suppress* only as long as we skip over forms. The last
+ toplevel form in the path is read with *read-suppress* = nil
+ because in newer versions of CMUCL and SBCL read will return nil
+ if *read-suppress* is t.
+
+2004-10-28 Helmut Eller <heller at common-lisp.net>
+
+ * swank-clisp.lisp: Ups. Undo previous change.
+
+ * swank-clisp.lisp: Add workaround for CLISP's broken control
+ string parser.
+
+ * swank-cmucl.lisp (set-step-breakpoints): Handle breakpoints at
+ single-return points in escaped frames better. Previously we
+ tried to set a breakpoint at the current position and consequently
+ was only hit during the next call.
+ (inspect-for-emacs)[function]: Call the next method only for
+ funcallable instances.
+ (profile-report, profile-reset, unprofile-all): We have to use
+ eval because the macro expansion depends on the value of
+ *timed-functions*. Reported by Chisheng Huang.
+
+ * slime.el (slime-space): Call slime-message in the right buffer,
+ so that after-command hooks are added in the right buffer.
+ Reported by Juho Snellman.
+ (slime-dispatch-event): Accept stepping flag.
+ (sldb-setup): Don't query when entering a recursive edit.
+ (sldb-exit): Don't kill the buffer if we are in stepping mode.
+ (slime-inspector-insert-ispec): New function.
+ (slime-open-inspector): Use it.
+ (slime-inspector-operate-on-point): Simplified.
+ (test interactive-eval): Fix test case.
+ (slime-kill-all-buffers): More regexp kludges. From Bill Clementson.
+
+ * swank-backend.lisp (activate-stepping): New function.
+
+ * swank.lisp (*sldb-stepping-p*): New variable. Used to tell
+ emacs that the debugger buffer should not be closed even if we
+ unwind.
+ (debug-in-emacs): Use it.
+ (sldb-step): Moved to the front end.
+ (inspector-princ, method-specializers-for-inspect): Simplified.
+ (methods-by-applicability): Use a simpler algorithm. I doubt there
+ is much difference in practice.
+ (inspect-for-emacs)[symbol, function, standard-generic-function]
+ [standard-method]: Use less than 80 columns.
+ (inspector-call-nth-action): Don't accept &rest args. Was never
+ used.
+ (inspect-for-emacs) [integer]: Fix control string. Thanks to CSR
+ for pointing it out.
+
+2004-10-27 Helmut Eller <heller at common-lisp.net>
+
+ * swank-sbcl.lisp (signal-compiler-condition): Actually delete one
+ of the reader-conditionalized forms.
+
+2004-10-26 Helmut Eller <heller at common-lisp.net>
+
+ * cl-indent.el: Add indentation specs for some missing CL symbols.
+ (lisp-prefix-match-indentation): Change default to
+ nil to avoid confusion for people who don't care about the issue.
+
+ * swank-sbcl.lisp (signal-compiler-condition): Remove reader
+ conditionals as the current code doesn't work in any SBCL before
+ 0.8.13 anyway.
+
+ * swank-source-path-parser.lisp: Remove workarounds for SBCL bugs.
+ The bugs are fixed in the versions we support.
+
+ * swank-cmucl.lisp (read-error-location)
+ (signal-compiler-condition): Handle read-errors.
+ (swank-compile-file): Don't load the fasl file if there was an
+ error.
+
+ * swank.lisp (define-printer-variables): Handle doc strings
+ properly.
+ (*sldb-pprint-dispatch*): Initialize it with the default dispatch
+ table.
+
+ * slime.el (slime-init-command): New function to send the command
+ to load swank. Having a separate function for the task should
+ make it easier to start a Lips with a preloaded swank.
+ (slime-maybe-start-lisp): Use it.
+ (slime-maybe-start-multiprocessing): Deleted.
+ (slime-repl-buffer): Include the name of the implementation.
+ (slime-set-default-directory)
+ (slime-sync-package-and-default-directory): Translate filenames.
+
+2004-10-25 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (inspect-for-emacs array): Properly deal with arrays
+ without fill pointers.
+ (inspect-for-emacs function): Show function-lambda-expression
+ when available.
+
+ * swank-openmcl.lisp (specializer-name): New function.
+ (who-specializes): Use it.
+ (maybe-method-location): Use it.
+ (function-source-location): Use it.
+
+ * swank-cmucl.lisp (inspect-for-emacs function): Use next
+ method's values and simply add cmucl specific details.
+
+ * slime.el (slime-repl-defparameter): Change default value to "*".
+
+2004-10-25 Thomas Schilling <tjs_ng at yahoo.de>
+
+ * swank-allegro.lisp (inspect-for-emacs): Use
+ excl::external-fn_symdef to get the function documentation.
+
+ * swank.lisp (inspect-for-emacs): Order generic function's methods
+ and show abbreviated docs for methods.
+ (abbrev-doc): New function.
+ (methods-by-applicability): New function.
+ (*gf-method-getter*): New variable.
+
+2004-10-19 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-show-source-location): Call `push-mark' to push
+ the source position onto the global mark ring.
+
+2004-10-19 Helmut Eller <heller at common-lisp.net>
+
+ * swank.lisp (define-printer-variables): NIL is not a valid
+ docstring. Reported by Alain Picard.
+ (printer-variables sldb-print): Include print-gensym,
+ pprint-dispatch, base, radix, array, and lines.
+
+2004-10-17 Luke Gorrie <luke at synap.se>
+
+ * slime.el (slime-message): Use slime-typeout-frame if available.
+
+2004-10-17 Helmut Eller <heller at common-lisp.net>
+
+ * cl-indent.el: Our local copy. Should eventually be merged the
+ file with in the main distribution.
+
+ * slime.el: (slime-find-buffer-package-function): New variable to
+ allow customization for unusal syntax.
+ (slime-maybe-rearrange-inferior-lisp): Removed unused function.
+ (slime-set-inferior-process): Non-macro version to make
+ byte-compiler happy. Reported by Raymond Wiker.
+ (slime-maybe-start-lisp): Use it.
+ (slime-sync-package-and-default-directory): Synch the
+ default-directory in the REPL buffer too.
+ (slime-goto-connection): Close the connection list window.
+ Suggested by Andras Simon.
+ (slime-repl-clear-buffer): Place point after the prompt.
+ (selector-method ?i): Use slime-process to switch to the right
+ buffer.
+ (slime-background-message): Do nothing if the minibuffer is
+ active.
+ (slime-indent-and-complete-symbol): Don't indent if we at the same
+ line as the prompt.
+
+ * swank.lisp (*sldb-pprint-frames*): Renamed to
+ *sldb-print-pretty*.
+ (*sldb-print-level*, *sldb-print-length*, *sldb-print-circle*)
+ (*sldb-print-readbly): Group of new variables to customize
+ printing in the debugger. The default values should be safe.
+ (define-printer-variables, with-printer-settings): New macros to
+ make defining and binding groups of printer variables easier.
+ (inspect-for-emacs-list): Fix bug with circular lists and only
+ shows the first 40 elements.
+ (inspect-for-emacs): Various cleanups.
+ (all-qualified-readnames): Removed. It was not needed because
+ common-lisp-indent-function strips of any package prefix and
+ downcases the symbol anyway.
+ (printer-variables sldb-print): Ooops. Better use sldb-print as prefix
+ than sldb alone. *sldb-level* was already defined.
+
+ * swank-cmucl.lisp (inspect-for-emacs (code-component)):
+ Disassemble the memory region if there's not enough debug info.
+
+2004-10-17 Jan Rychter <jan at rychter.com>
+
+ * swank-cmucl.lisp (return-from-frame): Add it.
+
+2004-10-11 Thomas F. Burdick <tfb at OCF.Berkeley.EDU>
+
+ * swank-sbcl.lisp (function-definitions): Find compiler macros, too.
+ (find-defintions, compiler-definitions)
+ (optimizer-definitions, transform-definitions): Add compiler
+ transformers and optimizers to the list of definitions.
+
+2004-10-07 Peter Seibel <peter at javamonkey.com>
+
+ * swank.lisp (spawn-threads-for-connection): Bind *debugger-hook*
+ instead of SETF'ing it.
+
+2004-10-06 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (update-indentation/delta-for-emacs): Configure Emacs
+ indentation settings not just for the symbol name but for all
+ package-qualified forms of it as well.
+
+ * doc/slime.texi (Credits): Updated the credits list to include
+ more Lisp implementors who're also SLIME hackers.
+
+2004-10-05 Luke Gorrie <luke at synap.se>
+
+ * swank.lisp (arglist-for-echo-area): Handle errors and return a
+ message.
+ (parse-symbol): Recognise an empty package name as the KEYWORD
+ package.
+
+2004-10-03 Reini Urban <rurban at x-ray.at>
+
+ * swank-clisp.lisp (getpid)[win32]: Use
+ win32:|GetCurrentProcessId|.
+
+2004-10-03 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el: Reduce dependency on inf-lisp internals. Make it
+ possible to start the inferior lisp in a buffer different from
+ "*inferior-lisp*".
+ (slime): Parse the command argument explicitly and don't rely on
+ `inferior-lisp'. Don't close all connections, but only the one
+ for the inferior lisp buffer we are using.
+ (slime-maybe-start-lisp): Take the command and buffer as argument.
+ Decide here whether we should start start a new processwe or just
+ disconnect and reconnect .
+ (slime-start-lisp): Load verbosely.
+ (slime-inferior-lisp): New function. Replaces call to
+ `inferior-lisp'.
+ (slime-inferior-connect, slime-start-swank-server): Take the
+ inferior process as argument
+ (slime-read-port-and-connect): Set the slime-inferior-process
+ variable in the new connection.
+ (slime-inferior-process): New connection local variable.
+ (slime-process): Use it.
+ (slime-restart-inferior-lisp): Don't use inferior lisp stuff.
+ (slime-switch-to-output-buffer): Process interactive arguments
+ properly.
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Load
+ verbosely.
+
+2004-10-01 Helmut Eller <heller at common-lisp.net>
+
+ * swank-allegro.lisp (find-fspec-location): excl:source-file can
+ return stuff like (:operator ...); try to handle it.
+
+ * swank-cmucl.lisp (code-component-entry-points): Only include
+ entry points with "valid" functions names. This excludes internal
+ lambdas which have usually a string as name, like "defun foo".
+
+ * swank.lisp (parse-symbol): Don't use the reader to avoid
+ interning unknown symbols. The downside is that we no longer
+ handle escaped |symbols| correctly.
+
+ * slime.el (slime-set-connection-info): Hide the *inferior-lisp*
+ buffer after we know Lisp's pid. Print the words of encouragement
+ here, when all the other asynchronous initialization is completed.
+ (slime-find-buffer-package): We need to preserve the case for
+ things like (:in-package "foo"), so return "\"foo\"".
+
+2004-09-27 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-process): New function intended to replace all
+ those references to the *inferior-lisp* buffer.
+ (slime-maybe-start-lisp): Split it up.
+ (slime-start-lisp): New function.
+ (slime-restart-inferior-lisp): Use the command from the existing
+ process to start the new process.
+
+2004-09-27 Christian Lynbech <christian at defun.dk>
+
+ * slime.el (define-slime-dialect): New macro to make starting
+ Lisps with different command line options easier.
+
+2004-09-27 Rui Patrocínio <rui.patrocinio at netvisao.pt>
+
+ * swank.lisp (mop, mop-helper): Support functions for the class
+ browser.
+
+ * slime.el (slime-browse-classes, slime-browse-xrefs): New
+ commands to browse class hierarchies and xref graphs in a tree
+ widget.
+
+ * tree-widget.el: New file. Only needed for older Emacsen.
+
+2004-09-23 Helmut Eller <heller at common-lisp.net>
+
+ * slime.el (slime-start-and-load): Take arguments so that the
+ function can be called non-interactively. Only start SLIME is if
+ it is not running.
+ (slime-recompile-bytecode): Don't warn about uses of cl-functions.
+ (slime-reset): Kill all sldb buffers.
+ (slime-goto-location-position): Fix syntax for Emacs 20.
+ (sldb-mode-map): Add C-c C-d bindings.
+ (slime-open-inspector): Insert the type in the second line so that
+ we can make longer titles, e.g we should include the princed
+ version of the inspected object.
+
+ * swank-backend.lisp (frame-package, label-value-line)
+ (label-value-line*): New functions.
+
+ * swank.lisp (frame-locals-for-emacs): Bind *print-pretty* to
+ *sldb-pprint-frames* to get more compact lines and bind *package*
+ to frame-package to get shorter labels for variables.
+ (format-values-for-echo-area): Include the hex and octal
+ representation for integers.
+ (apply-macro-expander, disassemble-symbol): Use the buffer-package
+ for reading.
+ (inspector-content-for-emacs): Use print-part-to-string so that we
+ see cycles in the data structure.
+ (inspect-for-emacs): Minor beautifications.
+ (load-file-set-package): New function.
+
+ * swank-cmucl.lisp (frame-package): Implemented.
+ (inspect-for-emacs): Only include stuff that is actually stored in
+ the object itself (see objdef.lisp for exact object layout).
+ Include the disassembly for functions and code components.
+
+2004-09-19 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-gray.lisp (stream-read-char): Treat empty strings as
+ end-of-file.
+
+ * swank-cmucl.lisp (sis/in): Treat empty strings as end-of-file.
+ (map-allocated-code-components): Inhibit efficiency notes.
+ (arglist)[symbol] Delete unreachable code.
+ (sldb-break-on-return, sldb-break-at-start): Implement it
+ (sldb-step): Some cleanups.
+
+ * swank.lisp (thread-for-evaluation): Restart the listener thread
+ if it was dead for some reason.
+ (debugger-condition-for-emacs): Include "extra" stuff. Currenlty
+ only used to pop up the source buffer at breakpoints.
+ (sldb-break): New function.
+ (interrupt-worker-thread): Interrupt the repl thread if there is
+ no other active thread.
+
+ * swank-backend.lisp (import-swank-mop-symbols): New
+ function. Useful if the implementation has most of the mop symbols
+ in the same package.
+ (sldb-break-on-return, sldb-break-at-start, condition-extras): New
+ functions.
+
+ * slime.el (sldb-break-on-return, sldb-break): New commands.
+ (slime-repl-return-string): Allow empty strings. That's our way
+ to send end-of-file.
+ (sldb-insert-condition): Add "extra" slot for random thing that
+ don't fit nicely somewhere else.
+ (sldb-dispatch-extras): New function.
+ (sldb-show-frame-source): New non-interactive version of
+ sldb-show-source.
+ (sldb-show-source): Use it.
+ (slime-beginning-of-symbol, slime-end-of-symbol): New functions
+ which don't include the character after a hash '#'.
+ (slime-symbol-name-at-point): Use them.
+ (slime-symbol-start-pos, slime-symbol-end-pos): Ditto.
+
+2004-09-17 Marco Baringer <mb at bese.it>
+
+ * swank.lisp: Don't print "Documentation:" if none is available;
+ add support for classes specializer-direct-methods; deal with
+ eql-specializers in methods.
+ (inspector-princ): New function.
+ (method-specializers-for-inspect): New function.
+ (method-for-inspect-value): New function.
+ (inspect-for-emacs): Use inspector-princ instead of
+ princ-to-string.
+
+ * swank-backend.lisp (swank-mop): Require eql-specializer,
+ eql-specializer-object and specializer-direct-methods in swank-mop
+ package.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-cmucl.lisp,
+ swank-openmcl.lisp, swank-sbcl.lisp (swank-mop): Export
+ eql-specializer, eql-specializer-object and
+ specializer-direct-methods from swank-mop.
+
+ * swank-cmucl.lisp (inspect-for-emacs): Thinko fix.
+
+ * swank-lispworks.lisp (swank-mop): Export
+ specializer-direct-methods.
+ (eql-specializer): Implement.
+ (eql-specializer-object): Implement.
+
+ * swank-sbcl.lisp (inspect-for-emacs): Fix broken ignore
+ declaration.
+
+ * doc/slime.texi: Update inspector documentation.
+
+2004-09-16 Marco Baringer <mb at bese.it>
+
+ * swank-clisp.lisp (swank-mop, inspect-for-emacs): Only define the
+ CLOS parts of the inspector if the underlying lisp provides the
+ required functionality. If not enough MOP is present to implement
+ the inspector then we define some very simple replacement methods.
+
+2004-09-16 Marco Baringer <mb at bese.it>
+
+ * swank-clisp.lisp (swank-mop): Implement the MOP compatability
+ package.
+ (inspect-for-emacs): Update for new inspection API.
+
+2004-09-15 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank-openmcl: typo in who-references. Fix frame-var-value
+
+2004-09-15 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-inspector-label-face,
+ slime-inspector-value-face, slime-inspector-action-face,
+ slime-inspector-type-face): These faces now inherit from similar
+ font-lock-<whatever> faces.
+ (slime-open-inspector): Use slime-inspector-value-face for values.
+
+ * swank.lisp (inspect-for-emacs): Add function and compiler-macro
+ documentation when inspecting symbols. View the truename of
+ logical pathnames where they exist. Fix typos in package
+ inspector (fix by Torsten Poulin <torsten at diku.dk>).
+
+ * swank-sbcl.lisp, swank-cmucl.lisp (inspect-for-emacs): Insert
+ function object's documentation when it's available.
+
+2004-09-15 Eduardo Muñoz <emufer at terra.es>
+
+ * .cvsignore: Added *.elc
+
+ * hyperspec.el: Fixed syntax error.
+
+2004-09-15 Alan Caulkins <fatman at maxint.net>
+
+ * swank.lisp (cleanp-connection-threads): Kill all Swank threads
+ for a connection when it terminates.
+
+2004-09-14 Thomas Schilling <tjs_ng at yahoo.de>
+
+ * swank-allegro.lisp (inspect-for-emacs): Fixes to previous patch.
+
+2004-09-14 Marco Baringer <mb at bese.it>
+
+ * swank-backend.lisp (inspector, make-default-inspector): Add an
+ INSPECTOR object argument to the inspector protocol. This allows
+ implementations to provide more information regarding cretain
+ objects which can't be, or simply aren't, inspected using the
+ generic inspector implementation. also export inspect-for-emacs
+ and related symbols from the backend package.
+ (make-default-inspector): New function.
+
+ * swank.lisp (inspected-parts): Rename to inspect-for-emacs and
+ add an inspector argument. Move inspect-for-emacs to
+ swank-backend.lisp, leave only the default implementations.
+
+ * swank-openml.lisp, swank-sbcl.lisp, swank-allegro.lisp,
+ swank-cmucl.lisp, swank-lispworks.lisp (inspected-parts): Rename
+ and change argument list. Many of the inspected-parts methods were
+ being clobbered by the inspected-parts in swank.lisp, now that
+ they're being used the return values have been updated for the new
+ inspect-for-emacs API.
+
+2004-09-14 Thomas Schilling <tjs_ng at yahoo.de>
+
+ * swank-allegro.lisp (inspected-parts): Implement inspector for
+ structs.
+
+2004-09-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (intern-catch-tag): New function.
+ (read-user-input-from-emacs, take-input): Use it.
+
+2004-09-13 John Paul Wallington <jpw at gnu.org>
+
+ * swank.lisp (define-special): Make the doc-type `variable'
+ rather than `symbol'. Don't quote `doc'. Doc fix.
+
+2004-09-09 Martin Simmons <martin at xanalys.com>
+
+ * swank-lispworks.lisp: Set up the swank-mop package. Implement
+ swank-mop:slot-definition-documentation and function-name.
+
+2004-09-13 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (inspected-parts): Added inspectors for pathnames,
+ logical pathnames, standard-objects and numbers (float, ratio,
+ integer and complex).
+
+ * swank-backend.lisp: Define import-to-swank-mop.
+
+ * swank-openmcl.lisp, swank-sbcl.lisp, swank-allegro.lisp: Don't
+ define the import-to-swank-mop function (now defined in
+ swank-backend.lisp).
+
+ * swank-cmucl.lisp (swank-mop, function-name): Implement backend
+ for inspector.
+ (arglist): Add support for extracting arglists from function
+ objects.
+ (create-socket): Don't specify the host on PPC.
+
+2004-09-13 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * slime.el slime-goto-location-position: New location specifiers:
+ (:method name specializers . qualifiers) all are strings. Looks
+ for defxxx name then the qualifiers as words, in order then the
+ specializers as words, in order (except for "T", which is
+ optional). Pass the symbols names for specializers and qualifiers
+ (no packages). Used by openmcl but might be useful for others
+ (:text-anchored <position fixnum> <string> <delta fixnum>)
+ Got to position, then search for string, then move delta. To
+ support upcoming source recording for openmcl debugging.
+
+ * swank-openmcl multiple changes: - fix support for *sldb-top*
+ (formerly *swank-debugger-stack-frame*) Was not thread safe. Now
+ (application-error), and (interrupt-thread) records the error
+ pointer in a table associated with thread and map-backtrace picks
+ up the appropriate pointer. *process-to-stack-top*,
+ (grab-stack-top), (record-stack-top).
+
+ - Other adjustments for changes to multiprocessing: remove
+ (force-break-in-listener) no longer necessary since we use
+ process-interrupt instead of ccl::*interactive-abort-process*
+ Adjust break-in-sldb to do so for swank repl connections
+ (abstraction breaking reference to swank::*connections*, but
+ nicely via intern)
+
+ - changes to (find-definitions) (function-source-location),
+ addition of (maybe-method-location) (remove-filename-quoting). To support
+ editing definitions of methods. To fix bug with pathnames with
+ quoted characters (like "\\.swank.lisp"). To remove bogus source
+ recording of l1-boot-3 in functions that didn't have a source file
+ noted.
+
+ - Implementation of xref functions: (xref-locations) uses xref
+ implementation added to openmcl recently. Note that you have to
+ (ccl::start-xref) for it to work for other than who-calls, and
+ that xref information is not currently persisted in fasl files (I
+ will release a patch for this soon) Backend functions (who-binds)
+ (who-macroexpands) (who-references) (who-sets)
+ (who-calls) (list-callees) (who-specializes)
+
+ - Lifted profile backend functions from swank-clisp which use
+ "metering.lisp"
+
+ - (openmcl-set-debug-switches) turns on the various variables I.
+ know about that have the lisp record extra debugging
+ information(including starting xref). I suggest you call
+ it. Should it be called by default?
+
+ - (frame-arguments) use builtin ccl::frame-supplied-args since the
+ current version was sometimes missing the first argument to the
+ function. (I think this was when it was passed by register. If you
+ don't want to lose it in the frame locals in backtrace, call
+ (openmcl-set-debug-switches) specifically, set
+ ccl::*ppc2-compiler-register-save-label* to t
+
+ - implement frame-var-value backend
+
+ * metering.lisp: Minor changes to #+ #- to recognize openmcl
+
+ * swank-loader.lisp: Load "metering.lisp"
+
+2004-09-13 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (inspected-parts): Deal with unfinalized classes in
+ standard-class inspector. (Patch from Thomas Schilling)
+
+2004-09-13 Marco Baringer <mb at bese.it>
+
+ * swank.lisp: New inspector protocol. The lisp side now returns a
+ specially formated list of "things" to format which are then
+ passed to emacs and rendered in the inspector buffer. Things can
+ be either text, recursivly inspectable values, or functions to
+ call.
+ (inspected-parts): Redefine for new inspector protocol.
+ (*inspectee-parts*): Redefine as array.
+ (*inspectee-actions*): New array, similar to *inspectee-parts*.
+ (reset-inspector): Update for new implementation of
+ *inspectee-parts* and new variable *inspectee-actions*.
+ (inspector-contents-for-emacs): New function.
+ (inspect-object): Update for new inspector protocol.
+ (inspector-nth-part): Update for new *inspectee-parts*
+ implementation.
+ (inspector-call-nth-action): New function.
+
+ * slime.el (slime-inspector-action-face): New face.
+ (slime-open-inspector): Adapt to new inspector protocol.
+ (slime-inspector-operate-on-point): New function, subsumes
+ slime-inspector-inspect-object-at-point.
+ (slime-inspector-next-inspectable-object): Skip to next object,
+ not just end of current object; wrap around buffer.
+ (slime-inspector-mode-map): change bindings of [return] and "\C-m"
+
+ * swank-bacend.lisp (swank-mop): New package. Simply defines all
+ the MOP related symbols we need from an implementation.
+ (arglist): Update doc string. Provide default implementation.
+ (function-name): New backend function.
+
+ * swank-allegro.lisp (swank-mop, slot-definition-documentation):
+ Implement. (Patch from Thomas Schilling)
+
+ * swank-sbcl.lisp (swank-mop, slot-definition-documentation,
+ function-name): Implement.
+
+ * swank-openmcl.lisp (swank-mop, function-name): Implement.
+ (arglist): Implement for function objects.
+
+2004-09-12 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (compile-file-for-emacs): Use with-buffer-syntax so
+ that SBCL source files can be compiled. From Christophe Rhodes.
+
+2004-09-09 Martin Simmons <martin at xanalys.com>
+
+ * swank-loader.lisp (make-swank-pathname): Preserve the host
+ component (important for LispWorks on Windows).
+
+2004-09-08 Martin Simmons <martin at xanalys.com>
+
+ * swank-lispworks.lisp: Implement call-with-compilation-hooks.
+
+2004-09-03 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * NEWS: Summarize changes since August.
+
+ * slime.el: Add some docstrings.
+
+ * mkdist.sh: Add PROBLEMS file. We're no longer alpha.
+
+ * swank.lisp: Remove debugging code in comment.
+
+ * swank-sbcl.lisp: Delete dead code.
+
+ * swank-lispworks.lisp (defimplementation): define-dspec-alias
+ seems to more apropriate than define-form-parser.
+
+ * swank-cmucl.lisp (print-frame): Catch errors during printing.
+
+ * README: Fix typo.
+
+2004-09-02 Wolfgang Mederle <wolfgang.mederle at stud.uni-muenchen.de>
+
+ * swank-loader.lisp (*lisp-name*): Replace / with - in CMUCL
+ version strings.
+
+2004-09-01 John Paul Wallington <jpw at gnu.org>
+
+ * slime.el (slime-oneliner): Don't use free variable.
+ (slime-recenter-window, slime-set-connection-info)
+ (slime-pprint-event, slime-compiler-notes-quit)
+ (slime-apropos-summary): Likewise.
+ (slime-connect): Tidy up handshake `message' call.
+
+2004-09-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-push-directory): Fix interactive spec.
+ (sldb-reference-properties): Take a the reference object as
+ argument instead of its parts. Fix callers accordingly.
+ (slime-fuzzy-choices-buffer): Remove assignment to unused variable
+ slime-fuzzy-target-mtime.
+ (slime-ed): Replace call to new-frame with make-frame.
+ (sldb-find-buffer): Cleanup.
+ (sldb-highlight-sexp): Fix regexp. It's now almost a full line.
+
+ * swank.lisp (completion-set, tokenize-symbol-designator)
+ (tokenize-completion, fuzzy-completion-set)
+ (briefly-describe-symbol-for-emacs): Remove simple-base-string
+ declarations.
+
+2004-08-30 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * PROBLEMS: We require SBCL 0.8.13. 0.8.12 is no longer
+ supported.
+
+ * swank-allegro.lisp (find-fspec-location): Catch errors in
+ excl:source-file.
+
+ * swank.lisp (send-to-socket-io): Add some ignore declarations.
+
+ * slime.el (sldb-fetch-all-frames, sldb-end-of-backtrace)
+ (sldb-beginning-of-backtrace): New commands.
+ (slime-search-suppressed-forms): Change the start regexp so that
+ reader conditionals in single line comments, like "; #+foo", are
+ ignored.
+
+2004-08-27 Peter Seibel <peter at javamonkey.com>
+
+ * swank-backend.lisp (swank-compile-string): Add directory
+ argument which is used by Allegro backend to improve source
+ recording for definitions compiled with C-c C-c.
+
+2004-08-23 John Paul Wallington <jpw at gnu.org>
+
+ * slime.el (slime-pretty-package-name): Fix last cond clause.
+
+2004-08-21 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (*global-debugger*): New configurable to globally
+ install swank-debugger-hook as *debugger-hook*. True by default.
+
+2004-08-19 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi: C-c C-c C-a, C-c C-u C-e.
+ Thanks Barry Fishman for reporting incorrect indexing.
+
+2004-08-18 Matthew Danish <mrd+nospam at cmu.edu>
+
+ * swank-allegro.lisp (swank-compile-string): Use #\; instead of
+ #\: to separate the position from the buffer-name. This avoids
+ troubles on Windows.
+
+2004-08-16 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi: Random updates.
+
+ * slime.el (slime-space): Use slime-message instead of
+ slime-background-message. This displays multi-line arglists.
+ (sldb-mode-map): Bind 'C' to sldb-inspect-condition.
+
+2004-08-14 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-find-buffer-package): Use "%s", not "%S", to
+ avoid ugly escape characters, if the package name contains dots.
+
+2004-08-13 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-eval-in-frame): Print result to the REPL when a
+ prefix argument is given.
+ Added pull-down menus for SLDB and the REPL.
+
+ * swank-source-path-parser.lisp: Removed caching of readtables and
+ the source-map hashtable. Fresh creation is ultra-cheap (<1ms).
+ The caching didn't handle modifications to readtables and
+ generally made me feel uneasy while tracking down an obscure bug
+ in a reader macro.
+ The cached source-map hashtable also wasn't thread-safe (ho hum).
+
+2004-08-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-merge-notes, slime-tree-for-note): Use the short
+ note message for annotation in the source buffer and the long
+ message in the tree widget. Used to be the other way around.
+ (sldb-insert-frames): Set the `start-open' property for XEmacs.
+ Without `start-open', the `point-entered' property is inherited
+ when we insert something before the "--more--" marker. Reported
+ by Sundar Narasimhan.
+
+ * swank.lisp (variable-desc-for-echo-area): Bind some printer
+ variables to limit the length of the output.
+
+2004-08-05 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-setup): Added typeout-frame keyword argument.
+ (slime-thread-attach): Fixed misnamed function call.
+
+2004-08-04 Luke Gorrie <luke at bluetail.com>
+
+ * swank-allegro.lisp (find-fspec-location): Fixed to work for more
+ types of definition than just functions. So M-. now works for e.g.
+ classes in Allegro. From Matthew Danish.
+ (find-fspec-location): Include the type of the definition in the
+ designator sent to Emacs. From Matthew Danish.
+
+2004-08-04 Martin Simmons <martin at xanalys.com>
+
+ * swank-lispworks.lisp (frame-actual-args): Correct syntax for
+ handler-case.
+
+2004-08-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: (slime-mode-map, slime-repl-mode-map)
+ (slime-repl-read-mode-map): Remove the binding for C-c C-g. C-c
+ C-b is now the default interrupt key.
+ (slime-list-repl-short-cuts): Don't trash the shortcut-table: copy
+ it before sorting. (Thanks to Mark Simpson.)
+
+2004-08-02 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-connect): Shorten the welcome message by leaving
+ out the port number (which is displayed in the REPL anyway). This
+ avoids line-wrapping some messages of encouragement.
+
+ * swank.lisp (with-buffer-syntax): Don't bind *readtable* to
+ *buffer-readtable* if they are already EQ. When we shadow this
+ binding the user can't assign *readtable* from the REPL so it's
+ best avoided when possible.
+
+ * swank-allegro.lisp: Removed fwrapper-based code for inheriting
+ "swankiness" to newly spawned threads. This was fighting the
+ system and not the right thing.
+
+ * slime.el (slime-choose-overlay-region): Tweaked the
+ multiline-annotation-avoidance code to work with forms not
+ starting with an open-paren, e.g. `(..) or #'(..).
+ (slime-update-modeline-package): New configurable. Non-nil (the
+ default) means update the Lisp package in the modeline using an
+ idle timer.
+ (slime-repl-send-input): Make the `slime-repl-old-input' property
+ cover the whole input (including newline) so that pressing RET on
+ the end of an input line works.
+ Use a unique integer as the value of this property to distinguish
+ adjacent inputs.
+ (slime-current-package): Deal with narrowing.
+
+2004-08-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp (swank-compile-string): Use a temporary file
+ and set excl::*source-pathname* manually. This way we can find
+ the source buffer of functions compiled with C-c C-c.
+ (call-with-temp-file, compile-from-temp-file): New functions.
+ (list-callers, function-callers, in-constants-p)
+ (map-function-constants): Implements list callers by groveling
+ through the constants pools of named functions.
+
+ * swank-lispworks.lisp: Minor refactoring.
+
+2004-07-30 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-connection): Say "No default connection
+ selected" if there are open connections but no default connection.
+ (slime-tree-indent-item): Point wasn't updated correctly if the
+ last line was empty. Use insert-before-markers instead of insert
+ to do it properly.
+ (slime-draw-connection-list): Don't break if there is no default
+ connection.
+
+ * swank-cmucl.lisp (call-with-debugging-environment): Only handle
+ DI::UNHANDLED-CONDITION not all DI:DEBUG-CONDITIONs.
+
+ * swank-backend.lisp (sldb-condition): Show the original condition
+ in the message.
+
+2004-07-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-eval-feature-conditional): Treat uppercase
+ operators NOT, AND, OR correctly.
+ (sldb-find-buffer): Remove killed buffers.
+ (sldb-quit): Raise an error if the RPC returns.
+ (slime-expected-failures): Delete unused function.
+ (complete-symbol): Test completion of
+ swank::compile-file. LispWorks has extra completions for
+ cl::compile-file.
+ (arglist): Test arglist of method cl:class-name. Add enough
+ regexpery to pass the test in most implementations.
+
+ * swank-sbcl.lisp (list-callers, list-callees): Implemented.
+
+2004-07-26 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-first-change-hook): Add `save-match-data' to
+ avoid breaking e.g. query-replace. Also added `save-excursion'
+ just to be safe.
+
+ * README: s/setup-slime/slime-setup/ in the .emacs snippet.
+
+2004-07-23 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-set-state): Show the message in the modeline in
+ the case where we aren't connected. Otherwise the "not connected"
+ status is ignored.
+ (slime-net-sentinel): Close the connection before changing the
+ status message. The old behaviour of this combined with the old
+ behaviour of `slime-set-state' could generally cause spurious
+ errors after a connection was closed.
+
+2004-07-22 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (carefully-find-package): Return *BUFFER-PACKAGE* if
+ no other package can be found. This is reverting a previous change
+ that broke completion in buffers with no known package.
+
+ * slime.el (slime-maybe-start-lisp): Check that *inferior-lisp*
+ exists /and/ has a running process. Fixes a startup problem if
+ your inferior-lisp has died and you want to restart SLIME.
+
+2004-07-21 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-sync-package-and-default-directory): Sync
+ `default-directory' in the REPL buffer too.
+ (slime-set-state): Convenience function for setting a connection's
+ state-name and updating the modeline if appropriate. This function
+ is called in the right places.
+ (slime-to-lisp-filename): Use `expand-file-name'.
+
+2004-07-20 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-repl-update-banner): Restore old behaviour of
+ using an asynchronous evaluation to setup the REPL. This works
+ around a problem I'd reintroduced where the first REPL command
+ uses the wrong keymap.
+
+2004-07-20 Andreas Fuchs <asf at boinkor.net>
+
+ * swank-sbcl.lisp (call-with-compilation-hooks): Trap and report
+ errors that cause compilation to fail, e.g. read errors.
+
+2004-07-19 Luke Gorrie <luke at bluetail.com>
+
+ * HACKING: Updated. Some notes about Emacs features.
+
+ * slime.el: More major refactoring.
+ Restructured and documented the networking and protocol code.
+ (slime-rex-continuations): Now connection-local.
+
+2004-07-18 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Major refactoring.
+ Mostly resectioning and reordering definitions to try and improve
+ readability.
+ (slime-get-temp-buffer-create): New utility function to popup a
+ temporary buffer that automatically has a binding on `q' to
+ intelligently restore window configuration. Handy, but currently
+ not applicable to all of our temporary buffers.
+ (slime-with-chosen-connection): Removed this macro. Consequently
+ the compilation commands no longer prompt for which connection to
+ use when given a prefix argument. `slime-switch-to-output-buffer'
+ still works like that, but for other cases I think the
+ connection-list buffer is sufficient.
+ (slime-eval-async): New arglist: (form &optional cont pkg). If the
+ continuation is unspecified then the evaluation result is ignored,
+ and if the package is unspecified then (slime-buffer-package) is
+ used.
+ (slime-eval): Package arg now defaults to (slime-buffer-package).
+ (slime-current-package): New name for (slime-buffer-package). No
+ more caching: returns the buffer-local `slime-buffer-package' if
+ set, otherwise searches for an `in-package' form.
+ A consequence of non-caching is that the package name doesn't
+ appear in the modeline anymore. The simplification is worthwhile
+ in my opinion.
+
+2004-07-17 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-autodoc): If there is a global variable name at
+ point then show its value.
+ (slime-autodoc-cache-type): Cache type 'full is no longer
+ supported.
+ (slime-background-message): Truncate messages to fit on a single
+ echo area line.
+ (slime-repl-update-banner-p, slime-dont-prompt)
+ (slime-swank-connection-retries): Removed these unused or unuseful
+ configuration variables.
+ Rearranged organised "customize" groups.
+
+ * swank.lisp (variable-desc-for-echo-area): New function.
+ (arglist-for-echo-area): Return nil if symbol can't be found.
+ (close-connection): Close connection before printing error
+ message. This avoids it getting lost in closed I/O redirection.
+
+ * README, doc/slime.texi: Updated setup instructions.
+
+2004-07-16 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-conservative-indentation): New variable. When
+ true (the default) don't auto-learn indentation of def* and with-*
+ macros. Set to nil if you want to learn them.
+ (slime-handle-indentation-update): Use it.
+
+ * swank.lisp (known-to-emacs-p): Removed filtering of def* and
+ with-*. Now handled by Emacs.
+
+ * slime.el (slime-interactive-eval): Changed display of results.
+ By default the result goes to `slime-message', which leads either
+ to echo area, temporary buffer, or typeout frame.
+ With a prefix argument the result is printed to the REPL.
+ This goes for all commands based on slime-interactive-eval, e.g.
+ `C-x C-e' and `C-c M-:'.
+
+2004-07-16 Peter Seibel <peter at javamonkey.com>
+
+ * slime.el (package-updating): Fixing this and other tests I broke
+ with my change to how emacs keeps track of the package prompt
+ string.
+ (arglist): Fix an test failure under Allegro due to a slight
+ difference in the way EXCL:ARGLIST returns arglist (no default
+ values of &optional parameters)
+
+2004-07-16 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (print-connection): print-function for connection
+ objects. Dumping the indentation-cache was damned ugly with
+ non-truncated lines (e.g. bug reports on slime-devel).
+
+ * slime.el (slime-setup): New function for installing a
+ lisp-mode-hook. You can call this from ~/.emacs to setup SLIME.
+ Takes a `autodoc' keyword argument to enable
+ slime-autodoc-mode. We can add more keywords in future.
+ (slime-keys): Moved `slime-reindent-defun' from C-M-q to
+ C-cM-q. This avoids overriding the standard binding of C-M-q to
+ index-sexp.
+ (slime-typeout-frame-properties): Removed some properties:
+ `name', because it interacts badly with X properties, `left' and
+ `top' because they don't put the frame anywhere terribly
+ convenient, and (width . 40) because it makes the frame narrower
+ than the usual word-wrapping width.
+
+2004-07-14 Peter Seibel <peter at javamonkey.com>
+
+ * slime.el (slime-lisp-package-prompt-string): Separate SLIME's
+ notion of package into two parts, an actual package name and the
+ name used in the prompt since the latter isn't necessarily an
+ actual package nickname any more.
+
+2004-07-13 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-restart-inferior-lisp): Renamed shortcut to
+ "restart-inferior-lisp" from "restart-lisp". The name better
+ suggests what it does: kill *inferior-lisp* and rerun SLIME.
+
+2004-07-13 Eric Blood <eblood at winkywooster.org>
+
+ (slime-inspector-next-inspectable-object): New inspector command
+ to goto the next inspectable object (slot). Bound to TAB.
+
+2004-07-13 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * slime.el: add support for actionable references in the
+ *slime-compiler-notes* buffer.
+ (slime-merge-notes): merge references if applicable.
+ (slime-compiler-notes-mode-map): use new functions defaulting to
+ show-details, but overrideable by text properties.
+ (slime-tree-default-printer): destroy generality by assuming a
+ tree of conditions, and insert references if applicable.
+ (sldb-format-reference-source): add :amop
+
+ * swank-sbcl.lisp (signal-compiler-condition,
+ brief-compiler-message-for-emacs,
+ long-compiler-message-for-emacs): handle references in compiler
+ conditions.
+
+ * swank.lisp (make-compiler-note): propagate references.
+
+ * swank-backend.lisp (compiler-condition): add references slot.
+
+2004-07-12 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-easy-menu): Added "Apropos all" menu item.
+ (slime-restart-lisp): Added `restart-lisp' shortcut. Doesn't do
+ the right thing if you have multiple Lisps up.
+
+ * swank.lisp: Added some docstrings.
+ Rearranged completion code and somewhat SLDB trying to layout
+ functions above their subfunctions in a tree-like way.
+ (slime-protocol-error): Renamed from slime-read-error.
+ (carefully-find-package): Now returns NIL if package can't be
+ determined, rather than *BUFFER-PACKAGE*. Correct? I didn't see
+ why it should return *BUFFER-PACKAGE*.
+ (xref): Find symbol in *BUFFER-PACKAGE*.
+
+2004-07-09 Peter Seibel <peter at javamonkey.com>
+
+ * swank.lisp (package-string-for-prompt): Change the way package
+ name in prompt is computed. N.B. after this change the name
+ displayed will not necsarily be either an actual name or nickname
+ of the package: if the name contains dots by default the prompt
+ will only display the last element, i.e. COM.GIGAMONKEYS.SPAM will
+ be shown as SPAM. This change also makes CL-USER the canonical
+ name for COMMON-LISP-USER even in implementations that provide a
+ shorter nickname such as USER.
+
+2004-07-09 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * slime.el (sldb-lookup-reference): substitute hyphens for spaces
+ in the url.
+
+2004-07-07 Thomas Schilling <tjs_ng at yahoo.de>
+
+ * swank.lisp (arglist-for-insertion): Changed formatting to use
+ arglist-to-string. That results in proper cases for
+ slime-insert-arglist.
+
+2004-07-07 Luke Gorrie <luke at bluetail.com>
+
+ * swank-loader.lisp (*lisp-name*): Include the version number in
+ ACL.
+
+ * slime.el (slime-alistify): Preserve order. This keeps the
+ *compiler-notes* right. Pointed out by Christophe Rhodes.
+ (slime-repl-update-banner-p): Renamed from slime-reply-..
+ (slime-changelog-date): Reintroduced for informational purposes.
+ (slime-repl-update-banner): Show ChangeLog date in the animation.
+ (slime-space): Do arglist lookup before inserting the
+ space. Otherwise we get a funky race condition: entering the space
+ may trigger `first-change-hook', which would send an async
+ notification to Lisp, which would put us in the 'busy' state and
+ thus we wouldn't lookup the arglist! Detective work by Edi Weitz.
+ (sldb-prune-initial-frames): More regexp fudgery :-(.
+ (read-directory-name): Use `file-name-as-directory' to ensure we
+ have the trailing / on the directory name.
+ (byte-compile-warnings): Bye-compile slime-alistify. Its inputs
+ can be pretty big.
+
+2004-07-04 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el, swank-backend.lisp, swank.lisp: Added a new backend
+ function `buffer-first-change' which is called via Emacs's
+ `first-change-hook' in slime-mode buffers. This gives Lisp a
+ chance to do something with source files before you change them on
+ disk.
+
+ * swank-cmucl.lisp (buffer-first-change): Suck the source file
+ into the cache unless already present. This is for M-. to increase
+ the chances of our having a copy of the sources corresponding with
+ the loaded code. Should help with the case where a user edits and
+ saves a file (without recompiling it) and then M-.'s for one of
+ its definitions.
+
+ * swank-allegro.lisp (make-process/inherit): Changed reader
+ conditionals to use fwrappers for #+(version>= 6).
+
+ * swank-backend.lisp (make-stream-interactive): This backend
+ function is called with each stream that will be used for
+ user-interaction, i.e. the redirected stdio streams. Can be used
+ to setup special output-flushing or similar.
+
+ * swank.lisp (open-streams): Call make-stream-interactive on the
+ redirected io streams.
+
+ * swank-allegro.lisp (make-stream-interactive): Set
+ interactive-stream-p slot on the stream to make it auto-flush.
+ (*swank-thread*, *inherited-bindings*): New variables.
+ (spawn): Bind *swank-thread* to T.
+ (make-process/inherit): Fwrapper (advice) for
+ mp:make-process. When *swank-thread* is T then make the new thread
+ inherit "sliminess": debugger hook, I/O streams, and also
+ *swank-thread* so that its children will inherit too.
+
+2004-07-03 Luke Gorrie <luke at bluetail.com>
+
+ * hyperspec.el (common-lisp-hyperspec-section-4.0): Bugfix from
+ Lennart Staflin.
+
+ * slime.el (slime-repl-clear-output): Avoid clearing the previous
+ REPL expression too. Patch from Andras Simon.
+
+ * swank-backend.lisp (definterface): Don't use
+ NO-APPLICABLE-METHOD for default methods. Instead just define them
+ as regular methods with all argument types being
+ T. Defimplementation will then replace them by using the same
+ signature. N-A-M was a stupid idea!
+
+2004-07-02 Brian Downing <bdowning at lavos.net>
+
+ * slime.el (slime-reindent-defun): Added a check for (boundp
+ 'slime-repl-input-start-mark) before checking the variable, as
+ XEmacs leaves variables unbound when `make-variable-buffer-local'
+ is run, while GNU Emacs binds them to NIL.
+
+2004-07-02 Martin Simmons <martin at xanalys.com>
+
+ * swank-lispworks.lisp (dspec-stream-position,
+ make-dspec-location): Fix typo in features for LW 4.1 and 4.2.
+
+2004-07-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (frame-actual-args): Bind
+ *break-on-signals* to nil and special case &rest, &optional, and
+ &key.
+
+2004-07-01 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-lookup-reference): Preserve case in SBCL node
+ names. Previously they were downcased, but the HTML manual's
+ filenames seem to have changed.
+
+ * NEWS: Added security note about the TCP server.
+ Added notes for ACL and ABCL.
+
+ * doc/slime.texi: General updatings for an alpha release.
+
+2004-06-30 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-display-compilation-output): New customizable
+ variable.
+
+ * swank.lisp: Minor cleanups.
+ (find-symbol-designator, find-symbol-or-lose)
+ (case-convert-input): Deleted. Replaced with calls to
+ parse-symbol{-or-lose}.
+
+ * swank-lispworks.lisp (describe-symbol-for-emacs): Include
+ information about setf-functions.
+ (emacs-connected): Add a default method to
+ env-internals:environment-display-debugger.
+
+2004-06-30 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-read-port-and-connect-to-running-swank)
+ (slime-connect, slime-open-stream-to-lisp): Replace "localhost"
+ with "127.0.0.1". This is believed to avoid unwanted DNS lookups
+ on certain operating systems. The lookups can become crippling if
+ the DNS server isn't available.
+ (line-beginning-position, line-end-position): Simple bugfix
+ suggested by Richard Klinda.
+
+ * swank-sbcl.lisp (preferred-communication-style): Choose
+ :fd-handler instead of :sigio when threads aren't available. A lot
+ of people seem to have had problems with :sigio on SBCL.
+
+2004-06-30 Luke Gorrie <luke at bluetail.com>
+
+ * NEWS: Wrote preliminary release notes for alpha-1.
+
+2004-06-29 Luke Gorrie <luke at bluetail.com>
+
+ * mkdist.sh: New shell script for creating a tarball for
+ distribution.
+
+2004-06-29 Bill Clementson <Bill_Clementson at peoplesoft.com>
+
+ * slime.el (slime-who-map): Add extra bindings for the XREF
+ commands as with the documentation commands. Now `C-c C-w C-c' is
+ `slime-who-calls' in addition to `C-c C-w c', etc.
+
+2004-06-29 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-prune-initial-frames): Tweaked regexp for
+ matching SWANK's own stack frames for effectiveness in SBCL.
+ (slime-keys): Shadow remaining inf-lisp keys (C-c C-a, C-c C-v)
+ with a null `slime-nop' command until we put them to a real use.
+
+ * swank.lisp (open-streams): Renamed the restart around reads from
+ the user-input stream from ABORT to ABORT-READ. Invoking this
+ restart seems kinda dangerous, so better for 'a' in SLDB not to do
+ so.
+
+2004-06-28 Thomas F. Burdick <tfb at OCF.Berkeley.EDU>
+
+ * swank.lisp (inspector-nth-part):
+ * slime.el (slime-inspector-copy-down, slime-inspector-mode-map):
+ Added copy-down command (M-RET) to easily move an object from the
+ inspector to the repl.
+
+2004-06-28 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-doc-map): New keymap for documentation
+ commands. These all use the `C-c C-d' prefix, followed by:
+ a - apropos
+ p - apropos-package
+ z - apropos-all
+ d - describe-symbol
+ f - describe-function
+ h - hyperspec lookup
+ ~ - hyperspec lookup of a format character
+ The final keystroke is bound both unmodified and with control, so
+ both `C-c C-d a' and `C-c C-d C-a' will make an apropos
+ search. The exception is hyperspec-lookup, because it's nice to
+ leave C-h unbound so that `C-c C-d C-h' will summarise the
+ documentation bindings.
+
+2004-06-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp (nth-frame): Skip frames where
+ frame-visible-p is false.
+
+ * slime.el (slime-buffer-package): Return the cached package if we
+ can't find something more sensible; this reverts a previous
+ change. The Lisp side will now fall back to an existing package
+ if the one supplied by Emacs doesn't exist. Using the cached
+ version is also necessary for some commands in the apropos buffer.
+ (sldb-insert-frame): Set the default-action property; pressing RET
+ on frame lines now shows/hides details.
+ (sldb-toggle-details): Preserve the current column.
+ (slime-inspector-buffer, slime-saved-window-config)
+ (slime-inspector-quit): Save and restore the window configuration.
+ (slime-highlight-suppressed-forms, slime-search-suppressed-forms):
+ Display expressions with reader conditionals (#+/#-) in
+ font-lock-comment-face if the test is false. Not implemented for
+ XEmacs.
+ (repl-return): New test.
+
+2004-06-28 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Events in the *slime-events* buffer are now exact
+ on-the-wire messages, without including e.g. Elisp continuation
+ functions. This is easier for debugging I think.
+
+ * swank-allegro.lisp (compute-backtrace): Only include frames
+ satisfying `debugger:frame-visible-p'. I did this as a lame
+ workaround for a problem where `output-frame' was segfaulting on
+ certain frames, and those frames happened not to be visible-p. I
+ don't know if it really fixes anything.
+
+ * hyperspec.el (common-lisp-hyperspec-format): This command now
+ works at the end of the buffer, fixed `char-after' usage as
+ suggested by Johan Bockgård.
+
+2004-06-28 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * hyperspec.el: add support for issue cross-reference lookups,
+ strongly inspired by hyperspec symbol lookup.
+ (common-lisp-hyperspec-issuex-table,
+ common-lisp-hyperspec-issuex-symbols): new variables
+ (common-lisp-issuex): new function
+
+ * slime.el (sldb-format-reference-node, sldb-lookup-reference):
+ (sldb-reference-properties): use new support for issue lookups
+ to support :ansi-cl :issue reference types.
+
+ * hyperspec.el: add support for glossary lookups.
+ (common-lisp-glossary-fun): new variable
+ (common-lisp-glossary-4.0, common-lisp-glossary-6.0): new functions
+
+ * slime.el (sldb-format-reference-node, sldb-lookup-reference):
+ (sldb-reference-properties): use new support for glossary lookupts
+ to support :ansi-cl :glossary reference types.
+
+2004-06-27 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * doc/slime.texi: Remove macros from chapter and section headings
+ to avoid texi2pdf breakage.
+
+ * swank-source-path-parser.lisp (cmucl-style-get-macro-character):
+ Add tests for #\space and #\\. Suggested by Christophe Rhodes.
+
+ * swank-sbcl.lisp, swank-openmcl.lisp, swank-lispworks.lisp,
+ swank-cmucl.lisp, swank-backend.lisp, swank-allegro.lisp,
+ swank-abcl.lisp (thread-id, find-thread): New backend functions.
+
+ * swank.lisp (dispatch-event): Quitting from the debugger was
+ seriously broken. Fix it. Move generation of thread ids to the
+ backends.
+ (encode-message, send-to-socket-io): Use WITHOUT-INTERRUPTS in
+ send-to-socket-io. The multithreaded version of encode-message
+ doesn't need it.
+ (nth-thread): Renamed from lookup-thread-by-id.
+ (debug-nth-thread): Renamed from debug-thread-by-id:
+ (kill-nth-thread): Renamed from kill-thread-by-id.
+
+ * slime.el (sldb-get-buffer): Add support for sldb buffers for
+ multiple threads.
+
+2004-06-25 Thomas F. Burdick <tfb at OCF.Berkeley.EDU>
+
+ * swank-sbcl.lisp (call-with-syntax-hooks, with-debootstrapping):
+ Preserve compatability with fairly recent SBCLs by checking for
+ the presense of the debootstrapping facilities at macroexpansion
+ time.
+
+ * slime.el (sldb-insert-condition): Initialize sldb-default-action
+ so that pressing RET inspects the condition.
+
+2004-06-25 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-insert-prompt): Set defun-prompt-regexp.
+ beginning-of-defun can be very slow in the repl buffer if the
+ defun-prompt-regexp is not set.
+ (sldb-insert-locals): Initialize sldb-default-action.
+ (sldb-var-number-at-point, sldb-inspect-var): New function.
+
+ * swank.lisp (inspect-frame-var): New function.
+
+ * swank-backend, swank-cmucl.lisp, swank-sbcl.lisp,
+ swank-allegro.lisp, swank-lispworks.lisp, swank-clisp.lisp
+ (frame-var-value): New backend function.
+
+2004-06-24 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * slime.el (sldb-format-reference-node): fix for when `what' is a
+ list.
+ (sldb-lookup-reference,sldb-reference-properties): support
+ :ansi-cl :section reference types.
+
+ * hyperspec.el (common-lisp-hyperspec-6.0): generalize to work
+ with section numbers lower than 10.
+
+2004-06-24 Brian Downing <bdowning at lavos.net>
+
+ * slime.el (slime-repl-send-input): Fixed a subtle difference in
+ sending input to the Lisp introduced in 1.316. The newline was
+ not getting sent, resulting in the Lisp constantly asking for more
+ read data. I believe the code has been adjusted to behave the
+ same as 1.315 with regard to sending newlines.
+ Also adjusted the `slime-repl-old-input' text property to end just
+ before the newline, not just after. This causes a gap between
+ inputs even if no Lisp output appeared in between, so that putting
+ point on an old line and hitting RET will only call up that line,
+ and hitting RET in the middle of the current line will send it and
+ not bring up a confusing combination of all previous input.
+ Many thanks to Loyd Fueston for pinpointing the date and exact
+ patch for when this problem was introduced.
+
+2004-06-23 Brian Downing <bdowning at lavos.net>
+
+ * slime.el: Re-added most of Luke's patches from yesterday. It
+ has the shortened names, uses markers instead of stored `(point)'
+ values, and `slime-fuzzy-complete-symbol' is an option for
+ `slime-complete-symbol-function'.
+ It still string compares the target buffer instead of using
+ `(buffer-modified-tick)'.
+ I left the `C-c M-i' keybinding in, as it allows use of the
+ regular completion as well. If there's an objection to this it
+ can be removed.
+ `window-configuration-change-hook' is used if the variable is
+ present, and ignored it not. This neatly sidesteps its absence in
+ XEmacs while not killing the functionality for GNU Emacs.
+
+ * doc/slime.texi: Added a command entry and short description for
+ `C-c M-I, slime-fuzzy-complete-symbol', and added its existence to
+ the `slime-complete-symbol-function' documentation.
+
+2004-06-22 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi: Noted ABCL support.
+
+ * slime.el: Backed out all of my changes to fuzzy completion. I
+ was too hasty and didn't do good things. Now it's back in pristine
+ state from Brian's patch -- use `C-c M-i' to fuzzy-complete.
+
+ * doc/Makefile (contributors.texi): The contributors list in the
+ manual is now sorted by most number of ChangeLog entries. Patch
+ from Michael Weber.
+
+ * slime.el: Some minor hacking to fuzzy completion:
+ Use the shorter `slime-fuzzy-' symbol prefix.
+ Use markers instead of numbers to remember where the completion is
+ being done. This way they are self-updating.
+ Use `buffer-modified-tick' to detect modifications instead of text
+ comparison.
+ Always restore window configuration when a completion is
+ chosen. For this completion style I think this will work okay
+ [famous last words], and the existing code wasn't
+ XEmacs-compatible for want of window-configuration-change-hook.
+ Now there is no separate keybinding for fuzzy completion, but it's
+ included as a customize option for `slime-complete-symbol-function'
+
+2004-06-22 Brian Downing <bdowning at lavos.net>
+
+ * slime.el, swank.lisp: Added "fuzzy completion."
+
+2004-06-22 Matthew Danish <mdanish at andrew.cmu.edu>
+
+ * swank-backend.lisp (unbound-slot-filler): New structure for
+ representing an unbound slot in the inspector functions.
+
+ * swank.lisp, swank-allegro.lisp: Use it.
+
+2004-06-22 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-output-filter): Choose connection based on
+ process-buffer, not current buffer. This fixes a bug where output
+ from multiple Lisp sessions could get mixed up.
+ (slime-kill-all-buffers): Include all *inferior-lisp*[<n>] buffers.
+ Split the customize settings into more subgroups.
+
+ * swank.lisp (prefixed-var): Intern *REAL-STANDARD-INPUT* etc in
+ the SWANK package instead of the COMMON-LISP package.
+
+2004-06-21 Luke Gorrie <luke at bluetail.com>
+
+ * swank-loader.lisp (*lisp-name*): Add version number to
+ Lispwork's fasl directory. We should do this for ACL and OpenMCL
+ too, but for some reason my ACL 5.0 gets an error when trying to
+ create a directory with a version number in its name, and I don't
+ have OpenMCL to test with.
+
+ * swank-backend.lisp, swank.lisp (add-hook, run-hook): Moved the
+ hook mechanism and all hooks to swank.lisp (from
+ swank-backend.lisp). There is no compelling use for the hooks in
+ backends yet and I want to pass swank.lisp-internal data
+ structures in the existing hooks.
+ (notify-backend-of-connection): Call `emacs-connected' with the
+ user-io stream for its argument. Should fix previous breakage
+ where the connection structure was passed instead.
+ (*globally-redirect-io*): New configurable: when true the standard
+ streams are globally redirected to Emacs. That way even
+ e.g. SERVE-EVENT handlers will print to Emacs. Currently does not
+ handle standard input -- that is trickier since the Lisp's native
+ REPL can be trying to read from that.
+
+ * slime.el (slime-complete-maybe-restore-window-configuration):
+ Only restore the window configuration if the completions buffer is
+ currently visible in the window that we popped it up in.
+ (slime-complete-maybe-save-window-configuration): Don't save the
+ window configuration if the completions buffer is already visible.
+ (slime-repl-return): Make sure the newline goes at the end of the
+ input, not at point.
+ (slime-complete-restore-window-configuration): Wrap the
+ `set-window-configuration' call in (run-at-time 0 ..). XEmacs does
+ not allow us to set the window configuration from inside
+ pre-command-hook.
+
+2004-06-20 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-sbcl.lisp (emacs-connected): Set *invoke-debugger-hook* to
+ our debugger hook. Not optimal, but at least BREAK will then
+ invoke our debugger.
+ (*trap-load-time-warnings*): New variable. If it is true,
+ conditions, most notably redefinition warnings, signalled at load
+ time are not trapped.
+ (swank-compile-file, swank-compile-string): Use it.
+
+ * swank.lisp (guess-buffer-package): Don't signal a continuable
+ error if the package doesn't exists; that's too annoying.
+
+ * slime.el: Fix outline structure.
+ (slime-maybe-list-compiler-notes): Fix thinko.
+ (break): New test. Reorganize the test-suite a bit to support
+ "expected failures".
+ (slime-eval-feature-conditional, slime-to-feature-keyword): Add a
+ ?: to the symbol-name if needed.
+
+2004-06-20 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (changelog-date): Removed unneeded function.
+ (connection-info): No more version field in result.
+
+ * slime.el: Audited to remove namespace slipups. Tracking a really
+ horrible clashing-with-some-user-configuration bug and want to
+ eliminate potential symbol conflicts.
+ (sldb-get-buffer): Renamed from `get-sldb-buffer'.
+ (slime-emacs-20-p): Renamed from `emacs-20-p'.
+ (slime-defun-if-undefined): Renamed from `defun-if-undefined'.
+ (slime-isearch): Small bugfix that could cause M-. to go to the
+ wrong place in CMUCL.
+ (slime-changelog-date, slime-check-protocol-version): Removed
+ unneeded functions.
+
+ * swank-backend.lisp (add-hook, run-hook): Added an Emacs-like
+ hook mechanism. The hope is that this will make some sections of
+ the code more self-describing by showing where they hook in.
+ (*new-connection-hook*): Hook run when a new connection is
+ established. Initialized to '(swank-backend:emacs-connected).
+ (*pre-reply-hook*): Hook run before sending a reply to Emacs.
+
+ * swank.lisp: Added some comments and docstrings.
+ (package-external-symbols): Removed unused function.
+ (serve-connection): Call *new-connection-hook*.
+ (eval-for-emacs): Call *pre-reply-hook*.
+ (sync-features-to-emacs, sync-indentation-to-emacs): Added to
+ *pre-reply-hook*.
+ (cl-package, keyword-package): Now defconstant instead of
+ defvar. Removed the *'s accordingly.
+
+ * slime.el (slime-abort-connection): Renamed from
+ `slime-connection-abort'. The new name is easier to find with
+ completion.
+
+ * swank-sbcl.lisp: Change sb-posix:: to sb-posix:
+
+2004-06-19 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (known-to-emacs-p): Bugfix. Indentation-updates was
+ broken.
+
+2004-06-18 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-buffer-package): If DONT-CACHE is true and no
+ package name can be found, then default to "COMMON-LISP-USER."
+ Previously we just kept using the cached version, but that could
+ lead to error-after-error if it was incorrect.
+
+ * swank.lisp (throw-to-toplevel): If our top-level catcher isn't
+ on the stack (i.e. we're using the debugger from outside an RPC)
+ then ABORT instead. That makes 'q' DWIM in SLDB.
+
+2004-06-18 Matthew Danish <mdanish at andrew.cmu.edu>
+
+ * swank-allegro.lisp (frame-source-location-for-emacs):
+ Implemented.
+
+2004-06-18 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-repl-return): If the user presses return on old
+ REPL input then take it and insert it as the current input.
+ Signal an error if the point is not on any input.
+ (slime-preserve-zmacs-region): Function to ensure that the current
+ command doesn't deactivate zmacs-region (XEmacs only).
+ (slime-repl-bol, slime-repl-eol): Use it.
+ (slime-kill-all-buffers): Changed buffer-name regexps for XEmacs
+ compatibility. The ",quit" shortcut now works in XEmacs.
+ (slime-display-message): Fixed call to `slime-typeout-message'
+ to handle formatting characters. Avoids errors on certain messages.
+ (slime-list-compiler-notes): Save the window configuration
+ earlier. This fixes an error under XEmacs when dismissing the
+ notes buffer.
+ (slime-recenter-window): Avoid moving the point. This keeps the
+ point in the right place when showing debugger-frame locations in
+ Emacs 21.
+
+2004-06-17 Luke Gorrie <luke at bluetail.com>
+
+ * swank-loader.lisp (binary-pathname): Place fasl files under
+ ~/.slime/fasl/ instead of the SLIME installation directory. The
+ installation directory can now be read-only.
+ (binary-pathname, user-init-file): Removed Win32
+ conditionalization. The init file is now called ~/.swank.lisp
+ instead of ~/_swank.lsp.
+
+ * swank-lispworks.lisp (with-fairly-standard-io-syntax): New
+ macro. Like with-standard-io-syntax, but keeps the existing values
+ of *package* and *readtable*.
+ (dspec-stream-position): Use it.
+ (quit-lisp): Implemented.
+
+2004-06-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-set-default-directory): Don't call
+ slime-repl-update-banner in Emacs 20.
+ (slime-show-source-location, slime-recenter-window): Use
+ set-window-start instead of recenter; this avoids flickering.
+ (sldb-list-locals): Don't forget about slime-current-thread in the
+ temporary buffer. (Fixes bug reported by Mike Beedle.)
+ (sldb-step): Re-enabled. The CMUCL backend has rudimentary support
+ for stepping.
+
+ * swank.lisp (*readtable-alist*): Call backend function for
+ initialization.
+ (eval-for-emacs, guess-buffer-package): Signal a continuable error
+ if a package name was supplied but no such package exists. Not
+ sure if this is better than what we did before (i.e. silently use
+ the current package).
+
+ * swank-cmucl.lisp (default-directory): Add implementation.
+ (sldb-step): Uncomment it and remove references to
+ *swank-debugger-condition*.
+
+ * swank-backend.lisp (sldb-step, default-readtable-alist): New
+ backend functions.
+ (emacs-connected): Pass the redirected stream as argument, so that
+ the OpenMCL backend can add it to CCL::*AUTO-FLUSH-STREAMS*.
+
+ * swank-sbcl.lisp (default-readtable-alist): Implement it.
+
+ * swank-loader.lisp: Move readtable-alist initialization to
+ swank-sbcl.lisp.
+
+ * swank-allegro.lisp (default-directory, call-with-syntax-hooks):
+ Add implementations as workarounds for ACL5 bugs.
+
+2004-06-16 Lawrence Mitchell <wence at gmx.li>
+
+ * slime.el (slime-maybe-rearrange-inferior-lisp): Call
+ `generate-new-buffer-name' manually, rather than relying on the
+ UNIQUE argument to `rename-buffer' to do so.
+
+2004-06-16 Frederic Brunel <frederic.brunel at in-fusio.com>
+
+ * slime.el (slime-startup-animation): Use defcustom to declare the
+ variable.
+ (slime-enable-startup-animation-p): Deleted.
+
+2004-06-16 Robert Lehr <bozzio at the-lehrs.com>
+
+ * slime.el (slime-backend): This variable can now be set to an
+ absolute filename.
+
+2004-06-15 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-compile-file): Just prompt for saving the
+ current file instead of calling `save-some-buffers'. Based on a
+ patch from Brian Downing.
+
+2004-06-12 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * wank-allegro.lisp (format-sldb-condition, condition-references):
+ Add workarounds for buggy no-applicable-method.
+
+ * swank.lisp (parse-symbol, parse-package): Handle reader errors.
+
+ * swank-openmcl.lisp (send, receive): Ensure that messages are
+ never nil.
+
+2004-06-10 Christophe Rhodes <csr21 at cam.ac.uk>
+
+ * swank-sbcl.lisp (call-with-syntax-hooks): Add hooks to fix
+ "SB!"-style package names.
+ (shebang-readtable): Return a readtable with readermacros needed
+ to parse SBCL sources.
+
+ * swank.lisp (with-buffer-syntax): New macro. This should be used
+ for code which needs to READ code from Emacs buffers. *package*
+ and *readtable* are bound suitable values.
+ (to-string, format-values-for-echo-area, interactive-eval)
+ (eval-region, interactive-eval-region, re-evaluate-defvar)
+ (swank-pprint, pprint-eval, listener-eval)
+ (compile-string-for-emacs, disassemble-symbol, describe-to-string)
+ (describe-symbol, describe-function)
+ (describe-definition-for-emacs)
+ (documentation-symbol, init-inspector, inspect-nth-part)
+ (inspector-pop, inspector-next, describe-inspectee)
+ (inspect-current-condition): Use it.
+
+2004-06-10 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-loader.lisp: Initialize swank::*readtable-alist* for SBCL.
+
+ * swank-backend.lisp (default-directory, call-with-syntax-hooks):
+ New functions.
+
+ * swank.lisp (*readtable-alist*): New configurable. The keys are
+ package name and the values readtables. The readtable will be
+ used to READ code originating from Emacs buffers in the associated
+ slime-buffer-package.
+ (drop-thread): Simplified.
+ (*buffer-readtable*): New variable.
+ (parse-package): New function.
+ (parse-string): Renamed from symbol-from-string. Make it case
+ insensitive.
+ (eval-for-emacs): Initialize the *buffer-readtable*.
+ (symbol-indentation): Don't consider symbols in the CL package.
+ Emacs already knows how to indent them.
+ (compile-file-if-needed): Used for REPL shortcut
+ 'compile-and-load'.
+
+ * slime.el (pwd): Re-add REPL shortcut.
+ (slime-repl-push-directory, slime-repl-compile-and-load): Simplified.
+
+2004-06-10 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-step): Command is disabled because the function
+ `swank:sldb-step' that it calls doesn't exist. I don't see any
+ stepping code in our backends.
+
+2004-06-09 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-goto-location-position) [:function-name]: The
+ function name can also occur after a ?(, not only after
+ whitespace.
+
+ * (slime-init-output-buffer): Initialize the package stack.
+ Reported by Rui Patrocínio.
+
+ * (slime-completions): Make it consistent with
+ slime-simple-completions. The second argument was never supplied.
+ Reported by Rui Patrocínio.
+
+2004-06-09 Eric Blood <eblood at winkywooster.org>
+
+ * slime.el (slime-indent-and-complete-symbol): Renamed from
+ slime-repl-indent-and-complete-symbol.
+
+ (slime-typeout-frame-properties): Add more default options for the
+ typeout frame--specifically it now has a default width, and moves
+ the typeout frame to the upper right.
+
+2004-06-09 Andras Simon <andras at renyi.hu>
+
+ * swank-abcl.lisp: New backend for Armed Bear Common Lisp.
+
+ * swank-loader.lisp: Add ABCL support.
+
+2004-06-09 Martin Simmons <martin at xanalys.com>
+
+ * swank-lispworks.lisp (dspec-stream-position): New function to
+ make source location work for anything complicated e.g. methods.
+ (with-swank-compilation-unit): Refactoring.
+ (who-macroexpands): Implemented.
+ (list-callers): Implemented.
+
+ * swank-backend.lisp (network-error): Inherit from simple-error to
+ get correct initargs.
+
+2004-06-09 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-insert-references): Added support for hyperlinked
+ references as part of conditions being debugged. This is a new
+ feature in SBCL to reference appropriate sections of their manual
+ or CLHS from condition objects. The references are clickable.
+
+ * swank-backend.lisp (format-sldb-condition): New backend function
+ to format conditions for SLDB.
+ (condition-references): New function to return a list of
+ documentation references associated with a condition.
+
+ * swank.lisp (debugger-condition-for-emacs): Call the above
+ backend functions to add a `references' list for Emacs.
+
+ * swank-sbcl.lisp (format-sldb-condition, condition-references):
+ Implemented. Requires a recent (latest?) SBCL release.
+
+2004-06-08 Luke Gorrie <luke at bluetail.com>
+
+ * swank-cmucl.lisp (close-socket): Remove any SERVE-EVENT handlers
+ for the socket's file descriptor.
+
+ * swank-sbcl.lisp (close-socket): Same fix.
+
+2004-06-07 Luke Gorrie <luke at bluetail.com>
+
+ * swank-cmucl.lisp: Minor refactorings.
+
+2004-06-07 Edi Weitz <edi at agharta.de>
+
+ * swank-allegro.lisp (call-with-compilation-hooks): Implemented.
+ Wrap IMPORT call in EVAL-WHEN.
+
+ * swank.lisp, swank-backend.lisp: Wrap EXPORT calls in
+ EVAL-WHEN. Fixes many warnings in ACL.
+
+2004-05-25 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-kill-without-query-p): Default to T.
+ (sldb-highlight): Variable to control face-based highlighting of
+ SLDB locations. (In Emacs21 the point is visible even in unselected
+ windows, which is sufficient for me.)
+ (sldb-show-location-recenter-arg): Argument to `recenter' when
+ showing SLDB locations. Default to nil, i.e. location appears in
+ the middle of the window.
+
+2004-05-24 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-input-complete-p): Return nil for unbalanced
+ sexps starting with quote ?', backquote ?`, or hash ?#. C-j can
+ be used for more complicated cases.
+
+2004-05-22 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-repl-sayoonara): Added "quit" as an alias for
+ sayoonara.
+
+2004-05-22 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (arglist): Catch (reader) errors in
+ READ-ARGLIST.
+
+ * swank-allegro.lisp (fspec-primary-name): New function.
+ (find-fspec-location): Use it, if the start position cannot be
+ found.
+
+ * slime.el (slime-pprint-event): New function.
+ (slime-log-event): Use it.
+ (slime-reindent-defun): Indent the form after point, if point is
+ in the first column an immediately before a #\(.
+
+2004-05-21 Bill Clementson <Bill_Clementson at peoplesoft.com>
+
+ * slime.el (slime-switch-to-output-buffer): Use "P" as interactive
+ spec.
+
+2004-05-21 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-switch-to-output-buffer): Override the
+ prefix-arg if we are called non-interactively.
+ (slime-repl-current-input): Don't add newlines.
+ (slime-repl-return): Send input if we are in read-mode also if it
+ isn't a complete expression.
+ (repl-read-lines): New test case.
+ (slime-enable-startup-animation-p): New configurable.
+ (slime-repl-update-banner): Use it.
+ (slime-hide-inferior-lisp-buffer): New function. Reuse the
+ *inferior-lisp* buffer window for the SLIME REPL.
+
+ * swank-allegro.lisp (find-fspec-location): Better handling of
+ methods. From Bill Clementson.
+
+2004-05-17 Luke Gorrie <luke at bluetail.com>
+
+ * xref.lisp, swank-clisp.lisp: Renamed XREF package to PXREF (P
+ for portable). This makes it possible to load the package in
+ e.g. CMUCL, which is nice because it's a good package.
+
+ * swank-cmucl.lisp: Some refactoring and high-level
+ commenting. Mostly just trying to organise things into fairly
+ self-contained sections (my new hobby, sad I know!)
+
+ * slime.el: Added `C-c C-e' as an alternative binding for
+ `slime-interactive-eval' (usually `C-c :'). This seems slightly
+ more convenient, and has the added bonus of clobbering an unwanted
+ `inf-lisp' binding.
+
+2004-05-14 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-with-output-to-temp-buffer): Now takes a
+ package arg specifying what slime-buffer-package should be in the
+ generated buffer.
+ (slime-show-description): actually pass the package arg.
+ (slime-show-apropos): pass the package arg to
+ slime-with-output-to-temp-buffer.
+ (slime-list-repl-shortcuts): pass a package arg.
+
+2004-05-12 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank-openmcl.lisp: Fixes to support openmcl 0.14.2 changes in
+ backtrace protocol, from Gary Byers.
+ - Replace string "tcr" to "context".
+ - Change the call to %current-tcr in map-backtrace to get-backtrace-context,
+ defined so as to be back compatible with 0.14.1.
+ - Change the call to %catch-top to explicitly use %current-tcr
+ instead of the passed in tcr-which-is-now-called-context.
+
+ Users of map-backtrace (outside of slime code) note: The tcr position in the
+ function call is now occupied by the backtrace "context" which is always nil.
+ If you really need the tcr then you need to call %current-tcr yourself now.
+
+ Gary comments: The part that's a little hard to document about
+ the new "context" stuff - used to walk the stacks of thread A from
+ thread B - is that thread B has to be aware of when a context
+ becomes invalid (a context describing part of thread A's stack is
+ valid while thread A's sitting in a break loop and becomes invalid
+ as soon as it exits that break loop.) A thread sort of announces
+ when a context becomes valid and when it becomes invalid; whether
+ and how SWANK could hook into that isn't yet clear.
+
+ * swank-openmcl.lisp: Minor changes to backtrace display: Anonymous
+ functions names in function position surrounded by #<>. Use prin1 instead of
+ princ to print function arguments (so strings have "s around them).
+ prefix symbol and list arguments by "'" to make them more look like a
+ valid function call. Let me know if you don't like this...
+
+2004-05-12 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Fixes for outline-mode in *slime-events* from Edi
+ Weitz.
+
+2004-05-11 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-events-buffer): Disable outline-mode by default.
+ (slime-inhibit-ouline-mode-in-events-buffer): New variable.
+ (slime-expected-failures): Reduce the number for SBCL.
+
+ * swank-sbcl.lisp (resolve-note-location): Resolve the location if
+ we are called by swank-compile-string. The pathname argument is
+ never :stream in SBCL, so the method written for CMUCL was never
+ called.
+
+2004-05-10 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (from-string): Bind *READ-SUPPRESS* to NIL.
+ (swank-compiler): Bind a restart to abort compilation but still
+ report the compiler messages already trapped.
+ (string-to-package-designator): Function that uses READ to
+ case-convert package names.
+ (apropos-list-for-emacs): Use it.
+
+ * slime.el (slime-eval-with-transcript): Don't print the "=>"
+ prefix in messages showing evaluation results. It mucks up
+ alignment in multi-line messages.
+ (sldb-eval-in-frame): Don't print "==>" prefix on evaluation
+ results, for the same reason.
+ (slime-show-source-location): Move the point to the source
+ location in addition to highlighting the matching parens.
+
+2004-05-08 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (find-definitions): Add support for variables
+ and constants.
+
+2004-05-07 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-clisp.lisp (compiler-note-location): Use make-location to
+ instead of `(:location ...). This initializes the new hint slot
+ automatically.
+
+2004-05-07 Barry Fishman <barry_fishman at att.net>
+
+ * swank.lisp (prin1-to-string-for-emacs, arglist-to-string): CVS
+ CLISP prints NIL as |COMMON-LISP|::|NIL| if *print-readably* is
+ true. Set *print-readably* to nil for a more Emacs friendly
+ printer syntax.
+
+2004-05-06 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-maybe-list-compiler-notes): Display the notes
+ listing after C-c C-c only if there are no annotations in the
+ buffer. CMUCL creates usually one warning with an error location
+ and an almost redundant warning without at the end of the
+ compilation unit. Don't display the listing in this common case.
+
+ (slime-reindent-defun): Pass nil as the third arument to
+ indent-region.
+
+2004-05-06 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-repl-sayoonara): Don't attempt to quit the lisp
+ if we're not connected.
+
+ * swank-openmcl.lisp (*buffer-offset*, *buffer-name*): Supply
+ default values. This avoids unbound value errors when compiling an
+ asdf system signals errors.
+
+2004-05-04 Alan Shutko <ats at acm.org>
+
+ * slime.el (slime-compiler-notes-show-details/mouse): New command.
+ (slime-compiler-notes-mode-map): Use it.
+
+2004-05-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (arglist): Handle byte-code functions better.
+ We don't know much about the actual argument list, only the number
+ of arguments. Return at least something mildly interesting like
+ (arg0 arg1 &optional arg2 ...)
+ (function-location): Special-case byte-code functions.
+
+ * swank-backend.lisp (with-struct): New macro.
+
+2004-05-04 Thomas F. Burdick <tfb at OCF.Berkeley.EDU>
+
+ * slime.el (slime-reindent-defun): New command on C-M-q. Reindent
+ the current Lisp defun after trying to close any unmatched
+ parenthesis. If used within a comment it just calls fill-paragraph.
+
+2004-05-04 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-goto-location-position): Regexp fix.
+ (slime-reindent-defun): New command on M-q. Reindent the current
+ Lisp defun after trying to close any unmatched parenthesis.
+
+ * swank.lisp: Remove (declaim (optimize ...)). The side-effect
+ this has on people's environment seems harmful (I saw someone
+ having trouble on the OpenMCL list).
+
+ * swank-cmucl.lisp (source-location-from-code-location): Fixed a
+ bug where the source-file-cache was not really used.
+ Now always report the location based on source file (cached or
+ not) even if modified -- not falling back on regexps, which was
+ probably a misfeature.
+
+ * slime.el: Remove `slime-cleanup-definition-refs'.
+
+2004-05-02 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-start-and-load): New command. Suggested by
+ Lars Magne Ingebrigtsen.
+
+2004-05-02 Lars Magne Ingebrigtsen <larsi at netfonds.no>
+
+ * slime.el (slime-kill-without-query-p): New variable.
+ (slime-net-connect): Use it.
+ (slime-open-stream-to-lisp): Ditto.
+ (slime-maybe-start-lisp): Ditto.
+
+2004-05-02 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-goto-source-location): Added support for the
+ :snippet "hint" in a location specifier. If Lisp sends the
+ (initial) source text for the definition then Emacs isearches for
+ it in both directions from the given character position. This
+ makes M-. robust when the Emacs buffer has been edited. Requires
+ backends to provide this snippet information.
+ (slime-goto-location-position): Tightened up the regular
+ expressions for :function-name style location search.
+ (slime-cleanup-definition-refs): New function to do a little
+ post-processing on definition references from Lisp. Mostly this is
+ a hack: if POSITION is NIL then we fill it in with the function
+ name, ready for regexp search. I was in a hurry and it was easier
+ to do here, and it doesn't seem entirely unreasonable.
+
+ * swank-backend.lisp (:location): Added a 'hints' property list
+ to the location structure. This is for extra information that
+ compliments the buffer/position.
+
+ * swank-cmucl.lisp (code-location-stream-position): Position the
+ argument stream at the definition before returning.
+ (source-location-from-code-location): Include the :snippet hint
+ for Emacs (see above). The snippet will only be accurate provided
+ that the source file on disk has not been modified.
+ (*source-file-cache*) The contents of all source files consulted
+ for M-. are now cached if they match the version of the running
+ code. This is so that we can accurately lookup source locations
+ even when the file is modified, provided we manage to get the
+ right version (by file timestamp) at least once.
+ (source-location-from-code-location): If the right source version
+ is not available on disk or in our cache then let Emacs fall back
+ on a regular expression search.
+
+2004-05-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (find-top-frame): New function used to hide
+ debugger-internal frames.
+ (call-with-debugging-environment): Use it.
+
+2004-05-01 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-abort): Print a message if the Emacs RPC
+ returns. It shouldn't, if ABORT manages to unwind the stack, but
+ it currently does in OpenMCL due to some bug.
+ (slime-edit-definition-fallback-function): Name of a function to
+ try if the builtin edit-definition finding fails. You can set
+ this to `find-tag' to fall back on TAGS.
+
+ * swank.lisp (list-all-systems-in-central-registry): Use explicit
+ :wild in pathname for matching (needed in at least SBCL).
+
+ * swank-openmcl.lisp: Removed obsolete `swank-compile-system'.
+
+ * swank-sbcl.lisp: Removed obsolete `swank-compile-system'.
+ Removed some stale comments about supported features.
+
+2004-04-30 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-update-banner): Don't print the working
+ directory. It rarely fits in a line and was only Emacs'
+ default-directory. M-x pwd is convenient enough.
+
+ * swank.lisp (symbol-indentation): Don't infer indentation for
+ symbols starting with 'def' or 'with-'. It was wrong most of the
+ time and Emacs' defaults are better.
+
+ * swank-lispworks.lisp (emacs-connected): Add methods to
+ stream-soft-force-output for socket-streams and
+ slime-output-streams. This flushes those streams automatically
+ (i assume it gets called when Lisp is idle).
+
+2004-04-29 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-mode): Set slime-current-thread to
+ :repl-thread.
+
+ * swank.lisp (thread-for-evaluation, dispatch-event): Accept
+ :repl-thread as thread specifier and dispatch evaluation and
+ interrupt request properly.
+ (repl-thread-eval, repl-eval): Deleted. We do the special casing in
+ thread-for-evaluation.
+
+2004-04-29 Lars Magne Ingebrigtsen <larsi at netfonds.no>
+
+ * slime.el (slime-event-buffer-name): New variable.
+ (slime-events-buffer): Use it.
+ (slime-space-information-p): Ditto.
+ (slime-space): Use it.
+ (slime-reply-update-banner-p): Ditto.
+ (slime-repl-update-banner): Use it.
+
+2004-04-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-loader.lisp (*lisp-name*): Add versioning support for
+ CLISP.
+
+ * swank-clisp.lisp (arglist): Trap exceptions and return
+ :not-available in that case.
+
+ * swank.lisp (arglist-for-insertion): Don't use ~< ..~:@>.
+ CLISP's pretty printer can't handle it.
+
+2004-04-28 Luke Gorrie <luke at bluetail.com>
+
+ * NEWS: Created a NEWS file for recording changes that we want
+ users to read about.
+
+ * slime.el (slime-log-event): Use outline-minor-mode in
+ *slime-events* instead of hideshow-mode. It's more
+ reliable. (Patch from Lawrence Mitchell.)
+
+2004-04-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-net-connect): Bind inhibit-quit to nil, so that
+ we have a chance to interrupt Emacs if open-network-stream blocks.
+ (slime-complete-maybe-restore-window-configuration): Keep trying
+ after slime-repl-indent-and-complete-symbol.
+ (slime-space): Don't close the completion buffer. We don't know
+ the window-config before the completion, so leave the buffer open.
+
+ * swank.lisp (create-server): New keyword based variant to start
+ the server in background.
+ (setup-server): Add support to keep the socket open for
+ single-threaded Lisps.
+
+2004-04-27 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi (Other configurables): Updated instructions on
+ globally installing SLDB on *debugger-hook*.
+
+ * slime.el (slime-log-event): Better bug-avoidance with
+ hs-minor-mode. Hopefully XEmacs users can rest safely now.
+ (slime-prin1-to-string): Bind `print-escape-newlines' to nil.
+ (slime-set-connection-info): Commented out call to
+ `slime-check-protocol-version'. Let's see how we do without it.
+ (slime-oneway-eval): Removed unused function.
+
+ * swank.lisp (oneway-eval-string): Removed unused function.
+
+2004-04-26 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp: Move definition of `with-io-redirection' above
+ `with-connection' to avoid a CLISP error. This is really weird.
+ (interactive-eval): Bind *package* to *buffer-package*, so that
+ `C-x C-e' and related commands evaluate in the expected package.
+
+ * slime.el (sldb-insert-frames): Handle empty backtrace (I got one
+ in CLISP).
+
+ * swank-allegro.lisp (arglist): Return :not-available if arglist
+ lookup fails with an error.
+
+ * slime.el: Moved snippets of Common Lisp code into swank.lisp
+ from the thread control panel. (Remember, no CL code in slime.el!)
+
+ * swank-loader.lisp (*lisp-name*): Include a short version number
+ in the Lisp name to separate FASL files for different
+ versions. Only implemented for CMUCL and SBCL sofar.
+
+ * swank.lisp (ed-in-emacs): Avoid mutating the argument.
+ (spawn-repl-thread): Add a new thread for evaluating REPL
+ expressions. This same thread is used for all REPL
+ evaluation. This fixes some issues with variables like * and **
+ in at least SBCL.
+
+ * nregex.lisp: Typo fix (thanks Barry Fishman).
+
+ * slime.el (slime-events-buffer): Don't use hideshow-mode in
+ XEmacs for the *slime-events* buffer. It causes obscure problems
+ for some users. Still used in GNU Emacs.
+
+2004-04-25 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-backend.lisp (arglist): Return a list or :not-available.
+ Don't return strings or raise exceptions.
+
+ * swank.lisp (arglist-for-echo-area): Simplified and adapted for
+ the new semantic of ARGLIST.
+ (arglist-for-insertion): Now a separate function.
+ (read-arglist): Deleted. No longer needed.
+
+ * swank-cmucl.lisp, swank-lispworks.lisp (arglist): Return
+ :not-available if the arglist cannot be determined.
+
+ * slime.el (slime-set-connection-info): Hide the *inferior-lisp*
+ buffer here, so that we have all the buffer rearrangement in one
+ place.
+ (slime-insert-arglist): Use swank:arglist-for-insertion.
+
+2004-04-24 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-init-connection-state): Use an asynchronous RPC
+ instead of slime-eval to reduce the amount of work we do in the
+ timer function. We can remove the workaround for the timer
+ problem.
+
+2004-04-23 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Updated top comments.
+ Make SLIME faces inherit from their font-lock cousins properly.
+ (slime-connect): Bind `slime-dispatching-connection' to avoid
+ being confused by old buffer-local variables when initializing
+ the connection. This fixes a bug where doing `M-x slime' from the
+ REPL could give a "Not connected" error.
+
+2004-04-22 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-read-system-name): Perform completion on all
+ systems in the central registry.
+
+ * swank.lisp (list-all-systems-in-central-registry): New function.
+
+2004-04-22 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-update-banner): Add workaround to force the
+ proper behavior of the the first command in the REPL buffer.
+ (slime-repl-shortcut-history): Define the variable to make XEmacs
+ happy.
+
+2004-04-22 Tiago Maduro-Dias <tcmd at rnl.ist.utl.pt>
+
+ * slime.el (slime-space): Cleanup.
+ (slime-complete-restore-window-configuration): Use
+ slime-close-buffer instead of bury-buffer.
+
+2004-04-21 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Suppress byte-compiler warnings by binding
+ byte-compiler-warnings to nil.
+ (slime-repl-shortcut): Use a structure instead of a list for the
+ short cut info. Update the users accordingly.
+
+ * swank-cmucl.lisp (arglist): Return a list instead of the string.
+
+2004-04-21 Edi Weitz <edi at agharta.de>
+
+ * slime.el (slime-apropos): Add support for regexp-based apropos.
+ We use nregex, so the regexp syntax is different from Emacs'
+ regexps and bit restricted (alternation '|' and optional groups
+ '(xy)?' are not implemented).
+ (slime-insert-arglist): New command - stolen from ILISP. I always
+ thought this was quite useful.
+ (slime-oos): Fix typo.
+
+ * swank.lisp (apropos-symbols): Use regexp and support
+ case-sensitive matching.
+ (arglist-for-echo-area): New argument to control if the operator
+ name should be included.
+
+ * nregex.lisp: New file.
+
+ * swank-loader.lisp (*sysdep-pathnames*): Load it.
+
+2004-04-21 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * doc/slime.texi (Compilation): slime-remove-notes is bound to C-c
+ M-c not M-c. Noted by Edi Weitz.
+
+2004-04-21 Edi Weitz <edi at agharta.de>
+
+ * swank.lisp (list-all-package-names): Optionally include
+ nicknames in the result.
+
+ * slime.el (slime-read-package-name): Include nicknames in the
+ completions set.
+ (slime-repl-mode-map): Bind C-c : to slime-interactive-eval just
+ like in most other SLIME buffers.
+ (read-directory-name): Compatibilty defun.
+
+2004-04-20 Tiago Maduro-Dias <tcmd at rnl.ist.utl.pt>
+
+ * slime.el (slime-close-buffer): New utility function.
+ (slime-space): Use it to kill superfluous *Completions* buffers.
+
+2004-04-17 Raymond Toy <rtoy at earthlink.net>
+
+ * swank-cmucl.lisp (source-location-tlf-number)
+ (source-location-form-number): New functions to extract the
+ encoded form-numbers from source locations.
+ (resolve-stream-source-location, resolve-file-source-location):
+ Use them.
+
+2004-04-17 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-merge-notes): Use mapconcat instead of
+ (concat (slime-intersperse (mapcar ....)))
+ (slime-intersperse): Handle empty lists.
+
+2004-04-16 Luke Gorrie <luke at bluetail.com>
+
+ * doc/Makefile: Added 'install' and 'uninstall' targets for the
+ Info manual. It may be necessary to tweak `infodir' in the
+ Makefile to suit the local system before installing. (Patch from
+ from Richard M Kreuter.)
+
+ * doc/slime.texi (Top): The Top node is now smaller, with details
+ moved into Introduction. This makes the Info front page easier to
+ navigate. (Patch from Richard M Kreuter.)
+
+2004-04-15 Ivan Boldyrev <email at secret-by-request>
+
+ * slime.el (slime-handle-repl-shortcut): Call `completing-read'
+ with an alist as expected, using `slime-bogus-completion-alist'.
+
+2004-04-14 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi (Shortcuts): Described REPL shortcuts.
+
+ * slime.el (slime-oos): Generic ASDF interface.
+ (force-compile-system, compile-system, load-system,
+ force-load-system): New REPL commands.
+
+ * swank-backend.lisp (operate-on-system): More generic interface
+ to ASDF.
+
+ * swank.lisp (operate-on-system-for-emacs): More generic
+ interface to ASDF.
+
+ * slime.el (slime-repl-mode-map): Portability fix for definition
+ of the REPL command character.
+ (slime-maybe-rearrange-inferior-lisp): Bugfix for running
+ multiple inferior lisps.
+
+2004-04-13 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-handle-repl-shortcut,
+ slime-list-all-repl-shortcuts, slime-lookup-shortcut,
+ defslime-repl-shortcut): Refactor repl shortcut code to provide a
+ more leggible help.
+
+2004-04-09 Lawrence Mitchell <wence at gmx.li>
+
+ * slime.el (slime-same-line-p): Use `line-end-position', rather
+ than searching for a newline manually.
+ (slime-repl-defparameter): Use VALUE, not VALUE-FORM.
+
+2004-04-08 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-repl-package-stack): New buffer local variable.
+ (slime-repl-directory-stack): New buffer local variable.
+ (slime-repl-command-input-complete-p): Remove.
+ (slime-repl-update-banner): New function.
+ (slime-init-output-buffer): Use slime-repl-update-banner.
+ (slime-repl-shortcut-dispatch-char): New variable.
+ (slime-repl-return): Don't check for repl commands anymore.
+ (slime-repl-send-repl-command): Remove.
+ (slime-repl-mode-map): Bind slime-repl-shortcut-dispatch-char to
+ slime-handle-repl-shortcut.
+ (slime-set-default-directory): Use read-directory-name, call
+ slime-repl-update-banner.
+ (slime-repl-shortcut-table): New global variable.
+ (slime-handle-repl-shortcut): New function.
+ (defslime-repl-shortcut): New macro for defining repl shortcuts.
+ (slime-repl-shortcut-help, "change-directory",
+ slime-repl-push-directory, slime-repl-pop-directory,
+ "change-package", slime-repl-push-package, slime-repl-pop-package,
+ slime-repl-resend, slime-repl-sayoonara, slime-repl-defparameter,
+ slime-repl-compile-and-load): New repl shortcuts.
+ (slime-kill-all-buffers): Kill sldb buffers as well.
+
+ * swank.lisp: Remove the repl related functions.
+ (requires-compile-p): New function.
+
+2004-04-07 Lawrence Mitchell <wence at gmx.li>
+
+ * slime.el (slime-repl-prompt-face): New face.
+ (slime-repl-insert-prompt): Use it.
+ (slime-with-chosen-connection, with-struct): Docstring
+ fix for function's arglist display.
+ (when-let, slime-with-chosen-connection, with-struct): Docstring
+ fix for function's arglist display.
+ (slime-read-package-name): Use `slime-bogus-completion-alist' to
+ construct completion table.
+ (slime-maybe-rearrange-inferior-lisp): Use `rename-buffer's
+ optional argument to rename uniquely.
+ (slime-check-connected): Display keybinding for `slime' via
+ `substitute-command-keys'.
+ (slime-repl-send-repl-command): Use whitespace character class in
+ regexp.
+ (slime-autodoc-stop-timer): New function.
+ (slime-autodoc-mode): Add `interactive' spec to specify optional
+ arg. This allows prefix toggling of mode (behaves more like
+ most Emacs modes now). Stop timer if switching mode off with
+ `slime-autodoc-stop-timer'.
+ (slime-autodoc-start-timer, slime-complete-symbol)
+ (slime-complete-saved-window-configuration)
+ (slime-insert-balanced-comments): Docstring fix.
+ (slime-ed): Call `slime-from-lisp-filename' on filename for list
+ case of argument.
+ (slime-insert-transcript-delimiter, slime-thread-insert): Use
+ ?\040 to indicate SPC.
+ (line-beginning-position): `forward-line' always puts us in
+ column 0.
+ (line-end-position): Define if not fboundp (for older XEmacs).
+
+2004-04-07 Peter Seibel <peter at javamonkey.com>
+
+ * swank-allegro.lisp (set-default-directory): Allegro specific
+ version that also uses excl:chdir.
+
+ * swank.lisp (swank-pprint): Add swank versions of two missing
+ pretty-printer control variables.
+
+2004-04-07 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (completion-set): Also complete package
+ names. (Patch from Sean O'Rourke.)
+ (find-matching-packages): Add a ":" to the end of package names
+ in completion.
+
+2004-04-06 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-bytecode-stale-p): Automatically check if
+ slime.elc is older than slime.el and try to help the user out if
+ so.
+
+2004-04-06 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-repl-command-input-complete-p): New function.
+ (slime-repl-send-string): New optional arg specifying what string
+ to put on slime-repl-input-history, usefull when this string
+ differs from what we actually want to eval.
+ (slime-repl-return): Check for repl commands and pass then to
+ slime-repl-send-repl-command.
+ (slime-repl-send-repl-command): New function.
+ (slime-kill-all-buffers): New function.
+
+ * swank.lisp: Define the various repl command handlers: sayoonara,
+ cd, pwd, pack and cload.
+
+ * swank-backend.lisp (quit-lisp): Define as part of the backend
+ interface and export.
+
+ * swank-sbcl.lisp, swank-openmcl.lisp, swank-cmucl.lisp,
+ swank-clisp.lisp, swank-allegro.lisp (quit-lisp): implement.
+
+2004-04-06 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (macro-indentation): Check that the arglist is
+ well-formed. This works around a problem with ACL returning
+ arglists that aren't real lambda-lists.
+
+2004-04-05 Lawrence Mitchell <wence at gmx.li>
+
+ * swank.lisp (*swank-pprint-circle*, *swank-pprint-escape*)
+ (*swank-pprint-level*, *swank-pprint-length*): Fix typo in
+ docstring.
+
+ * slime.el (slime-arglist): Don't `message' arglist directly, in
+ case it contains %-signs.
+ (slime-repl-output-face): Fix quoting.
+ (slime-symbol-at-point): Call `slime-symbol-name-at-point',
+ rather than ourselves.
+ (slime-check-protocol-version): Docstring fix.
+
+2004-04-05 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi (Semantic indentation): Documented new
+ automatically-learn-how-to-indent-macros feature.
+ Added auto version control header in subtitle.
+
+ * slime.el (slime-close-parens-at-point): New command bound to
+ C-a C-a. Inserts close-parenthesis characters at point until the
+ top-level form becomes well formed. Could perhaps be made fancier.
+ (slime-update-indentation): New command to update indentation
+ information (`common-lisp-indent-function' properties) based on
+ macro information extracted from Lisp. This happens
+ automatically, the command is just to force a full rescan.
+
+ * swank.lisp (connection): Added slots to track indentation caching.
+ (*connections*): List of all open connections.
+ (default-connection): Function to get a "default"
+ connection. This is intended to support globally using the
+ debugger hook outside the context of a SLIME request, which is
+ broken at present.
+ (with-connection): Don't setup a restart: that must be done
+ separately.
+ (sync-state-to-emacs): Call `update-connection-indentation'.
+ (update-connection-indentation): Automatically discover how to
+ indent macros and tell Emacs.
+
+ * swank-backend.lisp (arglist): Specify that strings returned
+ from ARGLIST should be READable.
+
+2004-04-02 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-maybe-list-compiler-notes): Display the notes
+ for C-c C-c, when there are notes without a good source-location.
+
+2004-04-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-sbcl.lisp: Remove the non-working workarounds for
+ non-existent fcntl. Reported by Brian Mastenbrook.
+ (preferred-communication-style): Use multithreading if futexes are
+ available, sigio if fcntl is present, and fd-handlers otherwise.
+ (resolve-note-location): Don't try to construct a source-location
+ if there's no context. Notes without location will be displayed
+ in the note-listing buffer.
+
+2004-04-01 Bill Clementson <Bill_Clementson at peoplesoft.com>
+
+ * swank-allegro.lisp (send): Fix misplaced parens.
+
+2004-03-31 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (debug-function-arglist): Return symbols if
+ possible.
+ (class-location): Support for experimental source-location
+ recording.
+
+2004-03-30 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-result-face): New face.
+ (slime-inspector-mode-map): Add a binding for M-.
+ (compile-defun): Add test case for escaped double quotes inside a
+ string.
+
+ * swank.lisp (ed-in-emacs): New allowed form for argument.
+ (pprint-eval-string-in-frame): Apply arguments in proper order.
+
+ * swank-cmucl.lisp (method-dspec): Include method-qualifiers.
+ (class-definitions): Renamed from struct-definitions. Try to
+ locate condition-classes and PCL classes (in the future).
+ (debug-function-arglist): Insert &optional, &key, &rest in the
+ right places.
+ (form-number-stream-position): Make it a separate function.
+
+2004-03-29 Lawrence Mitchell <wence at gmx.li>
+
+ * swank.lisp (ed-in-emacs): New allowed form for argument.
+
+ * slime.el (slime-ed): Deal with list form of argument. For a
+ list (FILENAME LINE [COLUMN]), visit the correct line and column
+ number.
+
+2004-03-29 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-source-path-parser.lisp (cmucl-style-get-macro-character):
+ New function. Workaround for bug(?) in SBCL.
+ (make-source-recording-readtable): Use it.
+
+2004-03-29 Luke Gorrie <luke at bluetail.com>
+
+ * HACKING: Some small updates (more needed).
+
+ * slime.el (slime-inspector-buffer): Enter `slime-inspector-mode'
+ after `slime-mode'. This seems to give priority of keymap to the
+ inspector, so that it can override SPC.
+ (slime-easy-menu): Add slime-switch-to-output-buffer.
+ Enable SLIME menu in the REPL buffer.
+ (slime-symbol-name-at-point): Avoid mistaking the REPL prompt for
+ a symbol.
+ (slime-words-of-encouragement): A few new ones.
+ (slime-insert-xrefs): Removed the final newline from XREF
+ buffers. This helps to avoid unwanted scrolling.
+
+ * doc/slime.texi: Added a section about user-interface
+ conventions and our relationship with inf-lisp.
+
+2004-03-27 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-changelog-date): Reinitialize it at load-time.
+ This avoids the need to restart Emacs (horror!) after an update.
+
+ * swank-cmucl.lisp (debug-function-arglist): Properly reconstruct
+ the arglist from the debug-info. (Not complete yet.)
+ (arglist): Use it.
+
+ * swank-lispworks.lisp (spawn): Remove CL symbols from
+ mp:*process-initial-bindings*, to avoid the irritating behavior
+ for requests executed in different threads. E.g., when someone
+ tries to set *package*.
+
+ * swank.lisp (*log-io*): New variable. Bind it to *terminal-io*
+ at load-time, so we can log to a non-redirected stream.
+ (disassemble-symbol): Allow generalized function names.
+ (apropos-symbols): Handle the PACKAGE argument properly to get
+ useful output for C-c P.
+
+ * slime.el (slime-repl-indent-and-complete-symbol): New command.
+ Bound to TAB in the REPL mode. First try to indent the current
+ line then try to complete the symbol at point.
+ (slime-dispatch-event): Ignore a unused thread variable to keep
+ XEmacs' byte compiler quiet.
+
+ * swank-sbcl.lisp (enable-sigio-on-fd): Use sb-posix::fcntl
+ instead of sb-posix:fcntl to avoid the ugly reader hack. SBCL
+ doesn't have package locks and even if they add locks in the
+ future sb-posix::fcntl will still be valid.
+ (getpid): Use defimplementation instead of defmethod.
+ (function-definitions): Take generalized function names ala '(setf
+ car)' as argument.
+
+2004-03-26 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-group-similar): Bugfix: return NIL if the input
+ list is NIL.
+ (slime-inspector-buffer): Enter `slime-inspector-mode' after
+ `slime-mode'. This seems to give priority of keymap to the
+ inspector, so that it can override SPC.
+
+2004-03-26 Bjørn Nordbø <bn at telenor.net>
+
+ * swank.lisp (print-arglist): Updated to handle arglists with
+ string elements, causing arglists for macros to display properly
+ in LW 4.1.
+
+2004-03-26 Marco Baringer <mb at bese.it>
+
+ * swank-cmucl.lisp (set-default-directory): Define only once;
+ define with defimplementation, not defun.
+
+2004-03-26 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-merge-notes-for-display): New function to merge
+ together compiler notes that refer to the same location. This is
+ an optimization for when there are a lot of compiler notes:
+ `slime-merge-note-into-overlay' concat'd messages together one by
+ one in O(n^2) time/space, and became noticeably slow in practice
+ with ~100 notes or more.
+ (slime-tree-insert): This function is now automatically
+ byte-compiled (good speed gain).
+ Wrap byte-compilation in `save-window-excursion' to avoid showing
+ an unwanted warnings buffer (in XEmacs).
+
+2004-03-25 Bjørn Nordbø <bn at telenor.net>
+
+ * swank-lispworks.lisp: (create-socket, set-sigint-handler)
+ (who-references, who-binds, who-sets): Add backward compatibility
+ for LW 4.1.
+ (dspec-buffer-position): Fix inappropriate use of etypecase.
+
+2004-03-24 Luke Gorrie <luke at bluetail.com>
+
+ * swank-sbcl.lisp (getpid): Use sb-posix:getpid.
+
+ * slime.el (slime-inspector-mode-map): Added SPC as extra binding
+ for slime-inspector-next (like info-mode).
+
+ * doc/slime.texi: Added completion style and configuration.
+
+2004-03-23 Alan Shutko <ats at acm.org>
+
+ * swank-clisp.lisp (set-default-directory): New function.
+
+2004-03-23 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp (send): Wait a bit if there are already many
+ message in the mailbox.
+
+ * swank-clisp.lisp (xref-results): Use fspec-location instead of
+ the of fspec-source-locations. Reported by Alan Shutko.
+ (break): Be friendly to case-inverting readtables.
+
+ * swank-lispworks.lisp (emacs-connected): Add default method to
+ environment-display-notifier. Reported by Bjørn Nordbø.
+ (set-default-directory, who-specializes): Implemented for
+ Lispworks.
+ (gfp): New function.
+ (describe-symbol-for-emacs, describe-definition): Distinguish
+ between ordinary and generic functions.
+ (call-with-debugging-environment): Unwind a few frames. Looks
+ better and avoids the problems with the real topframe.
+ (interesting-frame-p): Use Lispworks dbg:*print-xxx* variables to
+ decide which frames are interesting.
+ (frame-actual-args): New function.
+ (print-frame): Use it.
+
+ * swank.lisp (open-streams, make-output-function): Capture the
+ connection not only the socket. This way the streams can be used
+ from unrelated threads. Reported by Alain Picard.
+ (create-connection): Factorized. Initialize the streams after the
+ connection is created.
+ (initialize-streams-for-connection, spawn-threads-for-connection):
+ New functions.
+ (with-connection): Fix quoting bug and move upwards before first
+ use.
+ (guess-package-from-string): Add kludge for SBCL !-package names.
+ (apropos-list-for-emacs): Lispworks apparently returns duplicates;
+ remove them.
+ (inspect-object): Princ the label to allow strings and symbols.
+ (send-output-to-emacs): Deleted.
+ (defslimefun-unimplemented): Deleted. Was unused.
+
+ * slime.el (slime-easy-menu): Add some more commands.
+ (slime-changelog-date): New variable. Initialized with the value
+ returned by the function of the same name. This detects
+ incompatible versions if Emacs has not been restarted after an
+ upgrade.
+ (slime-check-protocol-version, slime-init-output-buffer): Use it.
+ (slime-events-buffer, slime-log-event): Use fundamental mode
+ instead of lisp-mode to avoid excessive font-locking for messages
+ with lots of strings.
+
+2004-03-22 Luke Gorrie <luke at bluetail.com>
+
+ * doc/slime.texi: New user manual.
+
+ * swank.lisp (*communication-style*): New name for
+ *swank-in-background*.
+ Exported configuration variables: *communication-style*,
+ *log-events*, *use-dedicated-output-stream*.
+
+2004-03-20 Julian Stecklina <der_julian at web.de>
+
+ * swank-sbcl.lisp (+o_async+, +f_setown+, +f_setfl+): Add correct
+ constants for FreeBSD.
+
+2004-03-19 Alan Shutko <ats at acm.org>
+
+ * swank.lisp, swank-loader.lisp: Take into account
+ `pathname-device' when deriving paths. A fix for Windows.
+
+2004-03-19 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-connected-hook): New hook called each time SLIME
+ successfully connects to Lisp. This is handy for calling
+ `slime-ensure-typeout-frame', if you want to use that feature.
+ (sldb-print-condition): New command to print the SLDB condition
+ description into the REPL, for reference after SLDB exits. Can be
+ called from `sldb-hook' if you want the condition to always be
+ printed. Bound to 'P' in SLDB.
+
+2004-03-18 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (format-values-for-echo-area): Bind *package* to
+ *buffer-package*.
+ (load-system-for-emacs): Renamed from swank-load-system.
+ (carefully-find-package): Be friendly to case inverting
+ readtables.
+ (inspect-current-condition): New function.
+
+ * swank-backend.lisp, swank-cmucl.lisp (set-default-directory):
+ New backend function.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-lispworks.lisp,
+ swank-sbcl.lisp (swank-compile-string): Be friendly to
+ case-inverting readtables.
+
+ * slime.el (sldb-inspect-condition): Use
+ swank:inspect-current-condition.
+ (slime-inspector-label-face): Make it bold by default.
+ (slime-check-protocol-version, slime-process-available-input):
+ Wait 2 secs after displaying the error message.
+ (sldb-list-catch-tags, sldb-show-frame-details): Display catch
+ tags as symbols not as strings.
+
+2004-03-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-dispatch-event, slime-rex): Pass a form instead
+ of a string with :emacs-rex.
+ (slime-connection-name): New connection variable. Use it in
+ various places instead of slime-lisp-implementation-type-name.
+
+ * swank.lisp: Better symbol completion for case-inverting
+ readtables. (Thanks Thomas F. Burdick for suggestions.)
+ (output-case-converter): New function.
+ (find-matching-symbols): Case convert the symbol-name before
+ comparing.
+ (compound-prefix-match, prefix-match-p): Use char= instead of
+ char-equal.
+ (case-convert-input): Renamed from case-convert.
+ (eval-for-emacs): Renamed from eval-string. Take a form instead
+ of a string.
+ (dispatch-event, read-from-socket-io): Update callers.
+ (eval-region, interactive-eval): Use fresh-line to reset the column.
+
+2004-03-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-space): Send a list of the operator names
+ surrounding point to Lisp. Lisp can use the list to select the
+ most suitable arglist for the echo area. Suggested by Christophe
+ Rhodes and Ivan Boldyrev.
+ (slime-enclosing-operator-names): New function.
+
+ * swank.lisp (arglist-for-echo-area): Renamed from arglist-string.
+ (format-arglist-for-echo-area, arglist-to-string): New functions.
+
+2004-03-12 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-backend.lisp (find-definitions): Fix docstring.
+
+ * slime.el (slime-dispatch-event): Re-enable :ed command.
+ (sldb-return-from-frame): Send swank:sldb-return-from-frame.
+
+ * swank-cmucl.lisp (find-definitions): Allow names like (setf car).
+
+ * swank.lisp (sldb-return-from-frame): Convert the string to a
+ sexp.
+ (dispatch-event, send-to-socket-io): Allow %apply events.
+ (safe-condition-message): Bind *pretty-print* to t.
+ (set-default-directory): Use the truename.
+ (find-definitions-for-emacs): Allow names like (setf car).
+
+2004-03-12 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank.lisp (:swank): Export startup-multiprocessing,
+ restart-frame, return-from-frame.
+ What about kill-thread and interrupt-thread, which are accessed
+ as internal symbols?
+
+2004-03-10 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (struct-definitions, find-dd)
+ (type-definitions, function-info-definitions)
+ (source-transform-definitions, setf-definitions): New funtions.
+ (find-definitions): Include struct definitions, deftypes, setf
+ defintions, compiler-macros and compiler transforms.
+
+2004-03-10 Andras Simon <andras at renyi.hu>
+
+ * swank.lisp (print-arglist): Use with-standard-io-syntax.
+
+2004-03-10 Pawel Ostrowski <pasza at zodiac.mimuw.edu.pl>
+
+ * swank-cmucl.lisp (unprofile-all): (eval '(profile:unprofile))
+ instead of just calling it since it is a macro in cmucl.
+
+ * swank.lisp (:swank): export profile symbols (profiled-functions,
+ profile-report, profile-reset, unprofile-all, profile-package)
+
+2004-03-10 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp, swank-lispworks.lisp, swank-sbcl.lisp,
+ swank-clisp.lisp, swank-cmucl.lisp (find-definitions): Some
+ tweaking.
+
+ * swank.lisp (print-arglist): Bind *pretty-circle* to nil to avoid
+ output like "(function . (cons))". Suggested by Michael Livshin.
+ (test-print-arglist): Re-enable the tests.
+ (find-definitions-for-emacs): Renamed from
+ find-function-locations.
+
+ * slime.el (slime-edit-definition): Renamed from
+ slime-edit-fdefinition. Display the dspec if there are multiple
+ definitions.
+ (slime-symbol-name-at-point): Handle the case when there is no
+ symbol at point.
+ (slime-expected-failures): New function
+ (slime-execute-tests): Use it.
+
+2004-03-09 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (frame-source-location-for-emacs): Export it.
+ Reported by Jouni K Seppanen
+ (test-print-arglist): Disable the tests until we know what's wrong
+ with print-arglist. Reported by Michael Livshin.
+
+ * swank-source-path-parser.lisp, swank-gray.lisp (in-package): We
+ are in-package :swank-backend. Thanks to Raymond Wiker.
+
+ Merge package-split branch into main trunk.
+
+ * swank-clisp.lisp (find-fspec-location): Handle "No such file"
+ errors.
+
+ * swank-openmcl.lisp (preferred-communication-style): Implemented.
+ (call-without-interrupts, getpid): Use defimplementation.
+ (arglist, swank-compile-file, swank-compile-string)
+ (swank-compile-system, backtrace): Renamed.
+ (print-frame): New function.
+ (frame-catch-tags): Don't exclude nil source location.
+ (format-restarts-for-emacs, debugger-info-for-emacs,
+ inspect-in-frame). deleted
+ (frame-arguments): Don't use to-string.
+ (find-source-locations, find-function-locations
+ (method-source-location): Deleted.
+ (canonicalize-location, find-definitions,
+ function-source-location, list-callers): Use
+ ccl::edit-definition-p and
+ ccl::get-source-files-with-types&classes. Makes things easier.
+ (return-from-frame): Take a sexp not a string.
+ (describe-definition): Describe more types.
+
+ * swank-loader.lisp: Change load order. swank.lisp is now the last
+ file.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-cmucl.lisp,
+ swank-gray.lisp, swank-lispworks.lisp, swank-sbcl.lisp,
+ swank-source-path-parser.lisp: Implement changed backend interface
+ and remove references to frontend symbols.
+
+ * swank-backend.lisp (:swank-backend): New package.
+ (definterface): Export the symbol.
+ (:location, :error, :position, :buffer): Define structure of
+ source locations here.
+ (preferred-communication-style, compute-backtrace, print-frame):
+ New functions.
+ (debugger-info-for-emacs): Deleted.
+
+ Renaming:
+
+ compile-file-for-emacs -> swank-compile-file
+ compile-string-for-emacs -> swank-compile-string
+ compile-system-for-emacs -> swank-compile-stystem
+ arglist-string -> arglist
+ backrace -> compute-backtrace
+ find-function-locations -> find-definitions
+
+ * swank.lisp (:swank): Create the package here.
+ (*swank-in-background*): Call the backend function
+ preferred-communication-style to for the initial value.
+ (find-symbol-designator): Handle NIL properly.
+ (arglist-string): Renamed from format-arglist. Call backend
+ function directly.
+ (*sldb-restarts*, swank-debugger-hook, format-restarts-for-emacs)
+ (nth-restart, invoke-nth-restart, sldb-abort): Handle restarts in
+ the front end.
+ (frame-for-emacs): Renamed from print-with-frame-label.
+ (backtrace, debugger-info-for-emacs, pprint-eval-string-in-frame)
+ (set-default-directory): Now in the front end.
+ (frame-locals-for-emacs): Use print not princ for variable names.
+ (compile-file-for-emacs, compile-string-for-emacs): Small wrappers
+ around backend functions.
+ (describe-definition-for-emacs): Handle unknown symbols before
+ calling the backend.
+ (find-function-locations): Wrapper for new backend function
+ find-definitions.
+ (group-xrefs, partition, location-valid-p, xref-buffer, xref):
+ Updated for the new backend functions.
+
+ * slime.el:
+ (slime-symbol-at-point, slime-symbol-name-at-point):
+ slime-symbol-at-point calls slime-symbol-name-at-point not the
+ other way around. This avoids the mess if the symbol at point is
+ NIL.
+ (slime-compile-file, slime-load-system, slime-compile-region)
+ (slime-call-describer, slime-who-calls, sldb-catch-tags): Updates
+ for renamed lisp functions.
+ (slime-list-callers, slime-list-callees): Unified with other xref
+ commands.
+ (sldb-show-frame-details): Catch tags no longer include the source
+ location.
+ (sldb-insert-locals): Simplified.
+
+2004-03-09 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (read-into-simple-string): Use the correct fix.
+ Reported by Håkon Alstadheim.
+
+2004-03-08 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-start-swank-server, slime-maybe-start-lisp):
+ Translate filenames. Reported by Dan Muller.
+
+2004-03-08 Bill Clementson <Bill_Clementson at peoplesoft.com>
+
+ * slime.el (slime-insert-balanced-comments)
+ (slime-remove-balanced-comments, slime-pretty-lambdas): New
+ functions.
+
+2004-03-07 Jouni K Seppanen <jks at iki.fi>
+
+ * slime.el (sldb-help-summary): New function.
+ (sldb-mode): Add docstring so that describe-mode is useful.
+ (sldb-mode-map): Add bindings for sldb-help-summary and
+ describe-mode.
+ (define-sldb-invoke-restart-key): Generate docstrings.
+ (sldb-default-action/mouse, sldb-default-action)
+ (sldb-eval-in-frame, sldb-pprint-eval-in-frame)
+ (sldb-inspect-in-frame, sldb-down, sldb-up, sldb-details-up)
+ (sldb-details-down, sldb-list-locals, sldb-quit, sldb-continue)
+ (sldb-abort, sldb-invoke-restart, sldb-break-with-default-debugger)
+ (sldb-step): Add rudimentary docstrings.
+
+2004-03-07 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-complete-symbol*, slime-simple-complete-symbol):
+ Use the correct block name when returning.
+ (slime-display-completion-list): Fix typo.
+
+ * swank-cmucl.lisp (frame-locals): Use #:not-available instead of
+ "<not-available>".
+
+2004-03-05 Bill Clementson <Bill_Clementson at peoplesoft.com>
+
+ * swank-lispworks.lisp (getpid, emacs-connected): Conditionalize
+ for Windows.
+
+2004-03-05 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (frame-locals-for-emacs): Bind *print-readably* to
+ nil.
+
+2004-03-05 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (frame-locals-for-emacs): New function.
+
+ * slime.el (sldb-frame-locals): Use swank::frame-locals-for-emacs
+ not swank::frame-locals.
+ (sldb-insert-locals): use the :value property, not the
+ :value-string property.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-cmucl.lisp,
+ swank-lispworks.lisp, swank-sbcl.lisp (frame-locals): Return lisp
+ objects, not strings. Use the :value property and not the
+ :value-string property.
+
+2004-03-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-display-comletion-list): New function. Set
+ syntax table properly.
+ (slime-complete-symbol*, slime-simple-complete-symbol): Use it.
+ (slime-update-connection-list): New function.
+ (slime-draw-connection-list): Simplified.
+ (slime-connection-list-mode-map): Bind g to update-connection-list.
+ (slime-open-inspector): Print the primitive type in brackets.
+ (slime-test-arglist): Add test for empty arglist.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-cmucl.lisp,
+ swank-lispworks.lisp, swank-sbcl.lisp, swank-backend.lisp
+ (thread-alive-p): Add default implementation.
+ (describe-primitive-type): Add default implementation.
+ (inspected-parts): Implemented for Allegro and CLISP.
+
+ * swank.lisp (remove-dead-threads): New function.
+ (lookup-thread): Use it.
+ (print-arglist): New function. This time without a custom pretty
+ print dispatch table.
+ (format-arglist): Use it.
+ (inspected-parts): Add method for hash-tables.
+
+2004-03-03 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp: Use *emacs-connection*, *active-threads*, and
+ *thread-counter* as thread local dynamic variables.
+ (init-emacs-connection): Don't set *emacs-connection*.
+ (create-connection, dispatch-event): Pass the connection object to
+ newly created threads.
+ (with-connection): New macro
+ (handle-request, install-fd-handler, debug-thread): Use it.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-cmucl.lisp,
+ swank-openmcl.lisp, swank-sbcl.lisp (call-with-compilation-hooks):
+ Bind fewer variables. Most of them are already bound in
+ swank.lisp.
+
+ * swank.lisp (setup-server, serve-connection): New dont-close
+ argument to keep the socket open after the first connection.
+ (start-server, create-swank-server): Update callers.
+ Reported by Bill Clementson.
+
+ * swank-cmucl.lisp (resolve-note-location): Don't be too clever,
+ if there is no context available. The compiler notes buffer is
+ probably more adequate in this situation.
+ (compile-file-for-emacs): Use the :load argument to compile-file.
+ (inspect-in-frame): Deleted.
+
+ * slime.el (slime-compilation-finished-hook): Use
+ slime-maybe-list-compiler-notes as default.
+ (slime-maybe-list-compiler-notes): New function.
+ (slime-list-compiler-notes): Insert "[no notes]" if there aren't
+ any. Pop to the buffer.
+ (slime-complete-symbol*, slime-simple-complete-symbol): Set the
+ lisp-mode-syntax-table in the completion buffer.
+ (check-parens): Compatibility function for XEmacs and Emacs 20.
+
+ * swank.lisp (find-completions): Deleted.
+ (simple-completions): Use longest-common-prefix instead of
+ longest-completion.
+ (inspect-in-frame): Moved here from swank-cmucl.lisp.
+
+ * swank-lispworks.lisp (call-with-debugging-environment): Bind
+ *sldb-top-frame*.
+ (nth-frame): Use *sldb-top-frame*.
+ (name-source-location, name-source-locations): Renamed from
+ dspec-source-location, dspec-source-locations. The result now
+ includes methods for generic functions.
+ (eval-in-frame, return-from-frame, restart-frame): Implemented.
+ (compile-string-for-emacs): Set dspec::*location* to the buffer
+ location.
+ (signal-undefined-functions, signal-error-data-base)
+ (make-dspec-location): Remove temp-file kludges.
+ (patch-source-locations, replace-source-file): Deleted.
+
+2004-03-01 Marco Baringer <mb at bese.it>
+
+ * swank.lisp (format-arglist): deal with nil arglists.
+
+2004-03-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (compile-string-for-emacs): Patch the
+ recorded source locations.
+ (replace-source-file, patch-source-locations): New function.
+ (dspec-buffer-position): Handle defgeneric.
+ (make-dspec-location): Handle (patched) emacs-buffer locations.
+ (emacs-buffer-location-p): New function.
+ (describe-primitive-type, inspected-parts): Implemented.
+ (kill-thread): Implemented.
+
+ * swank-sbcl.lisp, swank-cmucl.lisp, swank-allegro.lisp
+ (kill-thread): Implemented.
+
+2004-02-29 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-complete-symbol): Make slime-complete-symbol
+ customizable. I don't understand how the ILISP style completion
+ is supposed to work and find it unintuitive.
+ (slime-complete-symbol-function): New variable.
+ (slime-complete-symbol*): Renamed from slime-complete-symbol.
+ (slime-simple-complete-symbol, slime-simple-completions): New
+ function.
+ (slime-compiler-notes-to-tree): Return a list of trees, not a single
+ tree.
+
+ * swank.lisp (format-arglist): Don't use a custom pprint table.
+ Didn't work with CLISP and the behavior was different in SBCL and
+ Lispworks.
+ (completions): Factorize.
+ (parse-completion-arguments, format-completion-set,
+ (completion-set, find-matching-symbols, find-completions): New
+ functions.
+ (simple-completions): New function.
+ (prefix-match-p) New function.
+
+2004-02-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-compilation-finished-hook): New hook variable.
+ (slime-compilation-finished): Call it.
+ (slime-maybe-show-xrefs-for-notes): New function.
+ (slime-make-default-connection): Use the current connection.
+ (slime-connection-at-point): New function.
+ (slime-goto-connection, slime-connection-list-make-default): Use
+ it.
+ (slime-draw-connection-list): Minor cleanups.
+
+ Define selectors for t and c for thread and connection list.
+
+ * swank.lisp: (*initial-pprint-dispatch-table*)
+ (*arglist-pprint-dispatch-table*): Workaround for bug in
+ CLISP. Don't supply nil as argument to copy-pprint-dispatch.
+ (print-cons-argument): Insert a space after the car.
+
+2004-02-27 Marco Baringer <mb at bese.it>
+
+ * slime.el (slime-read-port-and-connect,
+ slime-read-port-and-connect-to-running-swank): Refactor
+ slime-read-port-and-connect into two functions so that
+ slime-thread-attach can use the logic in
+ slime-read-port-and-connect.
+ (slime-thread-control-mode-map): Added key bindings for
+ slime-thread-kill, slime-thread-attach, slime-thread-debug and
+ slime-list-threads.
+ (slime-thread-kill, slime-thread-attach, slime-thread-debug): New
+ functions.
+
+ * swank-backend.lisp (kill-thread): Added to swank interface.
+
+ * swank-openmcl.lisp (kill-thread): Implement.
+
+ * swank.lisp (start-server): Add optional background argument,
+ defaults to *swank-background*.
+ (lookup-thread-by-id): New function.
+ (debug-thread): New function.
+
+2004-02-26 Peter Seibel <peter at javamonkey.com>
+
+ * slime.el (slime-draw-connection-list): Use text-properties to
+ associate the connections each line of the connections list
+ buffer.
+
+2004-02-26 Peter Seibel <peter at javamonkey.com>
+
+ * slime.el (slime-list-connections): Make the buffer created by
+ this function do a bit more: Can use it to switch to different
+ connections and change the default.
+
+2004-02-26 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp (ccl::force-break-in-listener): Pass a
+ condition object to invoke-debugger.
+ Patch by Bryan O'Connor <bryan-slime at lunch.org>
+
+2004-02-26 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-backend.lisp (:swank): export connection-info.
+
+ * swank-allegro.lisp (lisp-implementation-type-name): Implement
+ it.
+
+ * swank-sbcl.lisp (compile-file-for-emacs): Load the fasl file
+ regardless of f-p.
+
+ * swank.lisp (swank-pprint): Bind *package* to *buffer-package*.
+ Reported by Alan Picard.
+
+ * swank-lispworks.lisp (dspec-buffer-position): Renamed from
+ dspec-buffer-buffer-position. Handle dspecs of the form (defmacro
+ foo). Reported by Alan Picard.
+ (arglist-string): Handle unknown arglists properly.
+
+2004-02-25 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (arglist-string): Delay the call to
+ di::function-debug-function until it is actually needed.
+ (compile-file-for-emacs): Load the fasl file irrespective of
+ COMILE-FILE's third return value.
+
+ * swank.lisp (connection-info): New function.
+ (open-streams): Don't send the :check-protocol-version message. Now
+ handled with CONNECTION-INFO.
+
+ * slime.el (slime-symbol-at-point): Don't skip backwards across
+ whitespace when we are at the first character of a symbol. To
+ handle this case: skip symbol constituents forward before skipping
+ whitespace backwards. Reported by Jan Richter.
+ (slime-connection-close-hook, slime-next-connection)
+ (slime-make-default-connection): Remove extra call to format.
+ (slime-init-connection-state): Use only a single RPC instead of 4.
+
+2004-02-25 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-with-chosen-connection): Bind
+ slime-dispatching-connection and not slime-buffer-connection.
+ slime-buffer-connection is a buffer local variable not a dynamic
+ variable.
+ (slime-find-connection-by-type-name)
+ (slime-read-lisp-implementation-type-name): Were lost during the
+ merge.
+ (sldb-fetch-more-frames): Use (goto-char (point-max)) instead of
+ end-of-buffer.
+
+2004-02-25 Peter Seibel <peter at javamonkey.com>
+
+ * slime.el: Various bits of support for maintaining multiple SLIME
+ connections to different Lisp implementations simultaneously.
+
+ * swank-backend.lisp (lisp-implementation-type-name): Add function to
+ return simple name of lisp implementation; used by new
+ multi-connection functionality in slime.el.
+
+2004-02-25 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (format-arglist): Use a special pprint-dispatch table.
+
+2004-02-22 Lawrence Mitchell <wence at gmx.li>
+
+ * swank.lisp (format-arglist): Bind *PRINT-PRETTY* to NIL.
+ (eval-in-emacs): Fix typo in docstring.
+
+ * swank-cmucl.lisp (arglist-string): Bind *PRINT-PRETTY* to NIL.
+
+2004-02-21 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ Add support for SERVE-EVENT based communication.
+
+ * swank-sbcl.lisp (add-sigio-handler, remove-sigio-handlers):
+ Renamed.
+ (add-fd-handler, remove-fd-handlers): Implement interface.
+
+ * swank-cmucl.lisp (fcntl): New function.
+ (add-sigio-handler, remove-sigio-handlers): Renamed.
+ (add-fd-handler, remove-fd-handlers): Implement interface.
+
+ * swank.lisp (create-connection): Add support for fd-handlers.
+ (install-fd-handler, deinstall-fd-handler): New functions.
+
+ * swank-backend.lisp (add-sigio-handler): Renamed from
+ add-input-handler.
+ (remove-sigio-handlers): Renamed from remove-input-handlers.
+ (add-fd-handler, remove-fd-handlers): New interface functions.
+
+ * slime.el (slime-batch-test): Use sit-for instead of
+ accept-process-output, so that we see something when swank gets
+ compiled. May be problematic in real batch mode.
+ (loop-interrupt-continue-interrupt-quit): Wait a second before
+ interrupting. The signal seems to arrive before the evaluation
+ request if don't wait => the endless loop is executed inside the
+ debugger and sldb-quit will not be processed with fd-handlers.
+
+ * swank.lisp (process-available-input): Move auxiliary function to
+ toplevel. Test if the stream is open.
+ (install-sigio-handler): Handle the first request after installing
+ the signal handler.
+
+ * slime.el (slime-keys): Bind C-c C-x t to slime-list-threads and
+ C-c C-x c to slime-list-connections.
+ (slime): Disconnect before reconnecting if the inferior-lisp
+ buffer wasn't renamed.
+ (slime-connect): Use the host argument and not "localhost".
+ (slime-compilation-finished): Undo last change. Switch to the
+ buffer to remove old annotations.
+ (slime-choose-overlay-region): Ignore errors in
+ slime-forward-sexp.
+
+2004-02-18 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime): Just close the connection when called without
+ prefix-argument. Keeping the connection open doesn't make sense.
+ We could ask if the Lisp process should be killed, though.
+ (slime-maybe-close-old-connections): Delete unused function.
+ (slime-start-swank-server): Use comint-send-string instead of
+ comint-proc-query, 'cause I don't like Olin "100%" Shivers' code.
+ (slime-init-output-buffer): Show some animations.
+ (slime-repl-clear-output): Fixed.
+ (slime-compilation-finished): It's not necessary to switch to the
+ original buffer, because the buffer is encoded in the
+ source-locations.
+ (sldb-show-source): Don't raise an error if the source cannot be
+ located. Print a message instead, because errors in
+ process-filters cause a 1 second delay.
+
+ * swank-cmucl.lisp (read-into-simple-string): Workaround for
+ read-sequence bug in 18e.
+
+2004-02-18 Peter Seibel <peter at javamonkey.com>
+
+ * swank-loader.lisp: Place the fasl files of different
+ implementations in different directories.
+
+2004-02-18 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-clisp.lisp: Update comments about metering package.
+
+ * metering.lisp: Imported from CLOCC. Suggested by Peter Seibel.
+
+2004-02-17 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp, slime.el (make-compiler-note): Don't send the
+ short-message across the wire if the slot is nil.
+
+ * swank-cmucl.lisp (clear-xref-info): Compare the truenames with
+ equalp instead of the unix-truenames. The old version was very
+ inefficient (clearing the tables with about 1000 entries required
+ serveral seconds).
+ (xref-context-derived-from-p, pathname=): Delete unused functions.
+
+ * swank-clisp.lisp (remove-input-handlers):
+ socket:socket-stream-handle is not available on Windows.
+ Reported by Alan Shutko.
+
+ * slime.el (slime-length>): New function.
+ (slime-compiler-notes-to-tree): Don't collapse if there is only
+ one kind of notes.
+
+2004-02-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (make-compiler-note): Include short-message.
+
+ * swank-sbcl.lisp (signal-compiler-condition): Initialize
+ short-message slot.
+ (long-compiler-message-for-emacs): New function.
+
+ * swank-cmucl.lisp (handle-notification-condition): Don't use the
+ context of the previous message.
+ (signal-compiler-condition): Set short message slot.
+ (long-compiler-message-for-emacs): New function.
+ (sigio-handler): Ignore arguments.
+
+ * swank-clisp.lisp (set-sigio-handler, add-input-handler):
+ Conditionalize for linux.
+
+ * swank-backend.lisp (compile-system-for-emacs): Add default
+ implementation.
+ (compiler-condition): New slot short-message.
+
+ * slime.el (slime-compilation-finished): Display compiler notes
+ grouped by severity in a separate buffer.
+ (slime-compilation-finished-continuation, slime-compile-file)
+ (slime-load-system, slime-compile-string): Update callers.
+ (slime-list-compiler-notes, slime-alistify, slime-tree-for-note)
+ (slime-tree-for-severity, slime-compiler-notes-to-tree)
+ (slime-compiler-notes-mode, slime-compiler-notes-quit): New
+ functions.
+ (with-struct, slime-tree): New code for pseudo tree widget.
+ (slime-init-connection-state): Set slime-state-name to "".
+
+2004-02-08 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (create-socket): Fix last fix. Use the proper
+ port argument.
+
+ * swank-allegro.lisp, swank-backend.lisp, swank-clisp.lisp,
+ swank-cmucl.lisp, swank-lispworks.lisp, swank-openmcl.lisp,
+ swank-sbcl.lisp (create-socket): Take interface as argument.
+
+ * slime.el (sldb-show-frame-details): Fix typos.
+ (slime-print-apropos): Don't bind action.
+ (slime-reset): Kill sldb-buffers.
+ (slime-test-find-definition, slime-test-complete-symbol)
+ (slime-test-arglist): Add more slime-check-top-level calls.
+
+ * swank.lisp (setup-server): Pass loopback-interface to
+ create-socket. Reported by Dirk Gerrits.
+ (*loopback-interface*): New parameter.
+ (sldb-loop): Send :debug event inside unwind-protect, so we never
+ lose the corresponding :debug-return event.
+
+2004-02-08 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp (find-source-locations): Eliminate unused
+ variable warning.
+
+ * swank.lisp (swank-pprint): Bind pretty print vars to
+ *swank-pprint-X* counter parts.
+ (*swank-pprint-circle*, *swank-pprint-escape*,
+ *swank-pprint-level*, *swank-pprint-length*): Swank counterparts
+ to *print-X* variables used when swank needs to pretty print a
+ form.
+ (apply-macro-expander): Use swank-pprint.
+
+2004-02-07 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (send, receive, interrupt-thread): Implement
+ more threading functions.
+
+ * swank-sbcl.lisp (inspected-parts): Implemented.
+
+ * slime.el (slime-rex): Mention thread argument in docstring.
+ (sldb-break-with-default-debugger): Use slime-rex and don't switch
+ to the output buffer (happens automatically).
+ (slime-list-threads): Renamed from slime-thread-control-panel.
+ (slime-thread-insert): Use slightly different layout.
+ (slime-give-goahead, slime-waiting-threads)
+ (slime-popup-thread-control-panel, slime-register-waiting-thread)
+ (slime-thread-goahead): Deleted.
+ (slime-maybe-start-multiprocessing): Call
+ swank:startup-multiprocessing. Reported by Paolo Amoroso.
+
+ * swank.lisp (dispatch-event): :debug, :debug-condition,
+ :debug-activate events were all encoded as :debug events, which
+ means the debugger never worked! Fix it. I guess no one uses
+ SLIME with a multithreaded Lisp.
+ (read-user-input-from-emacs): Flush the output before reading.
+ (sldb-loop): Add a sldb-enter-default-debugger tag, so we can
+ enter the default debugger by throwing to it.
+ (sldb-break-with-default-debugger): Throw to
+ sldb-enter-default-debugger.
+ (*thread-list*): New variable.
+ (list-threads): New function.
+
+ * swank-backend.lisp (thread-name): Take a thread object as
+ argument.
+ (thread-status, all-threads, thread-alive-p): New function.
+ (thread-id): Deleted.
+
+ * swank-allegro.lisp, swank-cmucl.lisp, swank-lispworks.lisp,
+ swank-openmcl.lisp, swank-sbcl.lisp: Update for modified thread
+ interface.
+
+ * swank-sbcl.lisp (enable-sigio-on-fd): New function. Use
+ fallback if sb-posix:fcntl isn't fbound.
+
+ * swank-cmucl.lisp (gf-definition-location): Return an error when
+ pathname for the GF is nil (this happens if the GF is not compiled
+ from a file).
+
+ * swank.lisp (undefine-function): New function.
+ (print-with-frame-label, print-part-to-string): Bind
+ *print-circle* to t, to avoid unbound recursion when printing
+ cyclic data structures.
+
+ * slime.el (slime-undefine-function): New command. Bound to C-c
+ C-u.
+
+2004-02-06 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (sldb-setup): Offer to enter a recursive edit if there
+ are pending continuations.
+ (slime-eval): Unwind the stack, thereby exititing recursive edits,
+ before signaling the error.
+
+2004-02-05 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-openmcl.lisp (compile-system-for-emacs): Remove compile
+ time dependency on ASDF.
+
+2004-02-05 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp, swank-loader.lisp: Add profiling support via
+ Kantrowitz's metering package. Reporting needs to be
+ refined (profile-package currently ignores callers-p and methods).
+
+2004-02-04 Bryan O'Connor <bryan-slime at lunch.org>
+
+ * swank-openmcl.lisp (mailbox): Use a semaphore instead of
+ process-wait. Works better with native threads.
+
+2004-02-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-backend.lisp (debugger-info-for-emacs): Export it.
+
+ * swank-sbcl.lisp (add-input-handler): Use fcntl from the sb-posix
+ package.
+
+ * swank.lisp (sldb-loop, dispatch-event, send-to-socket-io): Send
+ a :debug-activate event instead of a :debug event (to avoid
+ sending a potentially long backtrace each time).
+ (handle-sldb-condition): Include the thread-id in the message.
+
+ * slime.el (slime-path): Use load-file-name as fallback.
+ Suggested by Lawrence Mitchell.
+ (slime-dispatch-event): Add support for :debug-activate event.
+ (sldb-activate): New function.
+ (sldb-mode): make-local-hook doesn't seem to work in Emacs 20.
+ Use a buffer local variable instead.
+ (slime-list-connections): Don't print Lisp's state.
+ (slime-short-state-name): Deleted.
+
+2004-02-02 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-debugger): The customization group is called
+ 'slime-debugger', fix referrers. Reported by Jouni K Seppanen.
+
+ * swank.lisp (simple-break): Bind *debugger-hook* before invoking
+ the debugger. Reported by Michael Livshin.
+
+2004-01-31 Robert E. Brown <bbrown at speakeasy.net>
+
+ * swank-sbcl.lisp, swank.lisp: Add more type declarations and
+ detect missing initargs for the connection struct.
+
+2004-01-31 Jouni K Seppanen <jks at iki.fi>
+
+ * slime.el (slime-path): Placed inside an eval-and-compile. Works
+ around some problems when byte-compiling slime-changelog-date.
+
+2004-01-31 Marco Baringer <mb at bese.it>
+
+ * swank-openmcl.lisp: remove defslimefun-unimplemented forms.
+ (call-with-compilation-hooks, compile-system-for-emacs): Implement
+ them.
+ (compile-file-for-emacs, compile-string-for-emacs): Use
+ with-compilation-hooks.
+ (list-callers): Define with defimplementation and not defslimefun.
+
+ * swank-backend.lisp (compile-system-for-emacs): Declare method
+ as part of the interface.
+
+ * slime.el (slime-find-asd): Handle files whose directory does
+ not contain an asdf system definition.
+
+2004-01-31 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ Merge stateless-emacs branch into main trunk. We use now signal
+ driven IO for CMUCL and one thread per request for multithreaded
+ Lisps.
+
+2004-01-31 Robert E. Brown <bbrown at speakeasy.net>
+
+ * swank-backend.lisp, swank-sbcl.lisp,
+ swank-source-path-parser.lisp, swank.lisp: Add type declarations
+ to keep SBCL quiet.
+
+2004-01-29 Michael Weber <michaelw+slime at foldr.org>
+
+ * slime.el, swank-backend.lisp, swank-cmucl.lisp, swank-sbcl.lisp,
+ swank.lisp: Profiler support.
+
+2004-01-23 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-openmcl.lisp: Bind ccl::*signal-printing-errors* to nil
+ inside debugger so that error while printing error take us down.
+
+2004-01-23 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-sbcl.lisp (eval-in-frame, return-from-frame): Implemented.
+ (sb-debug-catch-tag-p): New auxiliary predicate.
+ (source-path<): Delete unused function.
+
+2004-01-23 Michael Weber <michaelw at foldr.org>
+
+ * slime.el (slime-keys): Bind C-c M-p to slime-repl-set-package.
+ (slime-easy-menu): Add entry for slime-repl-set-package.
+
+2004-01-23 Michael Weber <michaelw at foldr.org>
+
+ * slime.el (slime-repl-set-package): New command to set the
+ package in the REPL buffer.
+
+ * swank.lisp (set-package): Return the shortest nickname.
+
+2004-01-23 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (sldb-disassemble): Was lost somewhere.
+
+2004-01-22 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp: Replace defmethod by defimplementation where
+ appropriate.
+ (return-from-frame, restart-frame): Implement them.
+
+2004-01-22 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * test.sh: Copy the ChangeLog file too.
+
+ * swank-cmucl.lisp: Replace some defmethods with
+ defimplementation.
+
+ * swank-allegro.lisp (return-from-frame, restart-name): Implement
+ interface (partly).
+
+ * swank-openmcl.lisp (restart-frame, return-from-frame): Remove
+ sldb-prefix.
+
+ * swank-backend.lisp (return-from-frame, restart-frame):
+ Are now interface functions.
+
+ * swank.asd: Remove dependency on :sb-bsd-sockets. Is already
+ done in swank-sbcl.
+
+ * swank-loader.lisp: Don't reference the swank package at
+ read-time.
+
+ * swank.lisp (completions): Never bind *package* to nil. That's a
+ type error in SBCL.
+ (swank-debugger-hook): Flush the output streams and be careful
+ when accessing *buffer-package*.
+ (create-swank-server): Return the port of the serve socket.
+
+ * swank-lispworks.lisp (interesting-frame-p): Don't print catch
+ frames.
+ (make-sigint-handler): New function.
+ (emacs-connected): Use it.
+
+ * slime.el (slime-lisp-implementation-type): New per connection
+ variable.
+ (slime-handle-oob): Handle debug-condition event. Can be signaled
+ CMUCL when cannot produce a backtrace.
+ (slime-debugging-state): Don't pop up the debugger buffer an
+ activate events. Annoying.
+ (sldb-break-with-default-debugger): Switch to the output buffer
+ before returning to the tty-debugger.
+ (sldb-return-from-frame, sldb-restart-frame): Use slime-rex.
+ (slime-list-connections, slime-short-state-name): New functions.
+
+2004-01-20 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-complete-symbol): Insert the completed-prefix
+ before deleting the original text to avoid troubles with left
+ inserting markers.
+ (slime-symbol-start-pos): Skip backward across symbol
+ constituents.
+ (slime-evaluating-state): [:read-sring] Save the window
+ configuration.
+ (slime-read-string-state): Don't handle activate events
+ (troublesome if, e.g, complete-symbol is used from another
+ buffer). Restore the window configuration.
+ (slime-repl-read-string): Goto the end of buffer.
+ (slime-debugging-state): [:activate] Display the debugger buffer
+ if not visible.
+ (slime-to-lisp-filename, slime-from-lisp-filename)
+ (slime-translate-to-lisp-filename-function)
+ (slime-translate-from-lisp-filename-function, slime-compile-file)
+ (slime-goto-location-buffer, slime-ed, slime-load-file): Support
+ for remote filename translation (untested).
+
+ * swank.lisp (create-swank-server): Take announce-fn as optional
+ argument.
+
+ * swank-allegro.lisp: Replace defmethod with defimplementation.
+ (eval-in-frame): Implemented.
+
+2004-01-20 Lasse Rasinen <lrasinen at iki.fi>
+
+ * slime.el (slime-prin1-to-string): Replacement for
+ prin1-to-string that avoids escaping non-ascii characters in a
+ way that the CL reader doesn't understand. Allows use of 8-bit
+ characters in Lisp expressions with Emacs in unibyte-mode.
+
+2004-01-20 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-eval-print-last-expression): Insert a newline
+ before and after the result.
+ (slime-easy-menu): Added menu items:
+ "Eval Region", "Scratch Buffer", "Apropos Package..."
+ Added some bold to default SLDB faces.
+
+2004-01-19 Alan Ruttenberg <alanr-l at mumble.net>
+ *swank-openmcl.lisp in frame-catch-tags, ppc32::catch-frame.catch-tag-cell -> 0,
+ ppc32::catch-frame.csp-cell -> 3. FIXME when this code is more stable in openMCL.
+
+2004-01-19 Michael Weber <michaelw at foldr.org>
+
+ * slime.el (slime-close-all-sexp): New command to close all
+ unmatched parens in the current defun. Bound to `C-c C-]'. With
+ prefix argument, only operate in the region (for closing
+ subforms).
+
+2004-01-19 Luke Gorrie <luke at bluetail.com>
+
+ * swank-openmcl.lisp (thread-id, thread-name): Fixed silly bugs
+ (thanks Marco Baringer).
+
+ * swank-loader.lisp: Call (swank:warn-unimplemented-interfaces).
+
+ * swank.lisp (ed-in-emacs): New command with the same interface
+ as CL:ED.
+
+ * swank-cmucl.lisp, swank-sbcl.lisp, swank-lispworks.lisp,
+ swank-openmcl.lisp, swank-allegro.lisp, swank-clisp.lisp: Updated
+ to use `defimplementation'.
+
+ * swank-backend.lisp (definterface, defimplementation): New macros
+ as sugar around defgeneric/defmethod. This supports conveniently
+ supplying a default (on NO-APPLICABLE-METHOD). Because the
+ underly mechanism is still generic functions this doesn't break
+ code that isn't updated.
+ (warn-unimplemented-interfaces): Print a list of backend functions
+ that are not implemented.
+ (xref and list-callers): Defined interfaces for these functions.
+ (describe-definition): New function that takes over from the many
+ other describe-* functions called from apropos listing. Takes the
+ type of definition (as returned by describe-symbol-for-emacs) as
+ an argument.
+
+ * slime.el (sldb-enable-styled-backtrace): This is now true by
+ default.
+ (slime-keys): Bound `slime-inspect' to `C-c I'.
+ (slime): `M-x slime' now offers to keep existing connections
+ alive (else disconnect them). If you disconnect them, the new
+ connection gets to reuse the existing REPL.
+ (slime-connection): Error if the connection is closed.
+ (slime-handle-oob): New message (:ED WHAT) for `slime-ed'.
+ (slime-display-output-buffer): Don't pop up the REPL if it is
+ already visible in any frame.
+ (slime-find-asd): Handle case where (buffer-file-name) is nil.
+ (slime-ed): Elisp backend for (CL:ED WHAT).
+ (slime-apropos): Add a summary line to apropos listings.
+ (slime-print-apropos): Replaced `action' property (name of lisp
+ describe function) with `type' (argument to pass to unified
+ swank:describe-definition function).
+ (slime-apropos-package): New command on `C-c P'. Presents apropos
+ listing for all external (with prefix also internal) symbols in a
+ package.
+
+2004-01-18 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (sigint-handler): Bind a continue restart.
+ (make-dspec-location): Handle strings like pathnames.
+ Some multithreading support.
+
+ * slime.el (compile-defun): Don't use keywords. The keyword
+ package is locked in Lispworks and causes the test-suite to hang.
+ (slime-eval-with-transcript): Fix bug triggered when 'package' is
+ a buffer local variable. Reported by Janis Dzerins.
+ (slime-batch-test): Wait until the connection is ready.
+
+2004-01-18 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-openmcl: Implement frame-catch-tags. Added debugger functions
+ sldb-restart-frame, sldb-return-from-frame. Should probably be added to backend.lisp
+ but let's discuss first. Do other lisps support this?
+
+ * slime.el sldb-restart-frame, sldb-return-from-frame
+
+2004-01-18 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp (call-without-interrupts): Evaluate
+ linux:SIGFOO at read time since the macro with-blocked-signals
+ expects a fixnum.
+ (compile-file-for-emacs): Comment fix.
+
+2004-01-18 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-sbcl.lisp (make-fn-streams): Deleted. Already defined in
+ swank-gray.lisp.
+
+ * swank.lisp (find-symbol-or-lose, format-arglist): New functions.
+ (without-interrupts): New macro.
+ (send-to-emacs): Use it.
+
+ * swank-backend.lisp, swank-clisp.lisp, swank-lispworks.lisp,
+ swank-openmcl.lisp, swank-sbcl.lisp, swank-allegro.lisp:
+ (arglist-string): Refactor common code to swank.lisp.
+ (call-without-interrupts, getpid): Are now generic functions.
+
+ * slime.el (arglist): Test slot readers and closures.
+
+ * swank-cmucl.lisp (arglist-string): Use
+ pcl:generic-function-lambda-list for generic functions. Handle
+ closures. Print arglist in lower case.
+ (inspected-parts-of-value-cell): Was lost during the inspector
+ refactoring.
+
+2004-01-18 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp (compile-file-for-emacs,
+ split-compiler-note-line): Revert last change.
+ (handle-notification-condition): Don't signal the condition.
+ (*compiler-note-line-regexp*): Fix and rewrite it as extended
+ regexp.
+
+ * slime.el (slime-changelog-date): Use file-truename of
+ byte-compile-current-file.
+
+2004-01-17 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-format-arglist): Add some sanity checks and
+ print zero argument functions nicer. Suggested by Ivan Boldyrev.
+ (slime-test-expect): Take test predicate as argument.
+ (arglist): Test generic functions.
+
+ * swank-cmucl.lisp (arglist-string): Handle generic functions
+ better. Reported by Ivan Boldyrev.
+
+2004-01-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp: Multiprocessing support.
+
+ * swank-openmcl.lisp, swank-cmucl.lisp, swank-backend.lisp,
+ swank.lisp: Refactor inspector code.
+
+ * swank.lisp (changelog-date): Use *compile-file-truename* instead
+ of *compile-file-pathname*.
+ (with-I/O-lock, with-a-connection): The usual CLISP fixes.
+ (create-swank-server): Patch by Marco Baringer <mb at bese.it>.
+ Bring it back again.
+ (create-connection): Use return the dedicated output stream if
+ available.
+
+ * slime.el: Numerous REPL related fixes.
+ (slime-update-state-name): Take state as argument.
+ (slime-repl-beginning-of-defun, slime-repl-end-of-defun): Fix
+ typos.
+ (sldb-insert-restarts): Remove duplicate definition.
+
+2004-01-16 Luke Gorrie <luke at bluetail.com>
+
+ * swank-openmcl.lisp: Multiprocessing support.
+
+ * swank.lisp (changelog-date): make-pathname portability fix
+ (from alanr).
+ (with-io-redirection): Use (current-connection) instead of
+ *dispatching-connection* (from alanr).
+
+ * slime.el (slime-init-output-buffer): XEmacs portability fix, and
+ use header-line-format to show info about Lisp in Emacs21.
+
+2004-01-15 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-sbcl.lisp, swank-cmucl.lisp (remove-input-handlers): New
+ method.
+
+ * swank-allegro.lisp (excl:stream-read-char-no-hang): Import it.
+ (emacs-connected): Add default method. The method for
+ no-applicable-method doesn't seem to work. ACL bug?
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Don't
+ handle compilation errors. We must compile everything because
+ changelog-date requires *compile-file-truename*.
+
+ * slime.el: (slime-changelog-date)
+ (slime-check-protocol-version): New functions.
+ (slime-handle-oob): Handle :check-protocol-version event.
+ (slime-init-output-buffer): Print some info about the remote Lisp.
+ (slime-connect): Use it.
+ (slime-note-transcript-start): Renamed from
+ slime-insert-transcript-delimiter.
+ (slime-note-transcript-end): New function.
+ (slime-with-output-end-mark, slime-repl-insert-prompt)
+ (slime-repl-show-result, slime-compile-file)
+ (slime-show-evaluation-result): Insert output from eval commands
+ after the prompt and asynchronous output before the prompt. Needs
+ documentation.
+ (repl-test, repl-read, interactive-eval-output): New tests.
+ (slime-flush-output): Accept output from all processes.
+
+ * swank.lisp (serve-requests): New function.
+ (setup-server): Use it.
+ (start-server): Pass backgroud to setup-server.
+ (create-connection): Check the protocol version.
+ (changelog-date): New function.
+ (make-output-function): Use write-string instead of princ.
+
+ * swank-backend.lisp (remove-input-handlers): New function.
+
+2004-01-15 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-aux-connect, slime-handle-oob): Support for
+ (:open-aux-connection port) message where Lisp requests that
+ Emacs make a connection. These are "auxiliary" connections which
+ don't (or at least shouldn't) have their own REPL etc.
+
+ * swank.lisp: New support for multiprocessing and multiple
+ connections + commentary.
+ (with-a-connection): Macro to execute some forms "with a
+ connection". This is used in the debugger hook to automatically
+ create a temporary connection if needed (i.e. if the current
+ thread doesn't already have one).
+ (open-aux-connection): Helper function to create an extra
+ connection to Emacs.
+
+ * swank-sbcl.lisp: Implemented multiprocessing. Not perfect.
+
+ * swank-cmucl.lisp: Implemented new multiprocessing interface.
+ (create-socket): Make FDs non-blocking when multiprocessing is
+ enabled.
+ (startup-multiprocessing): Set *swank-in-background* to :spawn.
+
+ * swank-backend.lisp: Changed multiprocessing interface.
+
+2004-01-15 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp (with-blocked-signals): New macro.
+ (without-interrupts): Use it.
+ (*use-dedicated-output-stream*, *redirect-output*): Don't set them
+ here, use the default settings.
+ Make :linux one of *features* if we find the "LINUX" package.
+
+2004-01-14 Luke Gorrie <luke at bluetail.com>
+
+ * swank-openmcl.lisp (emacs-connected): Typo fix (missing
+ close-paren).
+
+2004-01-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-input-complete-p): Tolerate extra close parens.
+ (slime-idle-state): Don't active the repl.
+ (slime-insert-transcript-delimiter): Insert output before prompt.
+ (slime-open-stream-to-lisp): Initialize the process-buffer with
+ the connection buffer.
+ (slime-repl-activate): Deleted.
+ (slime-repl-eval-string, slime-repl-show-result)
+ (slime-repl-show-abort): Better handling of abortion.
+ (slime-compile-file): Insert output before prompt.
+
+ * swank-lispworks.lisp (create-socket): Fix condition message.
+
+ * swank-openmcl.lisp (*swank-in-background*): Set to :spawn.
+ (emacs-connected): Initialize ccl::*interactive-abort-process*.
+
+ * swank.lisp (*swank-in-background*): New variable.
+ (start-server): Start swank in background, depending on
+ *swank-in-background*.
+
+ * swank-cmucl.lisp, swank-sbcl.lisp (*swank-in-background*): Set
+ to :fd-handler.
+
+ * swank-clisp.lisp (accept-connection): Remove superfluous call to
+ socket-wait.
+
+ New more direct socket interface. The new interface is closer to
+ the functions provided by the implementations. For Lispworks we
+ use some non-exported functions to get a sane interface. The
+ interface also includes add-input-handler and a spawn function
+ (not used yet). The idea is that most of the logic can be shared
+ between similar backends.
+
+ * swank-gray.lisp (make-fn-streams): New function.
+ (stream-read-char-no-hang, stream-read-char-will-hang-p): Moved to
+ here from swank-clisp.lisp.
+
+ * swank-allegro.lisp, swank-clisp.lisp, swank-cmucl.lisp,
+ swank-lispworks.lisp, swank-openmcl.lisp, swank-sbcl.lisp:
+ (create-socket, local-port, close-socket, accept-connection)
+ (add-input-handler, spawn): Implement new socket interface.
+
+ * swank.lisp (start-server, open-dedicated-output-stream &etc):
+ Use new socket functions.
+
+ * swank-backend.lisp (create-socket, local-port, close-socket)
+ (accept-connection, add-input-handler, spawn): New functions.
+ (accept-socket/stream, accept-socket/run): Deleted.
+
+2004-01-13 Luke Gorrie <luke at bluetail.com>
+
+ * swank-clisp.lisp: Updated for new network interface but not
+ tested! Probably slightly broken.
+
+ * swank-lispworks.lisp: Updated for new network interface.
+ (accept-socket/stream): This function is currently broken, so
+ LispWorks can't use the dedicated output channel at the moment.
+
+ * swank.lisp, swank-cmucl.lisp, swank-sbcl.lisp: Updated for new
+ network interface.
+
+ * swank-backend.lisp (accept-socket/stream, accept-socket/run):
+ New functions replacing the ancient (over 24 hours!)
+ `create-socket-server'. This interface is much simpler.
+
+2004-01-12 Luke Gorrie <luke at bluetail.com>
+
+ * swank-lispworks.lisp: Partially updated for new backend
+ interface, but not actually working. The sockets code is broken, I
+ haven't grokked LispWorks the interface properly.
+
+ * swank-gray.lisp (slime-input-stream, slime-output-buffer): Added
+ slots to support the new `make-fn-streams' interface from
+ swank-backend.lisp. These slots need to be initialized by the
+ backend, see swank-sbcl.lisp for an example (very easy).
+
+ * swank-sbcl.lisp (create-socket-server): Implemented new server
+ interface.
+
+ * slime.el (slime-handle-oob): Added
+ :open-dedicated-output-stream message, previously implemented
+ with :%apply.
+ (slime-repl-read-string, slime-repl-return-string): Pass integer
+ argument to `slime-repl-read-mode' to set rather than toggle.
+
+ * swank.lisp: Taking over previously non-portable jobs:
+ (start-server): Now only uses sockets code from the backend.
+ (handle-request): Top-level request loop.
+ (open-dedicated-output-stream): Dedicated output socket.
+ (connection): New data structure that bundles together the things
+ that constitute a connection to Emacs: socket-level stream and
+ user-level redirected streams.
+
+ * swank-cmucl.lisp (create-socket-server): Generic TCP server
+ driven by SERVE-EVENT.
+ (serve-one-request, open-stream-to-emacs): Deleted. Now handled
+ portably in swank.lisp.
+ (make-fn-streams): Implement new stream-redirection interface.
+ (slime-input-stream): New slot referencing output sibling, so it
+ can be forced before input requests.
+
+ * swank-backend.lisp (create-socket-server): Generic
+ callback-driven TCP server interface. Replaces
+ `create-swank-server', with the higher-level logic moved into
+ swank.lisp.
+ (emacs-connected): Invoked when Emacs initially connects, as a
+ hook for backend implementations.
+ (make-fn-streams): Interface for creating pairs of input/output
+ streams that are backended by callback functions. Used to
+ implement redirected-via-Emacs standard I/O streams.
+
+2004-01-12 Lawrence Mitchell <wence at gmx.li>
+
+ * slime.el (slime-events-buffer): Set `hs-block-start-regexp'
+ before running `hs-minor-mode'.
+
+2004-01-10 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (package-updating): Expected package is now a list (can
+ be any), since the shortest nickname is not
+ standardized. e.g. USER or CL-USER for COMMON-LISP-USER.
+
+ * swank-cmucl.lisp: Don't enable xref (let the user decide).
+ (set-fd-non-blocking): Removed unused function.
+ Miscellaneous refactoring of the networking code.
+
+ * slime.el (slime-complete-symbol): Use markers to hold the
+ beginning and end of the completion prefix, in case looking up
+ completions causes insertions (e.g. GC announcements).
+
+2004-01-09 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-activate-state): Only update state name when
+ `slime-default-connection' activates. This fixes an annoying
+ "Selecting deleted buffer" bug that prevented SLIME from being
+ restarted.
+ (slime-next-connection): Fixed a bug where buffer-local connection
+ bindings could get in the way and prevent the connection from
+ actually changing.
+ (slime-complete-restore-window-configuration): Wrap
+ `set-window-configuration' in `save-excursion'. This fixes a
+ problem where the cursor would end up in the wrong place after
+ completion in XEmacs.
+
+2004-01-09 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Place (require 'cl) inside a eval-and-compile.
+ (slime-with-connection-buffer): Move definition upwards before the
+ first use.
+ (package-updateing): New test for package updates in the listeners.
+
+ * swank.lisp (eval-region): Bind *package* outside the
+ unwind-protect to detect updates.
+
+ * swank-backend.lisp (debugger-info-for-emacs)
+ (find-function-locations): Doc fix.
+
+2004-01-09 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp: Add methods for GRAY:STREAM-READ-CHAR-NO-HANG
+ and for the CLISP specific GRAY:STREAM-READ-CHAR-WILL-HANG-P.
+ This should fix the behaviour of SYS::READ-FORM.
+
+2004-01-08 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-inspector-fontify): Function to insert a string
+ in a particular inspector face. Replaces macro-code-generation
+ function `slime-inspector-expand-fontify'. Fixes a byte-compile
+ problem (macro was calling function not defined at compile-time).
+
+2004-01-07 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Multisession internal improvements. Now there are
+ three separate connection variables, in order of priority:
+ slime-dispatching-connection (dynamically-bound)
+ slime-buffer-connection (buffer-local)
+ slime-default-connection (global)
+ The most specific one available is used. This is splitting
+ `slime-connection' into multiple variables, so that you can be
+ specific about what you want to assign (i.e. know if you're
+ setting a dynamic binding or a buffer-local one).
+ Fixed some related bugs.
+ (slime-connection-close-hook): If default connection closes,
+ select another connection.
+ (slime-lisp-package): Initially CL-USER nickname instead of
+ COMMON-LISP-USER (for REPL prompt).
+
+ * slime.el (slime): Multisession support: with prefix argument,
+ gives the option of keeping existing sessions and firing up an
+ additional *inferior-lisp* to connect to. Each connection now has
+ its own *slime-repl[<n>]* buffer.
+ (slime-connection): Should now be read via the function of the
+ same name. The accessor will check if the value is NIL, and if so
+ use `slime-default-connection'.
+ (slime-default-connection): The connection that will be used by
+ default, i.e. unless `slime-connection' is bound. Renamed from
+ `slime-primary-connection'.
+ (slime-init-connection-state): When reconnecting, update the
+ `slime-connection' binding in the REPL to use the new connection.
+ (slime-repl-input-history, ...): REPL variables are now
+ buffer-local.
+
+2004-01-06 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (eval-string): New argument 'id'. Used to identify
+ the remote continuation.
+ (log-event): New debugging function.
+ (read-from-emacs, send-to-emacs): Use it.
+
+ * slime.el: The new macro 'slime-rex' can now be used to evaluate
+ sexps remotely. It offers finer control what to do when the
+ evaluation aborts.
+ (slime-rex): New macro
+ (slime-eval, slime-eval-async, sldb-continue)
+ (sldb-invoke-restart): Use it.
+ (slime-continuation-counter, slime-push-evaluating-state): New
+ functions.
+ (slime-output-buffer): Initialize markers.
+ (sldb-mode): XEmacs doesn't like (add-hook (make-local-hook ...)).
+ (slime-init-connection): New optional argument SELECT.
+ (slime-def-connection-var): Workarounds for Emacs 20 reader bugs.
+ Backquote is pretty broken Emacs 20.
+
+2004-01-06 Ignas Mikalajunas <i.mikalajunas at mbt.lt>
+
+ * swank-loader.lisp (user-init-file): Use merge-pathames. Fix
+ Windows support.
+
+2004-01-05 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Multiple session support, i.e. Emacs can open
+ multiple connections to Lisps. The guts is there, but
+ user-interface is currently minimal.
+ (slime-net-process): Replaced with slime-net-processes.
+ (slime-net-send): Take process as argument.
+ (slime-process-available-input): Poll all connections.
+ (slime-connection): Current connection (process) to use for
+ talking to Lisp. Can be bound dynamically or buffer-local.
+ (slime-with-connection-buffer): Macro to enter the process-buffer
+ of `slime-connection' to manipulate the local variables.
+ (slime-stack-stack): Now buffer-local in the process-buffer of
+ each connection.
+ (slime-push-state, slime-pop-state): Operate on the stack inside
+ `slime-connection's process-buffer.
+ (slime-dispatch-event): Take optional process argument, to bind
+ `slime-connection' appropriately when events arrive from the
+ network.
+ (slime-def-connection-var): Macro to define variables that are
+ "connection-local". Such variables are used via (setf'able)
+ accessor functions, and their real bindings exist as local
+ variables in the process-buffers of connections. The accessors
+ automatically work on `slime-connection'.
+ (slime-lisp-features, slime-lisp-package, slime-pid, sldb-level):
+ These variables are now connection-local.
+ (slime-read-from-minibuffer): Inherit `slime-connection' as
+ buffer-local so that we complete towards the right Lisp.
+ (sldb-mode): Inherit `slime-connection' as buffer-local so that we
+ debug towards the right Lisp.
+ (get-sldb-buffer): New function to return (optionally create) the
+ SLDB buffer for the current connection. Since multiple Lisps can
+ be debugged simultaneously, the buffername now includes the
+ connection number.
+ (slime-connection-abort): New command to abort a connection
+ attempt (don't use `slime-disconnect' anymore - that closes all
+ connections).
+ (slime-execute-tests): Honor `slime-test-debug-on-error'.
+ (slime-next-connection): Cycle through open Lisp connections.
+
+2004-01-02 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-display-output-buffer): Move the output markers
+ to the end of the buffer.
+
+ * swank-clisp.lisp (frame-do-venv): Rename the :symbol property to
+ :name.
+ (format-condition-for-emacs): Replaced with
+ debugger-condition-for-emacs.
+ (backtrace): Use print-with-frame-label.
+
+ * swank-openmcl.lisp (format-condition-for-emacs): Replaced with
+ debugger-condition-for-emacs.
+ (backtrace): Use print-with-frame-label.
+ (frame-locals): Rename the :symbol property to :name.
+
+ * swank-lispworks.lisp (format-condition-for-emacs): Replaced with
+ debugger-condition-for-emacs.
+ (backtrace): Use print-with-frame-label.
+ (frame-locals): Rename the :symbol property to :name.
+
+ * swank-allegro.lisp (frame-locals): Rename the :symbol property
+ to :name.
+ (format-condition-for-emacs): Replaced with
+ debugger-condition-for-emacs.
+ (backtrace): Use print-with-frame-label.
+
+ * swank-sbcl.lisp (tracedp, toggle-trace-fdefinition)
+ (format-condition-for-emacs): Remove unused functions.
+ (format-frame-for-emacs): Use print-with-frame-label.
+ (compute-backtrace): Simplified.
+ (backtrace): Return our frame numbers.
+ (frame-locals): Rename the :symbol property to :name. Remove the
+ :validity property.
+
+ * swank-cmucl.lisp (accept-loop, safe-definition-finding): Doc
+ fix.
+ (location-buffer=, file-xrefs-for-emacs)
+ (sort-contexts-by-source-path, source-path<)
+ (format-condition-for-emacs): Remove unused functions.
+ (format-frame-for-emacs): Don't include the frame number in the
+ description, but use the frame number for indentation. Update
+ callers.
+ (frame-locals): Rename the :symbol property to :name.
+
+ * slime.el (slime-add-face): New function.
+ (sldb-add-face): Use it.
+ (sldb-setup): Some refactoring.
+ (sldb-insert-condition): New function. Factorized from
+ sldb-setup. Message and types are now separate.
+ (sldb-insert-restarts): New function. Factorized from sldb-setup.
+ (sldb-insert-frame): Factorized from slime-insert-frames. The
+ frame number in no longer part of the string describing the frame.
+ (sldb-insert-frames): Use it.
+ (sldb-show-frame-details): Print frame numbers. Fix printing of
+ catch tags. Move to the start of the frame before at the
+ beginning to get unfontified text properties.
+ (sldb-inspect-condition): New command.
+ (sldb-insert-locals): The :symbol property is now called :name.
+ Fix locals with :id attribute.
+ (slime-open-inspector): Fix the bugs I introduced last time.
+
+ * swank.lisp (safe-condition-message): New function.
+ (debugger-condition-for-emacs): Used to be
+ format-condition-for-emacs in each backend. Separate the
+ condition message from the type description. Update all backends
+ accordingly.
+ (print-with-frame-label): New function.
+
+ * slime.el (slime-hyperspec-lookup): New function.
+
+2004-01-02 Wolfgang Jenkner <wjenkner at inode.at>
+
+ * swank-clisp.lisp: New file. Merged with Vladimir's version.
+
+ * xref.lisp: New file. Used by swank-clisp.
+
+ * swank-loader.lisp (user-init-file): Add CLISP files.
+
+ * swank.lisp (eval-region, tokenize-completion): Modify loops a
+ bit to make CLISP happy.
+
+ * swank-backend.lisp (with-compilation-hooks): Replace () with
+ (&rest _) to make CLISP happy.
+
+ * slime.el (slime-goto-source-location): Support for CLISP style
+ line numbers. Split it up.
+ (slime-goto-location-buffer, slime-goto-location-position): New
+ functions.
+ (slime-load-system): Use slime-display-output-buffer.
+ (slime-repl-mode): Disable conservative scrolling. Not sure if it
+ was a good idea.
+ (sldb-insert-frames, sldb-show-frame-details, sldb-list-locals):
+ Minor fixes.
+ (sldb-insert-locals): Renamed from sldb-princ-locals.
+ (sldb-invoke-restart): Use slime-eval instead of
+ slime-oneway-eval, because interactive restarts may read input.
+ (slime-open-inspector): Minor indentation fixes.
+ (slime-net-output-funcall): Removed. Was unused.
+
+2003-12-19 Alan Ruttenberg <alanr-l at mumble.net>
+ * slime.el 1.157
+ fix bug in sldb-princ-locals I introduced when adding fonts to sldb
+
+2003-12-19 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank-openmcl.lisp 1.42
+ in request-loop register output stream to be periodically slushed per Gary Byer's email.
+ * slime.el 1.156
+ slime-goto-source-location. Sometimes source information is recorded but it isn't a standard "def"
+ in that case, don't error out, just look for the most likely place for the definition.
+
+2003-12-19 Luke Gorrie <luke at bluetail.com>
+
+ * null-swank-impl.lisp: Deleted this old file. See
+ swank-backend.lisp instead.
+
+2003-12-18 Alan Ruttenberg <alanr-l at mumble.net>
+ * swank-openmcl.lisp 1.41
+ in openmcl (break) now goes into slime debugger.
+ (setq swank:*break-in-sldb* nil) to disable that.
+
+2003-12-17 Alan Ruttenberg <alanr-l at mumble.net>
+ * slime.el 1.155
+ Allow font choices for backtrack. Add group for customizing them: sldb.
+ Whole thing is enabled with sldb-enable-styled-backtrace which is off by default, for now.
+ Try
+ '(sldb-condition-face ((t (:foreground "DarkSlateGray" :weight bold))))
+ '(sldb-detailed-frame-line-face ((t (:foreground "brown" :weight bold :height 1.2))))
+ '(sldb-local-name-face ((t (:weight bold))))
+ '(sldb-restart-face ((t (:foreground "DarkBlue" :weight bold))))
+ '(sldb-restart-number-face ((t (:underline t :weight bold))))
+ '(sldb-restart-type-face ((t (:foreground "DarkSlateGrey" :weight bold))))
+ '(sldb-section-face ((t (:weight bold :height 1.2))))
+ '(sldb-selected-frame-line-face ((t (:foreground "brown" :weight bold :height 1.2))))
+ '(sldb-topline-face ((t (:foreground "brown" :weight bold :height 1.2))))
+
+2003-12-17 Alan Ruttenberg <alanr-l at mumble.net>
+ * slime.el 1.154
+ Allow some face choices in the inspector. Try
+ '(slime-inspector-label-face ((t (:weight bold))))
+ '(slime-inspector-topline-face ((t (:foreground "brown" :weight bold :height 1.2))))
+ '(slime-inspector-type-face ((t (:foreground "DarkRed" :weight bold))))
+ You can also set slime-inspector-value-face
+
+2003-12-17 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-openmcl.lisp 1.40
+ Fix an error with frame-source-location-for-emacs when the
+ function was a method-function.
+ Defined method-source-location that handles this case. You can
+ still end up looking at the wrong definition, as the protocol
+ doesn't allow passing back the qualifiers and specializers to look
+ up the correct one in the file
+
+. * swank-openmcl.lisp 1.39
+ Allow you to continue after interrupting.
+ Properly set *swank-debugger-stack-frame* when interrupting.
+
+ * slime.el 1.152
+ sldb-continue now uses slime-oneway-eval
+
+2003-12-17 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Better handling of asynchronous output.
+ (slime-output-end): New variable. Use this marker to insert
+ output. Insert asynchronous output inserted before the "input
+ region" and before the prompt.
+ (slime-show-last-output): Use it.
+ (slime-repl-insert-prompt): Initialize it.
+ (slime-last-output-start): Removed.
+ (slime-flush-output): Increase delay to 20 usecs.
+ (slime-with-output-end-mark): Renamed from
+ slime-with-output-at-eob. Insert a newline if needed.
+ (slime-output-string, slime-repl-activate): Use it.
+ (slime-repl-return): Ensure that slime-repl-input-end-mark points
+ to a reasonable location.
+
+2003-12-17 Luke Gorrie <luke at bluetail.com>
+
+ * HACKING: New file summarising our way of working.
+
+2003-12-16 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-lisp-preferred-package-nicknames): Removed. Not
+ very interesting (and slightly broken) now that shortest-nicknames
+ are automatically used.
+ (slime-output-oneway-evaluate-request): New function to evaluate
+ an expression for side-effects (without getting a
+ result).
+ (slime-idle-state): Handle new :emacs-evaluate-oneway.
+ (slime-debugging-state): Handle :emacs-evaluate-oneway.
+ (sldb-invoke-restart): Use slime-oneway-eval. This avoids pushing
+ an evaluating state (which will be aborted, and print an unnecessary
+ message saying so).
+ (sldb-break-with-default-debugger): New command to break into the
+ default TTY debugger. Bound to 'B' in *sldb*.
+ (slime-read-string-state): Added :emacs-evaluate-oneway.
+
+ * swank.lisp (invoke-nth-restart-for-emacs): Wrapper around
+ INVOKE-NTH-RESTART that checks that Lisp and Emacs agree on the
+ debug level. This detects and ignores old restart requests when
+ several are sent at once (possible because of new oneway-eval
+ feature).
+ (oneway-eval-string): New function to evaluate a string without
+ sending a result, and with *DEBUGGER-HOOK* bound to NIL. (The
+ debugger hook is inhibited to avoid state conflicts.)
+
+2003-12-15 Luke Gorrie <luke at bluetail.com>
+
+ * swank-openmcl.lisp (ccl::*warn-if-redefine-kernel*): Support for
+ interrupting the listener (by Alan Ruttenberg).
+
+2003-12-15 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp *start-swank-in-background*: Set to t by default.
+
+ * slime.el (slime-eval-last-expression-display-output): New
+ command. Bound to C-x M-e. Suggested by Nicolas Neuss.
+ (slime-display-output-buffer): New function.
+ (slime-slime-compile-file): Use it.
+
+2003-12-15 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (*processing-rpc*, *multiprocessing-enabled*,
+ *debugger-hook-passback*): New variables.
+ (with-conversation-lock, with-I/O-lock): New macros.
+ (read-next-form): Use with-I/O-lock.
+ (send-to-emacs): Use with-I/O-lock.
+ (swank-debugger-hook): When called asynchronously (i.e. not
+ during RPC) and multiprocessing is enabled, suspend until
+ acknowleged by Emacs.
+ (install-global-debugger-hook): Install a SLIME-DEBUGGER-FUNCTION
+ globally on *DEBUGGER-HOOK*.
+ (startup-multiprocessing-for-emacs): Called to initialize multiprocessing.
+ (eval-string): Dynamically set the *PROCESSING-RPC* flag.
+ (eval-string): Nasty hack with *DEBUGGER-HOOK-PASSBACK* to
+ install debugger hook. Temporary, I swear!
+ (eval-region, shortest-package-nickname): Report the shortest
+ package nickname to Emacs (for the REPL prompt). Patch from Marco
+ Baringer.
+
+ * swank-backend.lisp: Defined multiprocessing interface.
+
+ * swank-cmucl.lisp: Implmemented the multiprocessing interface.
+
+ * slime.el (slime-multiprocessing): When true, use
+ multiprocessing in Lisp if available.
+ (slime-global-debugger-hook): When true, globally set
+ *debugger-hook* to use the SLIME debugger. For use with
+ SERVE-EVENT and multiprocessing.
+ (slime-handle-oob): Handle :AWAITING-GOAHEAD message from threads
+ that have suspended to wait for Emacs's attention.
+ (slime-give-goahead): New command to allow a suspended thread to
+ continue (bound to RET in the thread-control-panel).
+ (slime-thread-control-panel): New command to display a buffer
+ showing all threads that are suspending waiting for Emacs's
+ attention. Bound to `C-c C-x t'.
+ (slime-popup-thread-control-panel): When true, automatically
+ popup the thread-control buffer when a new thread suspends.
+
+2003-12-14 Alan Ruttenberg <alanr-l at mumble.net>
+
+ * swank-openmcl.lisp (eval-in-frame, inspect-object and friends):
+ Most of this is copied from swank-cmucl. The parts between &&&&&
+ are what I added for openmcl. I piggyback off the inspector which
+ is shipped with openmcl, so inspecting won't look the same as it
+ would in cmucl, I imagine. Still, it's a start. eval in frame
+ uses frame-locals to get bindings so if you have debug settings
+ low or don't have *save-local-symbols* set you won't be able to
+ evaluate.
+
+2003-12-14 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (tracedp, toggle-trace-fdefinition): Moved
+ to swank.lisp.
+
+ * swank-allegro.lisp (create-swank-server): Add support for
+ BACKGROUND and CLOSE argument.
+ (call-with-debugging-environment): Use excl::int-newest-frame to
+ avoid the kludge with *break-hook*.
+ (sldb-abort): New function.
+ (frame-source-location-for-emacs): Dummy definition.
+ (compile-file-for-emacs): The argument is called
+ :load-after-compile and not :load.
+ (xref-results-for-emacs): Use dolist instead of loop.
+
+ * swank-openmcl.lisp (create-swank-server): Add support for
+ BACKGROUND and CLOSE argument.
+ (open-stream-to-emacs): Support for dedicated output stream.
+
+ * swank.lisp: *start-swank-in-background*,
+ *close-swank-socket-after-setup*, *use-dedicated-output-stream*:
+ Moved here from swank-cmucl.
+ (sldb-continue): Don't pass the condition as argument, because
+ that doesn't work with Allegro.
+ (toggle-trace-fdefinition, tracedp): Replace backend specific code
+ with portable, but ugly, calls to eval.
+
+ * swank-cmucl.lisp (compile-system-for-emacs): Add method for
+ CMUCL.
+
+ * slime.el (slime-goto-source-location): Better regexp for package
+ qualified symbols. Allow dashes in the name and two colons.
+ Reported by Alan Ruttenberg.
+
+2003-12-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-openmcl.lisp (create-swank-server): Interrupt the right
+ thread. Patch by Alan Ruttenberg. Not yet enabled, due to lack
+ of test platform.
+ (sldb-disassemble): Implement sldb-disassemble command. Patch by
+ Alan Ruttenberg.
+ Remove #' from lambdas.
+
+2003-12-12 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (create-swank-server): New keyword arguments to
+ control the server: BACKGROUND and CLOSE. fd-handlers are used if
+ BACKGROUND is true. If close CLOSE is true, close the socket
+ after the first connection; keep it open otherwise.
+ *start-swank-in-background*, *close-swank-socket-after-setup*: The
+ default values of the corresponding arguments for
+ create-swank-server.
+ (compile-file-for-emacs): Don't load the fasl-file when the
+ compilation failed.
+
+ * swank-openmcl.lisp (toggle-trace-fdefinition, tracedp):
+ Implement trace command. Patch by Alan Ruttenberg.
+ (find-function-locations, find-source-locations): Handle
+ variables, and method-combinations. General cleanups.
+ (source-info-first-file-name): Removed.
+ (list-callers): Fixed.
+ (list-callers): Fixed some more. method-name is not exported in
+ 0.14. From Marco Baringer.
+ (swank-accept-connection): Accept multiple connections. Patch by
+ Marco Baringer.
+
+ * swank-loader.lisp (user-init-file): Use homedir's truename.
+ Reported by Friedrich Dominicus.
+
+ * slime.el (slime-repl-current-input): Don't remove the final
+ newline if we are in reading state.
+ (slime-goto-source-location): Regex-quote the function-name and
+ handle package prefixes. Reported by Alan Ruttenberg.
+ (slime-output-string): Insert asynchronous output before the
+ prompt.
+
+2003-12-12 Daniel Barlow <dan at telent.net>
+
+ * swank-source-path-parser.lisp: new file, excerpting part of
+ swank-cmucl.lisp to where SBCL can find it as well.
+
+2003-12-11 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-one-line-ify): New function to convert
+ multi-line strings to one-liners by replacing any newline
+ followed by indentation by a single space.
+ (slime-xrefs-for-notes): Use it.
+
+2003-12-11 Daniel Barlow <dan at telent.net>
+
+ * swank-sbcl.lisp (compiler-note-location): replace with
+ thinly-ported version from the CMUCL backend which understands
+ :lisp as a pathname
+
+ * slime.el (slime-xrefs-for-notes): a little more temporary
+ variables, a little less cdr. Should be slightly faster on
+ big systems
+ (slime-goto-next-xref): set window point as well as buffer point -
+ now works in GNU Emacs 21.2.1
+
+ * swank.lisp (swank-compiler): new function abstracts commonality
+ between swank-compile-{file, string}.
+ (swank-load-system): call swank-compiler to load asdf system
+
+ * swank-sbcl.lisp (compiler-note-location and elsewhere):
+ remove all trace of *compile-filename*
+ (compile-*-for-emacs): shorten
+
+ * swank-backend.lisp (call-with-compilation-hooks): new GF
+ should set up all appropriate error condition loggers etc
+ to do a compilation preserving the notes. Implement for
+ sbcl, cmucl
+
+ * slime.el (slime-find-asd, slime-load-system): new command
+ to compile and load an ASDF system with all the usual compiler
+ notes and stuff
+ (slime-compilation-finished): if more than one file has new
+ errors/notes, create an xref buffer to show them all
+ (slime-remove-old-overlays): bug fix: now removes overlays even
+ at start of buffer
+ (slime-overlay-note): do nothing quietly if
+ slime-choose-overlay-region returns nil
+ (slime-choose-overlay-region): return nil if note has no location
+
+2003-12-11 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-repl-previous-prompt, slime-repl-next-prompt):
+ New commands. Suggested by Håkon Alstadheim.
+ (slime-repl-beginning-of-defun, slime-repl-end-of-defun): New
+ commands. Suggested by Andreas Fuchs.
+ (slime-repl-insert-prompt): Mark the prompt with a
+ slime-repl-prompt text property.
+ (slime-repl-eol): New function. Mostly for symmetry.
+ (slime-repl-in-input-area-p, slime-repl-at-prompt-end-p): New
+ predicates.
+ (slime-repl-find-prompt, slime-search-property-change-fn): New
+ functions.
+ (slime-ir1-expand): New command.
+
+ * swank-cmucl.lisp (accept-connection, request-loop): Don't use
+ fd-handlers. The code for the request-loop itself is now almost
+ the same as in the Allegro version.
+ (print-ir1-converted-blocks, expand-ir1-top-level): New functions.
+
+2003-12-10 Daniel Barlow <dan at telent.net>
+
+ * swank-sbcl.lisp (serve-request): more fiddling with serve-event
+ descriptors
+
+ * slime.el (slime-repl-return): slime-check-connected, otherwise
+ pressing Return in an unconnected repl gets a bit weird
+
+2003-12-10 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp, swank-lispworks.lisp, swank-openmcl.lisp,
+ swank-sbcl.lisp (create-swank-server): Accept an announce-function
+ keyword argument.
+
+ * swank.lisp (start-server): Pass an announce callback function to
+ create-swank-server. Works better with single threaded
+ implementations.
+ (announce-server-port, simple-announce-function): New functions.
+ (alistify): Doc fix.
+
+ * swank-cmucl.lisp (create-swank-server): Use announce callback.
+ (sldb-disassemble): New function.
+
+ * slime.el (sldb-disassemble): New command. Bound to D.
+
+2003-12-08 Luke Gorrie <luke at bluetail.com>
+
+ * swank-cmucl.lisp (*debug-definition-finding*): Now nil by
+ default, so that errors while looking for definitions are printed
+ as a message and not debugged.
+
+ * slime.el (slime-read-from-minibuffer): Now the only
+ completing-read function, stale ones deleted.
+
+2003-12-07 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-prune-initial-frames): Use regexp-heuristics and
+ the '--more--' token to avoid showing the user Swank-internal
+ backtrace frames initially.
+ (slime-repl-current-input): Don't include the final newline
+ character, to make backtraces prettier.
+ (slime-autodoc): Fixed annoying case where autodocs would be
+ fetched in a loop for undocumented symbols.
+
+ * swank.lisp (compound-prefix-match): New name and rewritten for
+ speed. Completion is much faster now.
+ (*sldb-initial-frames*): Send up to this many (default 20)
+ backtrace frames to Emacs when entering the debugger.
+
+2003-12-07 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp, swank-backend.lisp, swank-cmucl.lisp,
+ swank-lispworks.lisp, swank-openmcl.lisp, swank-sbcl.lisp
+ (function-source-locations): Make it at generic function.
+ (function-source-location-for-emacs): Removed. Fixes bug reported
+ by Marco Baringer.
+
+ * slime.el (slime-interactive-eval): Insert the result at point,
+ if called with prefix argument.
+
+2003-12-06 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-easy-menu): Added menubar support, contributed
+ by Friedrich Dominicus.
+
+2003-12-06 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-allegro.lisp: New file.
+
+ * swank-loader.lisp (user-init-file): Translate logical
+ pathnames. Reported by Friedrich Dominicus.
+
+ * swank-sbcl.lisp (handle-notification-condition): Don't ignore
+ warnings without context.
+ (compiler-note-location, brief-compiler-message-for-emacs,
+ compiler-note-location): Handle null context.
+ (compile-file-for-emacs): Bind *compile-filename* and load the
+ fasl file only if it exists.
+ (function-source-location): The name argument is now optional and
+ should be a symbol.
+ (find-function-locations): Return errors as a list of one error.
+ (call-with-debugging-environment): Set *print-level* to 4 and
+ *print-length* to 10. (Both where nil.)
+ (source-location-for-emacs): Fall back to the location of the
+ function, if there is no debug-block-info.
+ (safe-source-location-for-emacs): Don't catch all conditions; only
+ errors.
+ *compile-filename*: New variable
+ (open-listener): Don't make the socket non-blocking.
+
+ * slime.el (slime-eval/compile-defun-dwim): New command.
+ Suggested by "jan" <janmar at iprimus.com.au>.
+
+2003-12-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-debugging-state): Don't set sldb-level after
+ sldb-setup. Breaks the test-suite.
+ (slime-eval-defun): Fix typos.
+ (slime-xref-buffer, slime-goto-next-xref): Updated for the new
+ xref code.
+ (sldb-inspect-in-frame): Query with the sexp at point as initial
+ value.
+ (sldb-step): New command. Bound to s.
+
+ * swank-cmucl.lisp (format-frame-for-emacs, compute-backtrace,
+ backtrace): Don't send CMUCL's frame numbers to Emacs, use our own
+ numbering.
+ (set-step-breakpoints, sldb-step): Lisp side of sldb-step command.
+
+2003-12-04 Luke Gorrie <luke at bluetail.com>
+
+ * hyperspec.el: Updated URL to point to a live copy of the
+ hyperspec at lispworks.com, because the one on xanalys.com has
+ disappeared. Patch from Vincent Arkesteijn on the ilisp-devel
+ mailing list.
+
+2003-12-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (toggle-trace-fdefinition, tracedp): New
+ support functions for toggle-trace command. Written by Alain
+ Picard.
+ (compile-from-temp-file): Don't delete the binary file if there is
+ none.
+ (lispworks-severity): Map all ERRORs to :error.
+
+ * slime.el (slime-eval-defun): Use slime-re-evaluate-defvar if the
+ defun starts with "defvar". C-M-x in elisp does this too.
+ (slime-re-evaluate-defvar): Take the form as argument.
+
+2003-12-03 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-debugging-state): Initialize the sldb-buffer if
+ (/= sldb-level level).
+ (slime-who-specializes): New command.
+
+ * swank-cmucl.lisp (create-swank-server): Set reuse-address to t
+ by default.
+ (resolve-note-location): Add method for warnings in interpreted
+ code.
+ (who-specializes): New function.
+ (dd-source-location): Handle case without constructors more
+ correctly.
+ (source-path-source-position): Skip ambigous entries in
+ source-map.
+ (source-location-from-code-location): Simplified.
+
+2003-12-03 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-completing-read-internal): Fix from Sean
+ O'Rourke.
+
+2003-12-02 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-sbcl.lisp (find-function-locations): Return a non-empty
+ list of source locations.
+
+ * slime.el (slime-with-xref-buffer): Remove spurious comma. (Bug
+ reported by Raymond Wiker). Some reordering of the xref code.
+
+ * swank.lisp (documentation-symbol): New optional argument for
+ return value if the symbol is not documented.
+
+2003-12-02 Sean O'Rourke <sorourke at cs.ucsd.edu>
+
+ * slime.el: (slime-repl-{clear-buffer,clear-output}): clear the
+ last and entire output in the *slime-repl* buffer
+ (slime-documentation): pop up a buffer with a symbol's
+ documentation instead of its description, if found.
+ (slime-complete-symbol): tweak the completion, taken from ilisp, to
+ complete filenames inside strings.
+ (slime-set-default-directory): also set *slime-repl*'s
+ default-directory, so e.g. find-file makes sense.
+
+2003-12-02 Daniel Barlow <dan at telent.net>
+
+ * slime.el (slime-with-xref-buffer): moved further up the file so
+ it's defined before slime-show-xrefs needs it
+
+ * swank-sbcl.lisp (function-source-location-for-emacs): return a
+ list of source locations (one per method) when the request is
+ for a GF. This seems to make the elisp side popup a window
+ to let the user select one. Cool.
+
+2003-12-01 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-[cmucl,sbcl,openmcl,lispworks].lisp (invoke-nth-restart):
+ Use invoke-restart-interactively.
+
+ * slime.el (slime-create-note-overlay, slime-sexp-depth): The
+ 'priority' property is unused. Remove it.
+
+ * swank-openmcl.lisp (find-function-locations): Return all methods
+ for generic functions. Doesn't work very well if multiple methods
+ are in the same file.
+ (swank-accept-connection): Don't create an extra thread, call
+ request-loop directly.
+
+2003-12-01 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-repl-return): Goto end of input area before
+ inserting newline.
+ (slime-autodoc-message-ok-p): Test to see if a documentation
+ message should be printed (returns nil if the
+ minibuffer/echo-area is already being used).
+ (slime-symbol-at-point): Skip back over whitespace before
+ looking for the symbol.
+ (slime-autodoc-delay): New configurable to specify the delay
+ before printing an autodoc message (default 0.2 secs).
+ (slime-ensure-typeout-frame): New function to call create a
+ typeout frame unless it already exists. Suitable to run on
+ slime-mode-hook if you always want to have a typeout window.
+ (slime-log-events): When nil, don't log events to
+ *slime-events*. This works-around a problem Raymond Toy has when
+ starting SLIME under XEmacs. Still investigating..
+
+2003-11-29 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Rewrite the xref code to work with other source
+ locations.
+ (slime-edit-fdefinition): Use the xref window to display generic
+ functions with methods.
+ (slime-goto-source-location): New representation for source
+ locations. Drop old code.
+ (slime-list-callers, slime-list-callees): Use the xref window.
+ Remove the slime-select-* stuff.
+ (slime-describe-function): New command. Bound to C-c C-f.
+ Primarily useful in Lispworks.
+ (slime-complete-symbol): Display the completion window if the
+ prefix is complete but not unique.
+ (slime-forward-positioned-source-path): Enter the sexp only if the
+ remaining sourcepath is not empty.
+ (slime-read-symbol-name): New optional argument QUERY forces
+ querying.
+
+ * swank.lisp (group-xrefs): Handle unresolved source locations.
+ (describe-symbol): Print something sensible about unknown symbols.
+
+ * swank-cmucl.lisp: Use the new format for source locations.
+ (find-function-locations): New function. Replaces
+ function-source-location-for-emacs. Returns a list of
+ source-locations.
+ (resolve-note-location): Renamed from resolve-location.
+ Simplified.
+ (brief-compiler-message-for-emacs): Print the source context
+ (that's the thing after ==>).
+ (who-xxxx): Take strings, not symbols, as arguments.
+ (function-callees, function-callers): Use the same format as the
+ who-xxx functions. Support for byte-compiled stuff.
+ (code-location-stream-position): Try to be clever is the source
+ path doesn't match the form.
+ (call-with-debugging-environment): Bind *print-readably* to nil.
+
+ * swank-lispworks.lisp: Use the new format for source
+ locations. Implement the find-function-locations.
+ (list-callers, list-callers): New functions.
+
+ * swank-sbcl.lisp, swank-openmcl.lisp: Use the new format for
+ source locations and implement find-function-locations (just calls
+ the old code).
+
+2003-11-29 Daniel Barlow <dan at telent.net>
+
+ * swank-sbcl.lisp (source-location-for-emacs):
+ sb-debug::print-description-to-string takes only two args, not
+ three. Now 'v' command works in sldb :-)
+
+ * slime.el (slime-idle-state): added :debug as a valid transition
+
+ * swank.lisp (slime-debugger-function): New. Returns a function
+ suitable for use as the value of *DEBUGGER-HOOK* to install the
+ SLIME debugger globally. Must be run from the *slime-repl* buffer
+ or somewhere else that the slime streams are visible so that it
+ can capture them. e.g. for Araneida:
+ PKG> (setf araneida:*restart-on-handler-errors*
+ (swank:slime-debugger-fucntion))
+
+2003-11-29 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Some tweaking to the REPL. slime-repl-input-end-mark
+ is now always left inserting and slime-mark-input-end
+ "deactivates" the end mark by moving it to the beginning of the
+ buffer.
+ (slime-goto-source-location): Next try for more uniform
+ source-locations. A source-location is now a structure with a
+ "buffer-designator" and "position-designator". The buffer-designator
+ open the file or buffer and the position-designator moves point to the
+ right position.
+ (slime-autodoc-mode): New command.
+ (slime-find-fdefinitions): Experimental support for generic functions
+ with methods.
+ (slime-show-xrefs, slime-insert-xrefs, slime-goto-xref): Rewritten to
+ work with more general source locations.
+
+ * swank.lisp: Structure definitions for source-locations.
+ (alistify, location-position<, group-xrefs): Utilities for xref
+ support.
+
+ * swank-cmucl.lisp (code-location-source-location): Renamed from
+ safe-source-location-for-emacs.
+ (code-location-from-source-location): Renamed from
+ source-location-for-emacs.
+ (find-fdefinitions, function-source-locations): New functions.
+ (safe-definition-finding): New macro.
+
+ * swank-lispworks.lisp: Xref support.
+ (make-dspec-location): Updated for the new source-location format.
+
+2003-11-29 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (complete-symbol, arglist): Updated test cases for new
+ completion interface.
+
+2003-11-28 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-complete-symbol): Use the new completion
+ support from the Lisp side. Don't obscure minibuffer input with
+ completion messages.
+
+ * completer.el: Dead and buried! Replaced by half a page of Common
+ Lisp. Thanks Bill Clementson for a motivational and well-deserved
+ taunt.
+
+ * swank.lisp (longest-completion): Compute the best partial
+ completion for Emacs.
+
+ * slime.el (slime-swank-port-file): Try (temp-directory),
+ temporary-file-directory, or "/tmp/", depending on what
+ is (f)bound.
+
+2003-11-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp (make-dspec-location): Handle logical
+ pathnames. Reported by Alain Picard.
+
+ * swank-sbcl.lisp, swank-cmucl.lisp: Support for output
+ redirection to an Emacs buffer via a dedicated network stream.
+ Can be enabled with *use-dedicated-output-stream*.
+
+ * swank.lisp (slime-read-string, eval-string): Flush *emacs-io*.
+ (eval-in-emacs): New function.
+
+ * slime.el: Support for output from a dedicated socket.
+ (slime-open-stream-to-lisp, slime-output-filter): New functions.
+ Reorganized REPL code a bit.
+ (slime-input-complete-p): Use vanilla forward-sexp, because
+ slime-forward-sexp sometimes caused endless loops.
+ (slime-disconnect): Close the output-stream-connection if present.
+ (slime-handle-oob): A new :%apply event. Executes arbitrary code;
+ useful for bootstrapping.
+ (slime-flush-output): New function.
+ (slime-symbol-end-pos): Didn't work at all in Emacs20. Just use
+ point until someone commits a proper fix.
+ Various uses of display-buffer: The second argument is different in
+ XEmacs.
+ (interrupt-bubbling-idiot): Reduce the timeout to 5 seconds.
+
+2003-11-27 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-swank-port-file): Use `temporary-file-directory'
+ instead of hardcoding "/tmp/".
+
+2003-11-27 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-lispworks.lisp: New backend.
+
+ * slime.el (slime-with-output-to-temp-buffer): Save the window
+ configuration in a buffer local variable instead on a global
+ stack.
+ (slime-show-last-output): Behavior customizable with
+ slime-show-last-output-function. Various tweaking for better
+ multi-frame support.
+
+ * swank-backend.lisp: List exported symbols explicitly.
+
+ * swank-cmucl.lisp (function-source-location): Better support for
+ generic functions.
+
+ * swank.lisp (briefly-describe-symbol-for-emacs): Don't return
+ unbound symbols.
+ (describe-symbol, describe-function): Support package-qualified
+ strings.
+
+ * swank-loader.lisp: *sysdep-pathnames*: Add Lispworks files.
+ (compile-files-if-needed-serially): Compile all files in a
+ compilation unit.
+
+2003-11-27 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-complete-symbol): Make a bogus alist out of the
+ completion set, for compatibility with XEmacs.
+
+ * completer.el: Stolen^Wimported from ILISP version 1.4. This is
+ one revision prior to their latest, where they added a (require)
+ for some other ILISP code. I backed down a revision to make it
+ stand-alone, but this may mean that putting SLIME in the load-path
+ before ILISP will break ILISP. So, beware.
+ (completer-message): Cut dependency on undefined ilisp constant
+ testing for xemacs.
+
+2003-11-27 Zach Beane <xach at xach.com>
+
+ * swank.lisp (completions): Complete compound symbols (see below).
+
+ * slime.el (slime-complete-symbol): Use `completer' package to
+ handle more sophisticated completions. This includes abbreviations
+ like "m-v-b" => "multiple-value-bind". It also (somewhat scarily)
+ redefines other standard Emacs completion functions with similar
+ capabilities. See commentary in completer.erl for details.
+
+2003-11-25 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-make-typeout-frame): New command to create a
+ frame where commands can print messages that would otherwise go to
+ the echo area.
+ (slime-background-message): Function for printing "background"
+ messages. Uses the "typeout-frame" if it exists.
+ (slime-arglist): Print arglist with `slime-background-message'.
+ (slime-message): Use typeout frame if it exists, but only for
+ multi-line messages.
+
+2003-11-25 Daniel Barlow <dan at telent.net>
+
+ * swank-sbcl.lisp: delete big chunk of leftover commented-out
+ code
+
+ * slime.el: arglist command to use slime-read-symbol-name,
+ not slime-read-symbol
+
+ * README: Minor updates for currency
+
+2003-11-24 Luke Gorrie <luke at bluetail.com>
+
+ * swank-backend.lisp (compiler-condition): Removed use of
+ :documentation slot option. That is not portable (to CMUCL 18e).
+
+ * swank.lisp (eval-string-in-frame): Fixed symbol-visibility
+ problem (thanks Lawrence Mitchell).
+
+ * swank-sbcl.lisp (function-source-location): Use TRUENAME to
+ resolve source file name (thanks Lawrence Mitchell).
+
+ * slime.el (slime-goto-source-location): Fixes when finding
+ definition by regexp: open the right file (was missed), and
+ tweaked regexp to match more 'def' forms - especially
+ `defmacro-mundanely' (hyphen wasn't allowed before).
+
+2003-11-23 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-fetch-more-frames): Call swank:backtrace instead
+ of (renamed) swank:backtrace-for-emacs.
+
+ * swank-cmucl.lisp, swank-sbcl.lisp, swank-openmcl-lisp: Updated
+ to use new debugger interfaces in swank-backend.lisp.
+
+ * swank-backend.lisp (backtrace, eval-in-frame, frame-catch-tags,
+ frame-locals, frame-source-location-for-emacs): More interface
+ functions.
+
+ * slime.el (slime-goto-source-location): Added optional `align-p'
+ argument for :file and :emacs-buffer location types. This is for
+ OpenMCL - unlike CMUCL its positions are not character-accurate so
+ it needs to be aligned to the beginning of the sexp.
+ (slime-connect): Don't delete a random window when *inferior-lisp*
+ isn't visible.
+
+ * swank-cmucl.lisp: Tidied up outline-minor-mode structure and
+ added comments and docstrings.
+
+ * swank-cmucl.lisp, swank-sbcl.lisp, swank-openmcl-lisp: Updated
+ to use new debugger interface in swank-backend.lisp.
+
+ * swank-backend.lisp (call-with-debugging-environment,
+ sldb-condition, debugger-info-for-emacs): More callbacks defined.
+
+ * swank.lisp: Tidied up outline-minor-mode structure, added
+ comments and docstrings.
+ (sldb-loop): Took over the main debugger loop.
+
+ * swank-openmcl.lisp: Updated after refactoring of other backends
+ (was broken).
+
+ * slime.el (slime-goto-source-location): Align at beginning of
+ sexp after (:file name pos) and (:emacs-buffer buffer pos).
+
+ * swank-sbcl.lisp (describe-symbol-for-emacs): Don't ask for
+ (documentation SYM 'class), CLHS says there isn't any 'class
+ documentation (and SBCL warns).
+
+ * swank.lisp, swank-cmucl.lisp, swank-sbcl.lisp: Refactored
+ interface through swank-backend.lisp for: swank-compile-file,
+ swank-compile-string, describe-symbol-for-emacs (apropos),
+ macroexpand-all, arglist-string.
+
+ * swank-backend.lisp: New file defining the interface between
+ swank.lisp and the swank-*.lisp implementation files.
+
+2003-11-22 Brian Mastenbrook <bmastenb at cs.indiana.edu>
+
+ * swank.asd: ASDF definition to load "swank-loader.lisp". This is
+ useful for starting the Swank server in a separate Lisp and later
+ connecting with Emacs. The file includes commentary.
+
+2003-11-22 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-connect): Slightly reordered some window
+ operations to ensure that *slime-repl* is popped up after `M-x
+ slime-connect'.
+ (slime-show-last-output): If the *slime-repl* buffer is already
+ visible in any frame, don't change anything.
+
+ * swank.lisp (listener-eval): Format results in *buffer-package*.
+ Exporting (CREATE-SWANK-SERVER <port>). This function can be
+ called directly to start a swank server, which you can then
+ connect to with `M-x slime-connect'. It takes a port number as
+ argument, but this can be zero to use a random available port.
+ The function always returns the actual port number being used.
+
+2003-11-19 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp: Better printing off return values. In the REPL
+ buffer we print now every value in a separate line and in the echo
+ area separated by a comma. We also print "; No value" for the
+ degenerated case (values). A new variable *sldb-pprint-frames*
+ controls the printing of frames in the debugger. (Thanks Raymond
+ Toy for the suggestions.)
+
+ * swank-cmucl.lisp (format-frame-for-emacs): Bind *pretty-print*
+ to *sldb-pprint-frames*.
+
+ * slime.el: Window configuration are now saved on a stack, not in
+ a single global variable.
+ (slime-with-output-to-temp-buffer) We use now our own version of
+ with-output-to-temp-buffer. The default version is painfully
+ incompatible between Emacs versions. The version selects the
+ temporary buffer and the behaivor of "q" is now more consistent
+ (as suggested by Jan Rychter).
+ (slime-connect): Hide the *inferior-lisp-buffer* when we are
+ connected.
+ sldb-mode-map: Bind n and p to sldb-down and sldb-up.
+ (slime-edit-fdefinition-other-window): New function. Suggested by
+ Christian Lynbech.
+
+ * swank-loader.lisp (user-init-file): There is now a user init
+ file (~/.swank.lisp). It is loaded after the other files.
+
+2003-11-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: [slime-keys] Override C-c C-r with slime-eval-region
+ (reported by Paolo Amoroso).
+
+ * swank-loader.lisp: Compile and load gray stream stuff for SBCL
+ and OpenMCL.
+
+ * swank-openmcl.lisp, swank-sbcl.lisp: Import gray stream symbols.
+ (without-interrupts*): New function.
+
+ * swank.lisp (send-to-emacs): Protect the write operations by a
+ without-interrupts, so that we don't trash the *cl-connection*
+ buffer with partially written messages.
+
+ * swank-cmucl.lisp (without-interrupts*): New function.
+
+ * swank-gray.lisp (stream-write-char): Don't flush the buffer on
+ newlines.
+
+ * slime.el: Add some docstring.
+ (interrupt-bubbling-idiot): New test.
+ [slime-keys]: Don't bind "\C- ". Problematic on LinuxPPC.
+
+2003-11-15 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Some tweaking for better scrolling in the *slime-repl*
+ buffer (suggested by Jan Rychter).
+ (slime-compile-file): Display the output buffer at the beginning.
+ (slime-show-last-output): Include the prompt so that window-point
+ is updated properly.
+ (slime-with-output-at-eob): Update window-point if the buffer is
+ visible.
+ (slime-state/event-panic): Include the *slime-events* and
+ *cl-connection* buffers in the report.
+
+ * swank-cmucl.lisp (sos/out): Don't flush the buffer on newlines.
+
+2003-11-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Imititate an "output-mark". Output from Lisp should
+ move point only if point is at the end of the buffer. (Thanks
+ William Halliburton for the suggestion.)
+ (slime-with-output-at-eob): New function.
+ (slime-output-string, slime-repl-maybe-prompt): Use it.
+
+ slime-repl-mode-map: Override "\C-\M-x".
+
+ An experimental scratch buffer:
+ (slime-eval-print-last-expression): New function.
+ (slime-scratch-mode-map, slime-scratch-buffer,
+ slime-switch-to-scratch-buffer, slime-scratch): New functions.
+
+ * swank-cmucl.lisp (resolve-location): Emacs buffer positions are
+ 1 based. Add 1 to the 0 based file-position.
+
+2003-11-13 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-connect): pop-to-buffer into *slime-repl* when
+ we connect.
+
+2003-11-13 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el, swank-cmucl.lisp, swank-sbcl.lisp, swank-openmcl: New
+ representation for "source-locations". Compiler notes have now a
+ message, a severity, and a source-location field. Compiler notes,
+ edit-definition, and the debugger all use now the same
+ representation for source-location. CMUCL does the source-path to
+ file-position translation at the Lisp side. This works better
+ with reader macros, in particular with backquote. The SBCL
+ backend still does the translation on the Emacs side. OpenMCL
+ support is probably totally broken at the moment
+
+2003-11-13 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-repl-previous-input, slime-repl-next-input):
+ When partial input has already been entered, the M-{p,n} REPL
+ history commands only match lines that start with the
+ already-entered prefix. This is comint-compatible behaviour which
+ has been requested. The history commands also skip over line
+ identical to the one already entered.
+ (slime-complete-maybe-restore-window-confguration): Catch errors,
+ so that we don't cause `pre-command-hook' to be killed.
+ (slime-truncate-lines): If you set this to nil, slime won't set
+ `truncate-lines' in buffers like sldb, apropos, etc.
+
+2003-11-12 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-show-description): XEmacs portability: don't use
+ `temp-buffer-show-hook'.
+ (slime-inspect): Use `(slime-sexp-at-point)' as default inspection
+ value (thanks Jan Rychter).
+
+2003-11-10 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-post-command-hook): Inhibit unless (still) in
+ slime-mode. Only call `slime-autodoc-post-command-hook' when
+ `slime-autodoc-mode' is non-nil.
+ (slime-setup-command-hooks): Use `make-local-hook' instead of
+ `make-local-variable'.
+
+2003-11-08 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: slime-highlight-face: Use the :inherit attribute if
+ possible.
+ (slime-face-inheritance-possible-p): New function.
+
+ * slime.el (slime-repl-return): Only send the current input to
+ Lisp if it is a complete expression, like inferior-slime-return.
+
+ * swank.lisp (completions): Use *buffer-package* if no other
+ package is given.
+
+ * slime.el: Remove the non-working face inheriting stuff.
+ Hardcode colors for slime-highlight-face and specify the :inherit
+ attribute for slime-repl-output-face. So Emacs21 will do the
+ right thing and the others get at least a customizable face.
+
+ * slime.el (slime-buffer-package): Try to find be the
+ package name before resorting to slime-buffer-package. Return nil
+ and not "CL-USER" if the package cannot be determined.
+ (slime-goto-location): Insert notes with a source path, but
+ without filename or buffername, at point. This can happen for
+ warnings during macro expansion. (The macro expander is a
+ interpreted function and doesn't have a filename or buffername.)
+ (slime-show-note): Display 2 double quotes "" in the echo area for
+ zero length messages. SERIES tends to signal warnings with zero
+ length messages.
+ (slime-print-apropos): Add support for alien types.
+
+ * swank-cmucl.lisp (briefly-describe-symbol-for-emacs): Add
+ support for alien types.
+ (source-path-file-position): Read the entire expression with a
+ special readtable. The readtable records source positions for
+ each sub-expression in a hashtable. Extract the sub-expression
+ for the source path from the read object and lookup the
+ sub-expression in the hashtable to find its source position.
+
+ * swank-sbcl.lisp (swank-macroexpand-all): Implemented.
+
+2003-11-06 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-autodoc-mode): When non-nil, display the
+ argument list for the function-call near point each time the point
+ moves in a slime-mode buffer. This is a first-cut; more useful
+ context-sensitive help to follow (e.g. looking up variable
+ documentation).
+ (slime-autodoc-cache-type): Cache policy "autodoc" documentation:
+ either nil (no caching), 'last (the default - cache most recent
+ only), or 'all (cache everything on symbol plists forever).
+
+ * slime.el: Convenience macros:
+ (when-bind (var exp) &rest body)
+ => (let ((var exp)) (when var . body))
+ (with-lexical-bindings (var1 ...) . body)
+ => (lexical-let ((var1 var1) ...) . body)
+
+ * slime.el (slime, slime-lisp-package): Reset `slime-lisp-package'
+ (the REPL package) when reconnecting.
+ (slime-buffer-package): Return `slime-lisp-package' when the
+ major-mode is `slime-repl-mode'.
+
+2003-11-04 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-read-string-state): Add support for evaluation
+ requests.
+ (slime-repl-read-break): New command.
+ alternative.
+ slime-keys: XEmacs cannot rebind C-c C-g. Use C-c C-b as an
+ alternative.
+ (slime-selector): XEmacs has no prompt argument for read-char.
+ (slime-underline-color, slime-face-attributes): Make face
+ definitions compatible with XEmacs and Emacs20.
+ (slime-disconnect): Delete the buffer of the socket.
+ (slime-net-connect): Prefix the connection buffer name with a
+ space to avoid accidental deletion.
+
+ * swank.lisp (slime-read-string): Send a :read-aborted event for
+ non-local exits.
+ (case-convert): Handle :invert case better.
+
+2003-11-03 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-display-message-or-view,
+ slime-remove-message-window): Display too long lines in a new
+ window. Add a temporary pre-command-hook to remove the multiline
+ window before the next command is executed.
+
+ (slime-complete-symbol): Save the window configuration before
+ displaying the completions and try to restore it later. The
+ configuration is restored when: (a) the completion is unique (b) there
+ are no completion. It is also possible to delay the restoration until
+ (c) certain characters, e.g, space or a closing paren, are inserted.
+
+ (slime-selector): Don't abort when an unkown character is pressed;
+ display a message and continue. Similiar for ?\?. Add a selector for
+ the *sldb* buffer.
+
+ (slbd-hook, sldb-xemacs-post-command-hook): Emulate Emacs'
+ point-entered text property with a post-command hook.
+
+ * swank.lisp (case-convert, find-symbol-designator): New
+ functions.
+
+ * swank-cmucl.lisp, swank-openmcl.lisp, swank-sbcl.lisp
+ (arglist-string): Don't intern the function name. Use
+ find-symbol-designator instead.
+
+2003-11-03 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-display-buffer-region): Hacked to fix completely
+ inexplicable XEmacs problems.
+
+2003-11-2 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * null-swank-impl.lisp, swank-cmucl.lisp, swank-openmcl.lisp,
+ swank.lisp: Input redirection works now on the line level, like a
+ tty. Output streams are now line buffered. We no longer compute
+ the backtrace-length.
+
+ * slime.el:
+ (slime-repl-read-mode, slime-repl-read-string, slime-repl-return,
+ slime-repl-send-string, slime-read-string-state,
+ slime-activate-state): Reorganize input redirection. We no longer
+ work on the character level but on a line or region; more like a
+ terminal. This works better, because REPLs and debuggers are
+ usually written with a line buffering tty in mind.
+ (sldb-backtrace-length, slime-debugging-state,
+ slime-evaluating-state, sldb-setup, sldb-mode, sldb-insert-frames,
+ sldb-fetch-more-frames): Don't use backtrace-length. Computing
+ the length of the backtrace is (somewhat strangely) an expensive
+ operation in CMUCL, e.g., it takes >30 seconds to compute the
+ length when the yellow zone stack guard is hit.
+
+2003-11-02 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-log-event): Added a *slime-events* buffer
+ recording all state machine events. The buffer uses hideshow-mode
+ to fold messages down to single lines.
+ (slime-show-source-location): Bugfix: only create source-highlight
+ overlay if the source was actually located.
+ (slime-selector): Renamed from `slime-select' because that
+ function name was already in use. Ooops!
+
+ * swank.lisp (eval-string): force-output on *slime-output* before
+ returning the result. This somewhat works around some trouble
+ where output printed by lisp is being buffered too long.
+
+ * slime.el (slime-lisp-package-translations): Association list of
+ preferred package nicknames, for the REPL prompt. By default maps
+ COMMON-LISP->CL and COMMON-LISP-USER->CL-USER.
+
+2003-11-01 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-select): Added an extensible "Select" command,
+ which I gather is a LispM/Martin-Cracauer knock-off. When invoked,
+ the select command reads a single character and uses that to
+ decide which buffer to switch to. New characters can be defined,
+ and the currently availables ones can be seen with '?'. I have not
+ assigned a key to Select, because it seems like a command that
+ should have a global binding. I would suggest `C-c s'.
+
+ * swank.lisp (*slime-features*): Variable remembering the FEATURES
+ list.
+ (sync-state-to-emacs): Update Emacs about any state changes -
+ currently this just means changes to the FEATURES list.
+ (eval-string): Call `sync-state-to-emacs' before sending result.
+ (eval-region): With optional PACKAGE-UPDATE-P, if the evaluation
+ changes the current package, tell Emacs about the new package.
+ (listener-eval): Tell `eval-region' to notify Emacs of package
+ changes, so that e.g. (in-package :swank) does the right thing
+ when evaluated in the REPL.
+
+ * slime.el (slime-repl-output-face, slime-repl-input-face): Face
+ definitions for output printed by Lisp and for previous REPL user
+ inputs, respectively. Defaulting the input face to bold rather
+ than underline, because it looks better on multi-line input.
+ (slime-handle-oob): Two new out-of-band messages
+ (:new-features FEATURES) and (:new-package PACKAGE-NAME). These
+ are used for Lisp to tell Emacs about changes to *FEATURES* and
+ *PACKAGE* when appropriate.
+ (slime-same-line-p): Better implementation (does what the name
+ suggests).
+ (slime-lisp-package): New variable keeping track of *PACKAGE* in
+ Lisp -- or at least, the package to use for the REPL.
+ (slime-repl-insert-prompt): The prompt now includes the package
+ name.
+ (slime-repl-bol): C-a in the REPL now stops at the prompt.
+ (slime-repl-closing-return): C-RET & C-M-m now close all open
+ lists and then send input in REPL.
+ (slime-repl-newline-and-indent): C-j in REPL is now better with
+ indentation (won't get confused by unmatched quotes etc appearing
+ before the prompt).
+
+2003-11-1 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-debugging-state): Save the window configuration
+ in a state variable.
+ sldb-saved-window-configuration: Removed.
+ (slime-repl-mode): Use conservative scrolling.
+ (slime-repl-insert-prompt): Set window-point after the prompt.
+ (slime-repl-add-to-input-history): Don't add subsequent duplicates to
+ the history.
+
+ * swank.lisp (slime-read-char): Flush the output before reading.
+ (listener-eval): Like eval region but set reader variables (*, **,
+ *** etc.)
+
+ * swank-openmcl.lisp, swank-sbcl.lisp: Implement stream-line-column.
+
+ * swank-cmucl.lisp (slime-input-stream-misc-ops): Renamed from
+ slime-input-stream-misc.
+
+2003-10-31 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-repl-mode-map): Bound `slime-interrupt' on both
+ C-c C-c and C-c C-g.
+
+ * swank.lisp (interactive-eval): Evaluate in *buffer-package*.
+
+ * slime.el: Tweaked debugger window management somewhat: the
+ window configuration is saved when the debugger is first entered
+ and then restored when the idle state is reached.
+
+2003-10-31 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: (slime-repl-read-mode, slime-repl-read-xxx): New minor
+ mode for stream character based input to Lisp.
+
+ * swank.lisp: *read-input-catch-tag*, take-input, slime-read-char:
+ Moved here from swank-cmucl.lisp.
+ (defslimefun, defslimefun-unimplemented): Move macro definitions to
+ the beginning of the file.
+
+ * swank-cmucl.lisp: (slime-input-stream, slime-input-stream-read-char,
+ lime-input-stream-misc): Character input stream from Emacs.
+ (slime-input-stream/n-bin): Removed.
+
+ * swank-openmcl.lisp, swank-sbcl.lisp: Gray stream based input
+ redirection from Emacs.
+
+2003-10-29 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el:
+ Beginnings of a REPL-mode.
+ Minor debugger cleanups.
+
+ * swank.lisp:
+ slime-read-error: New condition.
+ (read-next-form): Re-signal the conditions as slime-read-errors. And
+ check the result of read-sequence (i.e. detect CMUCL's read-sequence
+ bug).
+ (sldb-continue, throw-to-toplevel): Was more or less the same in all
+ backends.
+
+ * swank-openmcl.lisp, swank-sbcl.lisp, swank-cmucl.lisp:
+ (serve-request): Handle slime-read-errors and bind a
+ slime-toplevel catcher.
+
+ * swank-cmucl.lisp:
+ (sldb-loop): Flush output at the beginning.
+ (inspect-in-frame): New function.
+ (frame-locals): Don't send the validity indicator across wire. Too
+ cmucl specific.
+
+2003-10-29 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-net-sentinel): Only show a message about
+ disconnection if the inferior-lisp is still running.
+ (slime-interrupt, slime-quit): Only send the quit/interrupt
+ message to Lisp if it is in fact evaluating something for us. This
+ fixes a protocol bug reported by Paolo Amoroso. Added (require
+ 'pp).
+
+2003-10-28 James Bielman <jamesjb at jamesjb.com>
+
+ * null-swank-impl.lisp: New file.
+
+ * swank-openmcl.lisp: Pre-refactoring updates to the OpenMCL backend:
+ (map-backtrace): Renamed from DO-BACKTRACE.
+ (frame-source-location-for-emacs): New function.
+ (function-source-location-for-emacs): New function,
+
+ * swank-openmcl.lisp: Docstring updates/additions.
+
+2003-10-25 Luke Gorrie <luke at bluetail.com>
+
+ * Everywhere: Changed the connection setup to use a dynamic
+ collision-free TCP port. The new protocol is this:
+
+ Emacs calls (swank:start-server FILENAME) via the
+ listener. FILENAME is /tmp/slime.${emacspid}
+ Lisp starts a TCP server on a dynamic available port and writes
+ the port number it gets to FILENAME.
+ Emacs asynchronously polls for FILENAME's creation. When it
+ exists, Emacs reads the port number, deletes the file, and makes
+ the connection.
+
+ The advantage is that you can run multiple Emacsen each with an
+ inferior lisp, and the port numbers will never collide and Emacs
+ will always connect to the right lisp.
+
+ All backends are updated, but only CMUCL and SBCL are
+ tested. Therefore, OpenMCL is almost certainly broken just now.
+
+ * slime.el (inferior-slime-closing-return): New command that
+ closes all open lists and sends the result to Lisp. Bound to C-RET
+ and (for people who use C-m for RET) C-M-m.
+ (inferior-slime-indent-line): Improved indentation in the inferior
+ list buffer.
+
+2003-10-24 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (inferior-slime-return): Command bound to RET in
+ inferior-slime-mode: only send the current input to Lisp if it is
+ a complete expression (or prefix argument is given). Two reasons:
+ it makes the input history contain complete expressions, and it
+ lets us nicely indent multiple-line inputs. (Thanks Raymond Toy
+ for the suggestions.)
+
+2003-10-23 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-maybe-start-lisp): Restart inferior-lisp if the
+ process has died.
+
+ * swank-sbcl.lisp (accept-connection): Use a character stream to
+ match swank.lisp.
+
+2003-10-22 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp (setup-request-handler): Create a character
+ stream.
+ (read-next-form): Removed.
+
+ * swank.lisp (read-next-form, send-to-emacs): Assume *emacs-io* is
+ a character stream. Add the necessary char-code/code-char
+ conversions.
+
+ * slime.el: slime-keys: Add :sldb keywords for keys useful in the
+ debugger.
+ (slime-init-keymaps): Allow allow :sldb keywords.
+
+ inferior-lisp-mode-hook: Display the inf-lisp buffer if there is
+ some output.
+
+ (slime-process-available-input): Start a timer to process any
+ remaining input.
+ (slime-dispatch-event): The timer should take care of any lost
+ input. So don't process the available input here. Remove the
+ process-input argument.
+ (slime-push-state, slime-pop-state, slime-activate-state,
+ slime-idle-state, slime-evaluating-state): Update callers.
+ (slime-debugging-state): Remove the unwind-protect in the
+ :debug-return clause. Should not be necessary.
+
+ sldb-mode-map: Define more slime-mode keys.
+
+ (slime-time<, slime-time-add): Removed. Emacs-21 has equivalent time
+ functions.
+ (slime-sync-state-stack): Use Emacs-21 time-date functions.
+ (seconds-to-time, time-less-p, time-add): Compatibility defuns.
+
+2003-10-22 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime): With a prefix argument, prompt for the port
+ number to use for communication with Lisp. This is remembered for
+ future connections.
+
+2003-10-22 Hannu Koivisto <azure at iki.fi>
+
+ * slime.el (slime-space): Now allows one to insert several spaces
+ with a prefix argument.
+
+2003-10-21 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-space): Don't give an error when not connected,
+ to avoid feeping.
+
+ * swank-sbcl.lisp (swank-compile-string): Include only one
+ :SOURCE-PATH attribute in the plist, and replace the front element
+ with a 0 (fixes a problem probably due to recent hacks to the
+ elisp source-path lookups).
+
+ * slime.el (inferior-slime-mode): New minor mode for use with
+ `inferior-lisp-mode'. Defines a subset of the `slime-mode' keys
+ which don't clash with comint (e.g. doesn't bind M-{p,n}).
+ (slime-keys): List of keybinding specifications.
+ (slime-find-buffer-package): If we don't find the "(in-package" by
+ searching backwards, then try forwards too.
+
+ * swank.lisp (completions): Fixed semantics: should now consider
+ only/all completions that would not cause a read-error due to
+ symbol visibility. Also avoiding duplicates and sorting on
+ symbol-name.
+
+2003-10-20 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (completions): Slight change of semantics: when a
+ prefix-designator is package-qualified, like "swank:", only match
+ symbols whose home-package matches the one given - ignore
+ inherited symbols.
+
+ * slime.el: Updated test suite to work with the different backends:
+ (find-definition): Lookup definitions in swank.lisp.
+ (arglist): Lookup arglists of functions in swank.lisp.
+
+2003-10-20 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (interactive-eval): Make test case independent of
+ *print-case*.
+
+2003-10-20 Luke Gorrie <luke at bluetail.com>
+
+ * swank-cmucl.lisp (clear-xref-info): Conditionalised
+ xref:*who-is-called* and xref:*who-macroexpands* with
+ #+CMU19. This makes SLIME compatible with CMUCL 18e, but also
+ disables the `who-macroexpands' command in any CMUCL version that
+ doesn't have the "19A" feature (which does break the command in
+ some snapshot builds that can actually support it).
+
+2003-10-20 Daniel Barlow <dan at telent.net>
+
+ * swank.lisp (*notes-database*): tyop fix
+
+ * swank-sbcl.lisp (throw-to-toplevel): select TOPLEVEL restart
+ instead of throwing to a catch that no longer exists
+
+ * slime.el: change some strings containing 'CMUCL' to more
+ backend-agnostic phrases
+
+2003-10-19 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el, swank-cmucl.lisp, swank.lisp: First shoot at input
+ redirection.
+
+ * swank-sbcl.lisp, swank-openmcl.lisp: Bind *slime-input* and
+ *slime-io* to dummy values.
+
+2003-10-19 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime): Connection setup is now asynchronous, with
+ retrying on a timer. This makes it possible to bring the server up
+ by hand while debugging. `M-x slime' while already connected will
+ cause the old connection to be dropped and a new one established.
+ (slime-disconnect): New command to disconnect from Swank, or
+ cancel asynchronous connection attempts when not yet connected.
+ (slime-state/event-panic): Illegal events in the communication
+ state machine now trigger a general panic that disconnects from
+ Lisp, and displays a message describing what has happened. This is
+ a bug situation.
+ (slime-connect): Print a message during connection attempts unless
+ the minibuffer is active (it's annoying to get messages while
+ trying to enter commands).
+
+2003-10-18 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Fix some bugs in the state machine and be a bit more
+ careful when processing pending input.
+ (slime-compile-region): New command.
+ Some more tests.
+
+2003-10-17 James Bielman <jamesjb at jamesjb.com>
+
+ * .cvsignore: Add OpenMCL and SBCL fasl file extensions.
+
+ * swank-openmcl.lisp (who-calls): Fix bug where we would try to
+ take the TRUENAME of NIL when source information isn't available
+ for a caller.
+ (backtrace-for-emacs): Clean up the backtrace code a bit in
+ preparation for implementing FRAME-LOCALS.
+ (frame-catch-tags): Implement a stub version of this.
+ (frame-locals): Implemented fully for OpenMCL.
+
+ * swank-loader.lisp (compile-files-if-needed-serially): Be a little
+ more verbose when compiling files.
+
+2003-10-17 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp, swank-sbcl.lisp, swank-openmcl.lisp,
+ swank-cmucl.lisp: Move more stuff to swank.lisp.
+
+2003-10-17 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-post-command-hook): Check that we are connected
+ before trying to process input.
+ (slime-net-connect): Handle `network-error' condition for XEmacs
+ 21.5. (Thanks Raymond Toy.)
+
+ * swank-sbcl.lisp: Report style-warnings separately from notes
+ (patch from Christophe Rhodes). Use REQUIRE to load sb-introspect
+ instead of loading the source file (requires the sb-introspect
+ library to be installed, which doesn't yet happen in the
+ sourceforge-lagged SBCL anoncvs, but does in the real one).
+
+ * slime.el (slime-style-warning-face): Added style-warnings, which
+ are between a warning and a note in severity. (Patch from
+ Christophe Rhodes).
+
+ * test.sh: When the test fails to complete, print "crashed"
+ instead of reporting nonsense.
+
+2003-10-17 James Bielman <jamesjb at jamesjb.com>
+
+ * swank.lisp (apropos-symbols): Change back to using the standard
+ 2-argument APROPOS-LIST and check symbols explicitly when
+ EXTERNAL-ONLY is true.
+ Move loading of sys-dependent backend code into 'swank-loader'.
+
+ * swank-sbcl.lisp: Moved declarations of *PREVIOUS-COMPILER-CONDITION*
+ into 'swank.lisp' to kill warnings about undefined variables.
+
+ * swank-openmcl.lisp (handle-compiler-warning): Use source position
+ instead of function name for warning locations.
+ (swank-compile-string): Compile into a temporary file instead of
+ using COMPILE so finding warning positions works when using C-c C-c.
+ (compute-backtrace): Don't display frames without a function.
+ (apropos-list-for-emacs): Implement APROPOS.
+ (who-calls): Implement WHO-CALLS.
+ (completions): Implement COMPLETIONS.
+ Use NIL instead of zero so FRESH-LINE does the right thing.
+
+ * slime.el (slime-maybe-compile-swank): Removed function---compile
+ the backend using 'swank-loader.lisp' instead.
+ (slime-backend): Changed default backend to 'slime-loader'.
+ (slime-lisp-binary-extension): Deleted as this is no longer needed.
+
+ * swank-loader.lisp: New file.
+
+2003-10-17 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-net-connect): Check that
+ `set-process-coding-system' is fbound before calling it. This is
+ needed in the XEmacs I built from sources.
+
+2003-10-17 Daniel Barlow <dan at telent.net>
+
+ * swank-sbcl.lisp: Transplanted Helmut's serve-event server to
+ replace the existing thread-using server. SLIME now has no
+ dependency on SB-THREAD
+
+ * slime.el (slime-find-buffer-package): handle errors from (read)
+ for the case where the buffer ends before the in-package form does
+ (slime-set-package): insert missing comma
+ (slime-goto-source-location): sbcl has a disagreement with emacs
+ over the meaning of a character position. Level up with
+ C-M-f C-M-b
+
+ * assorted typo fixes
+
+2003-10-16 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-forward-source-path): Improved somewhat. Seems
+ to work for all common cases except backquote. Backquote is
+ tricky, because the source-paths are based on the reader's
+ expansion, e.g.:
+ * (let ((*print-pretty* nil))
+ (print (read-from-string "`(a ,@(b c) d)")))
+ -->
+ (COMMON-LISP::BACKQ-CONS (QUOTE A)
+ (COMMON-LISP::BACKQ-APPEND (B C)
+ (QUOTE (D))))
+ Must investigate whether we need to write a hairy
+ backquote-traversing state machine or whether this is something
+ that could be fixed in CMUCL.
+
+ * swank*.lisp (with-trapping-compiler-notes): This macro is now
+ defined here, and expands to a call to the backend-defined
+ `call-trapping-compiler-notes' with the body wrapped in a
+ lambda. This is to avoid swank.lisp referring to macros in the
+ backends -- it gets compiled first so it thinks they're functions.
+
+ * slime.el (slime-swank-connection-retries): New default value is
+ `nil', which means unlimited retries (until user aborts). Retry
+ interval also reduced from once per second to four times per
+ second.
+
+2003-10-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank-cmucl.lisp, swank.lisp: Fix CMUCL support.
+
+2003-10-15 Daniel Barlow <dan at telent.net>
+
+ * swank.lisp: rearrange the backends. rename swank.lisp to
+ swank-cmucl.lisp, then create new swank.lisp which loads an
+ appropriate backend according to *features*. Next up,
+ identify common functions in the backends and move them
+ into swank.lisp
+
+2003-10-15 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Inspector support. list-callers, list-callees
+ implemented without xref.
+
+ * swank.lisp: Lisp side for inspector and list-callers,
+ list-calees. Better fdefinition finding for struct-accessors.
+
+
+2003-10-15 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-point-moves-p): Macro for executing subforms and
+ returning true if they move the point.
+
+ * test.sh: New file to run the test suite in batch-mode. Will need
+ a little extending to allow configuring the right variables to
+ work with non-CMUCL backends.
+
+ * slime.el: Set `indent-tabs-mode' to nil. This makes diffs look
+ better.
+ (slime-start-swank-server): Now passing the port number to
+ SWANK:START-SERVER.
+ (slime-evaluating-state): Debugging synchronous evaluations with
+ recursive edits now works.
+ (slime-forward-sexp): Added support for #|...|# reader comments.
+ (sldb-hook): New hook for entry to the debugger (used for the test
+ suite).
+ (slime-run-tests): Reworked the testing framework. Now presents
+ results in an outline-mode buffer, with only the subtrees
+ containing failed tests expanded initially.
+ (slime-check): Check-name can now be a string or
+ format-control. (Test cases have been updated to take advantage of
+ this.)
+ (compile-defun): This test case now works for the case containing
+ #|..|#
+ (async-eval-debugging): New test case for recursively debugging
+ asynchronous evaluation.
+
+2003-10-15 Daniel Barlow <dan at telent.net>
+
+ * README.sbcl: new file
+
+ * README: update for new backends, change of hosting provider
+
+ * swank-sbcl.lisp: new file.
+ New SWANK backend for Steel Bank Common Lisp, adapted from
+ swank.lisp with bits of swank-openmcl.lisp
+
+2003-10-12 Daniel Barlow <dan at telent.net>
+
+ * slime.el (sldb-mode-map): add mouse-2 clickability for areas
+ in sldb buffers covered by the sldb-default-action property:
+ restarts can now be mouse-activated
+
+2003-09-28 James Bielman <jamesjb at jamesjb.com>
+
+ * swank-openmcl.lisp: New file, a Slime backend for OpenMCL 0.14.x.
+ (condition-function-name): Figure out the name of methods correctly
+ instead of passing a list to Emacs.
+
+ * slime.el (slime-goto-location): Try to position notes based on
+ some (questionable) regex searching if the :FUNCTION-NAME property
+ is set. Used in the OpenMCL backend which does not support source
+ paths.
+
+2003-09-29 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Fairly major hacking.
+ Rewrote the evaluation mechanics: similar design but some macros
+ to make it look more like a push-down automaton (which it really
+ was!). Debugging Lisp no longer uses recursive edits, partly as a
+ side-effect and partly to see if it's better this way.
+ Removed the asynchronous-communication test cases that tested
+ something we decided not to do.
+ (slime-eval-string-async): Give a meaningful error message when
+ trying to make a request while already busy.
+ (slime-lisp-binary-extension): Uh oh, time to start taking out
+ gratuitous CMUCL-isms. This variable renamed from
+ `slime-cmucl-binary-extension'.
+ (slime-backend): Name of the Lisp backend file, defaulting to
+ "swank", but can be set to e.g. "swank-openmcl".
+
+ * swank.lisp: Minor protocol changes to accomodate slime.el's
+ changes above.
+
+2003-09-28 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp
+ (getpid, set-package, set-default-directory): New functions.
+ (slime-out-misc): Don't send empty strings.
+ (*redirect-output*, read-from-emacs): A new switch to turn output
+ redirection off. Useful for debugging.
+ (interactive-eval, interactive-eval-region, pprint-eval,
+ re-evaluate-defvar): Bind *package* to *buffer-package*.
+ (with-trapping-compilation-notes): Add a dummy argument for better
+ indentation.
+ (measure-time-intervall, call-with-compilation-hooks): Measure
+ compilation time.
+ (frame-locals): Use di::debug-function-debug-variables instead of
+ di:ambiguous-debug-variables. Don't access non-valid variables.
+
+ * slime.el
+ (slime-display-message-or-view): Delete old multi-line windows.
+ (slime-read-package-name): Added an optional initial-value
+ argument. slime-pid: New variable.
+ (slime-init-dispatcher): Initialize slime-pid.
+ (slime-send-sigint): Use slime-pid instead of inferior-lisp-proc.
+ (slime-eval): Accept debug-condition messages.
+ (slime-output-buffer): Turn slime-mode on.
+ (slime-switch-to-output-buffer): New command. Bound to C-c C-z.
+ (slime-show-note-counts): Display compilation time.
+ (slime-untrace-all, slime-set-package, slime-set-default-directory
+ slime-sync-package-and-default-directory): New commands.
+ (slime-princ-locals): Don't access non-valid variables. This may
+ cause segfaults and severely confuse CMUCL.
+ (slime-define-keys): New macro.
+
+2003-09-28 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (create-swank-server): Bind the listen-socket on the
+ loopback interface by default, so that remote machines can't
+ connect to the Swank server.
+
+2003-09-27 Luke Gorrie <luke at bluetail.com>
+
+ * swank.lisp (with-trapping-compilation-notes): New macro for
+ bindings the handlers to record compiler notes. Now being used in
+ `compile-string', which I had broken when removing the compilation
+ hook.
+
+ * slime.el (slime-function-called-at-point): Rewritten to work
+ better. Now considers "((foo ..." _not_ to be a function call to
+ foo because of the double ('s - this will keep it from misfiring
+ in e.g. LET bindings.
+ (def-slime-test): All tests now being with (slime-sync). This
+ fixes some accidental/bogus test failures.
+
+ * swank.lisp (handle-notification-condition): Rewrote
+ compiler-note collection. Now it uses lower-level condition
+ handlers instead of c:*compiler-notification-function*. This way
+ the error messages are tailored to omit redundant information,
+ like the filename and original source text (which are displayed
+ and highlighted in Emacs already). Much nicer.
+ (sort-contexts-by-source-path): Now sorting xref results by
+ lexical source-path order, so that you're always jumping in the
+ same direction.
+ (*debug-definition-finding*): New variable. You can set this to
+ true if you want to be popped into the debugger when M-. fails to
+ find a definition (for debugging the
+ definition-finding). Otherwise it reports the error to Emacs as a
+ message, like "Error: SETQ is a special form."
+
+ * slime.el (slime-fetch-features-list): New command to fetch the
+ *FEATURES* list from Lisp and store it away. This is done
+ automatically upon connection, but can also be called manually to
+ update.
+ (slime-forward-reader-conditional): Now does the right things with
+ reader-conditionals (#+ and #-) based on the Lisp features.
+
+2003-09-26 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (sldb-setup): Setting `truncate-lines' to t in the
+ debug buffer. I like having the backtrace take strictly one line
+ per frame, since otherwise a few ugly arguments (e.g. streams) can
+ chew up a lot of space. (Can make this a configurable on request
+ if tastes differ :-)
+
+ * swank.lisp: Did a little defensive programming so that asking
+ for the definition of an unbound function will return nil to Emacs
+ instead of entering the debugger.
+ (format-frame-for-emacs): Binding *PRETTY-PRINT* to nil when
+ formatting frames (due to truncate-lines change above).
+
+2003-09-24 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp:
+ Support for stream redirection.
+ slime-output-stream: New structure.
+ (slime-out-misc): New function.
+ *slime-output*: New variable.
+ (read-from-emacs): Redirect output to *slime-output*.
+ (read-form): Bind *package* inside the standard-io-syntax macro.
+ (eval-string): Read the string with read-form.
+ (completions): Support for keyword completion.
+
+ * slime.el (slime-process-available-input, slime-eval): Rewritten
+ once again. Don't use unwind-protect anymore. Didn't work
+ properly when the Lisp side aborted due to too many debug
+ levels. "Continuing" from the Emacs debugger aborts one level on
+ the Lisp side. "Quitting" from the Emacs debugger quits the Lisp
+ side too. Increase stack sizes before entering the recursive edit.
+ (slime-eval-async-state, slime-eval, sldb-state): Support for stream
+ output.
+ slime-last-output-start: New variable.
+ (slime-output-buffer, slime-output-buffer-position,
+ slime-insert-transcript-delimiter, slime-show-last-output,
+ slime-output-string): New functions.
+ (slime-show-evaluation-result,
+ slime-show-evaluation-result-continuation): Use them.
+ (slime-use-inf-lisp-p, slime-insert-transcript-delimiter,
+ slime-inferior-lisp-marker-position,
+ slime-inferior-lisp-show-last-output): Deleted.
+ (slime-use-tty-debugger, slime-debugger-hook,
+ slime-enter-tty-debugger, slime-tty-debugger-state): Deleted. Removed
+ tty debugger support.
+ (def-sldb-invoke-restart): Renamed.
+ (define-sldb-invoke-restart-key, define-sldb-invoke-restart-keys):
+ Version without eval.
+ (defun-if-undefined): New macro.
+ Many indentation fixes.
+
+2003-09-23 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * swank.lisp (completions):
+ Moved most of the completion code to Lisp.
+ (string-prefix-p): Be case insensitive.
+
+ * slime.el:
+ Make sure define-minor-mode is defined before we use it.
+ (slime-completing-read-internal, slime-completing-read-symbol-name,
+ slime-read-from-minibuffer, slime-completions, slime-complete-symbol):
+ Support for reading symbols and expressions with completion.
+ (slime-read-symbol-name): New function.
+ (slime-read-symbol): Use it.
+ (slime-read-package-name): Case insensitive completion.
+
+ (slime-edit-symbol-fdefinition, slime-edit-fdefinition): Rename
+ slime-edit-symbol-fdefinition to slime-edit-fdefinition.
+
+2003-09-23 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-show-xrefs): Improved the xrefs buffer, now
+ using a custom minor mode.
+ (slime-next-location): This function goes to the next "something"
+ by funcall'ing slime-next-location-function. Currently that
+ variable is set by xref commands like who-calls to go to the next
+ matching reference. In future it can also be used to go to the
+ next function definition for a generic-function-understanding
+ version of edit-fdefinition. Bound to C-M-. and C-c C-SPC, until
+ we see which binding is better.
+
+2003-09-22 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-symbol-at-point): Now returns a symbol, as the
+ name suggests.
+ (slime-symbol-name-at-point): This one returns a string.
+ (slime-read-symbol): New function for taking the symbol at point,
+ or prompting if there isn't one.
+ (slime-edit-fdefinition): Now uses looks up the symbol at point,
+ not the function being called at point.
+
+ * swank.lisp (who-calls, who-references, who-binds, who-sets,
+ who-macroexpands): New function.
+ (present-symbol-before-p): Use `*buffer-package*' when checking
+ accessibility of symbols.
+
+ * slime.el (slime-restore-window-configuration): New command to
+ put the Emacs window configuration back the way it was before
+ SLIME last changed it.
+ (slime-who-calls, etc): Very basic WHO-{CALLS,..} support. Not
+ finished, wrestling around trying to make `view-mode' or
+ `help-mode' help me (I just want to hijack RET and C-m). Bound to
+ "C-c C-w ...".
+
+2003-09-21 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el: Rearranged the `outline-mode' structure slightly.
+ (slime-check-connected): Using new function to give a helpful
+ error message if you try to use commands before establishing a
+ connection to CMUCL.
+ (sldb-mode): Keys 0-9 are now shortcuts to invoke restarts.
+
+ * README, swank.el: Updated commentary.
+
+2003-09-20 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-choose-overlay-region): Tweaked overlay
+ placement.
+
+ * swank.lisp (handle-notification): Skipping null
+ notifications. For some reason CMUCL occasionally calls us with
+ NIL as each argument.
+
+2003-09-19 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-connect): Propose default values when called
+ interactively.
+ (slime-process-available-input): If possible, use while rather than
+ recursion.
+ (slime-compilation-finished-continuation): New function.
+ (slime-compile-file, slime-compile-defun): Use it.
+ (slime-forward-source-path): Id an error is encounter move back to the
+ last valid point.
+ (slime-eval-region): Use append COND. Send the entire string to the
+ Lisp side and read&evaluate it there.
+ (slime-eval-buffer): New function.
+ (sldb-sugar-move, sldb-details-up, sldb-details-down): New functions.
+
+ * swank.lisp (interactive-eval-region): New function.
+ (re-evaluate-defvar): New function.
+ (compile-defun): Install handler for compiler-errors.
+ (function-first-code-location): Simplified.
+
+2003-09-17 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-apropos-all): New command, bound to C-c M-a.
+ (slime-eval): Simplified.
+ (swank:arglist-string): Send a string and not a symbol. It easier
+ to package related thins in CL.
+ (slime-edit-symbol-fdefinition): Prompt when called with
+ prefix-argument.
+ (slime-eval-region): New function.
+ (slime-load-file): New function.
+ (slime-show-description): Set slime minor mode in Help buffer.
+
+ * swank.lisp: (read-string, from-string): Renamed read-string to
+ from-string.
+ (to-string) New function.
+ (arglist-string): Catch reader errors.
+ (sldb-loop): Also bind *readstrable*.
+
+
+2003-09-16 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el (slime-toggle-trace-fdefinition): New command.
+ (slime-symbol-at-point, slime-sexp-at-point): New utility functions.
+ (slime-edit-symbol-fdefinition): Similar to slime-edit-fdefinition but
+ uses swank:function-source-location-for-emacs.
+ (slime-goto-source-location): New function.
+ (sldb-show-source): Use it.
+ (slime-read-package-name): Completing read for package names.
+ (slime-apropos): Use it.
+
+ * swank.lisp (function-source-location,
+ function-source-location-for-emacs): New functions to extract
+ source locations from compiled code. For struct-accessors we try
+ to find the source location of the corresponding constructor.
+ (list-all-package-names): New function.
+ (toggle-trace-fdefinition, tracedp): New functions.
+
+2003-09-15 Helmut Eller <e9626484 at stud3.tuwien.ac.at>
+
+ * slime.el: Moved many CL fragments from slime.el to swank.lisp.
+ (slime-compile-file, slime-compile-defun, slime-goto-location):
+ Compiler notes are now represented with a property list. To find
+ the source expression first move to the file offset of the
+ top-level form and then use the source path to find the
+ expression. This should avoid many reader issues. For
+ compile-defun store the start position of the top-level expression
+ from the buffer in the compiler notes and use that to locate error
+ messages. Add error overlays for notes without context to the
+ first available expression.
+
+ * swank.lisp: Moved many CL fragments from slime.el to swank.lisp.
+ (defslimefun): New macro.
+
+2003-09-15 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-setup-command-hooks): Removed post-command-hook
+ that was used for cleaning up input that was unprocessed due to an
+ error breaking out of the process filter. This is now handled by
+ an `unwind-protect' in the filter.
+
+ * swank.lisp (apropos-list-for-emacs): Hacked the apropos listing
+ to accept more options and to specially sort results.
+
+ * slime.el (slime-net-send): Added newlines to messages over the
+ wire. This makes the protocol nicely readable in Ethereal.
+ (slime-sync): New function for blocking until asynchronous
+ requests are complete.
+ (slime-apropos): Hacked the apropos command: by default, only
+ external symbols are shown. With a prefix argument you have the
+ option to include internal symbols and to specify a package.
+ (slime-run-tests): Extended the test suite. Use `M-x
+ slime-run-tests' to run it.
+
+2003-09-14 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el, swank.lisp: Added the debugger written by Helmut.
+
+ * cmucl-wire.el: Removed. The WIRE communication protocol has been
+ replaced by a simple custom TCP protocol based on READ/PRIN1 to
+ send sexps as ascii text. This simplifies the code, makes the
+ protocol nicely debugable with ethereal, and should ease porting
+ to other Lisps. Incremented TCP port number to 4005 in honor of
+ the new protocol.
+
+ In addition, Lisp now always uses *print-case* of :DOWNCASE when
+ preparing sexps for Emacs. This is in reaction to a bug with Emacs
+ reading the empty list as `NIL' instead of `nil'.
+
+ * slime.el (slime-net-connect): The Emacs end of the new
+ communication protocol.
+
+ * swank.lisp (create-swank-server): The Lisp end of the new
+ communication protocol.
+
+2003-09-11 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-mode): Added Helmut's commands to the mode
+ description.
+ (slime-show-apropos): Setting `truncate-lines' to t in apropos
+ listings, to avoid line-wrapping on overly long descriptions.
+ (slime-run-tests): Added the beginnings of an automated test
+ suite. (This is most useful for testing cross-Emacsen
+ compatibility before releases.)
+
+ * swank.lisp (symbol-external-p): Put back this function which was
+ lost in a merge.
+
+2003-09-10 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el, cmucl-wire.el, swank.lisp: Large patch from Helmut
+ Eller. Includes: apropos, describe, compile-defun, fully
+ asynchronous continuation-based wire interface, interactive
+ evaluation, and more. Very nice :-)
+
+2003-09-08 Luke Gorrie <luke at bluetail.com>
+
+ * cmucl-wire.el (wire-symbol-name, wire-symbol-package): Fixed to
+ handle internal references (pkg::name).
+
+ * slime.el (slime-swank-connection-retries): Increased default
+ number of connection retries from 5 to ten.
+
+ * swank.lisp (find-fdefinition): Support for finding
+ function/macro definitions for Emacs.
+
+ * slime.el: Indentation "cleanups": somehow I was using
+ `common-lisp-indent-function' for Emacs Lisp code previously.
+ (slime-edit-fdefinition): Added M-. (edit definition) and M-, (pop
+ definition stack) commands. Definitions are found in much the same
+ way Hemlock does it. The user-interface is not the same as TAGS,
+ because I like this one better. We can add TAGS-compatibility as
+ an optional feature in future.
+
+2003-09-04 Luke Gorrie <luke at bluetail.com>
+
+ * slime.el (slime-completions): Now supports completing
+ package-internal symbols with "pkg::prefix" syntax.
+
+ * Everything: imported slime-0.2 sources.
+
+;; Local Variables:
+;; coding: latin-1
+;; End:
+
+This file has been placed in the public domain.
Added: branches/bos/thirdparty/emacs/slime/HACKING
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/HACKING Fri Jan 18 06:05:59 2008
@@ -0,0 +1,136 @@
+* The SLIME Hacker's Handbook -*- outline -*-
+
+* Lisp code file structure
+
+The Lisp code is organised into these files:
+
+ swank-backend.lisp:
+ Definition of the interface to non-portable features.
+ Stand-alone.
+
+ swank-<cmucl|...>.lisp:
+ Backend implementation for a specific Common Lisp system.
+ Uses swank-backend.lisp.
+
+ swank.lisp:
+ The top-level server program, built from the other components.
+ Uses swank-backend.lisp as an interface to the actual backends.
+
+* ChangeLog
+
+For each change we make an entry in the ChangeLog file. This is
+typically done using the command `add-change-log-entry-other-window'
+(C-x 4 a). The message can be automatically extracted from the
+ChangeLog to use in a CVS commit message by pressing C-c C-a in a
+vc-mode or pcl-cvs commit buffer.
+
+ChangeLog diffs are automatically sent to the slime-devel mailing list
+each day as a sort of digest summary of the slime-cvs list.
+
+There are good tips on writing ChangeLog entries in the GNU Coding Standards:
+ http://www.gnu.org/prep/standards_40.html#SEC40
+
+For information about Emacs's ChangeLog support see the `Change Log'
+and `Change Logs and VC' nodes of the Emacs manual:
+ http://www.gnu.org/software/emacs/manual/html_node/emacs_333.html#SEC333
+ http://www.gnu.org/software/emacs/manual/html_node/emacs_156.html#SEC156
+
+* Sending Patches
+
+If you would like to send us improvements you can create a patch with
+C-x v = in the buffer or manually with 'cvs diff -u'. It's helpful if
+you also include a ChangeLog entry describing your change.
+
+* Test Suite
+
+The Elisp code includes a command `slime-run-tests' to run a test
+suite. This can give a pretty good sanity-check for your changes.
+
+Some backends do not pass the full test suite because of missing
+features. In these cases the test suite is still useful to ensure that
+changes don't introduce new errors. CMUCL historically passes the full
+test suite so it makes a good sanity check for fundamental changes
+(e.g. to the protocol).
+
+Running the test suite, adding new cases, and increasing the number of
+cases that backends support are all very good for karma.
+
+
+* Source code layout
+
+We use a special source file layout to take advantage of some fancy
+Emacs features: outline-mode and "narrowing".
+
+** Outline structure
+
+Our source files have a hierarchical structure using comments like
+these:
+
+ ;;;; Heading
+ ;;;;; Subheading
+ ... etc
+
+We do this as a nice way to structure the program. We try to keep each
+(sub)section small enough to fit in your head: typically around 50-200
+lines of code each. Each section usually begins with a brief
+introduction, followed by its highest-level functions, followed by
+their subroutines. This is a pleasing shape for a source file to have.
+
+Of course the comments mean something to Emacs too. One handy usage is
+to bring up a hyperlinked "table of contents" for the source file
+using this command:
+
+ (defun show-outline-structure ()
+ "Show the outline-mode structure of the current buffer."
+ (interactive)
+ (occur (concat "^" outline-regexp)))
+
+Another is to use `outline-minor-mode' to fold away certain parts of
+the buffer. See the `Outline Mode' section of the Emacs manual for
+details about that.
+
+(This file is also formatted for outline mode. If you're reading in
+Emacs you can play around e.g. by pressing `C-c C-d' right now.)
+
+** Pagebreak characters (^L)
+
+We partition source files into chunks using pagebreak characters. Each
+chunk is a substantial piece of code that can be considered in
+isolation, that could perhaps be a separate source file if we were
+fanatical about small source files (rather than big ones!)
+
+The page breaks usually go in the same place as top-level outline-mode
+headings, but they don't have to. They're flexible.
+
+In the old days, when slime.el was less than 100 pages long, these
+page breaks were helpful when printing it out to read. Now they're
+useful for something else: narrowing.
+
+You can use `C-x n p' (narrow-to-page) to "zoom in" on a
+pagebreak-delimited section of the file as if it were a separate
+buffer in itself. You can then use `C-x n w' (widen) to "zoom out" and
+see the whole file again. This is tremendously helpful for focusing
+your attention on one part of the program as if it were its own file.
+
+(This file contains some page break characters. If you're reading in
+Emacs you can press `C-x n p' to narrow to this page, and then later
+`C-x n w' to make the whole buffer visible again.)
+
+
+* Coding style
+
+We like the fact that each function in SLIME will fit on a single
+screen (80x20), and would like to preserve this property! Beyond that
+we're not dogmatic :-)
+
+In early discussions we all made happy noises about the advice in
+Norvig and Pitman's _Tutorial on Good Lisp Programming Style_:
+ http://www.norvig.com/luv-slides.ps
+
+For Emacs Lisp, we try to follow the _Tips and Conventions_ in
+Appendix D of the GNU Emacs Lisp Reference Manual (see Info file
+`elisp', node `Tips').
+
+Remember that to rewrite a program better is the sincerest form of
+code appreciation. When you can see a way to rewrite a part of SLIME
+better, please do so!
Added: branches/bos/thirdparty/emacs/slime/NEWS
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/NEWS Fri Jan 18 06:05:59 2008
@@ -0,0 +1,159 @@
+* SLIME News -*- outline -*-
+
+* 3.0 (not released yet)
+
+** Removed Features
+Some of the more esoteric features, like presentations or fuzzy
+completion, are no longer enabled by default. A new directory
+"contrib/" contains the code for these packages. To use them, you
+must make some changes to your ~/.emacs. For details see, section
+"Contributed Packages" in the manual.
+
+** Stepper
+Juho Snellman implemented stepping commands for SBCL.
+
+** Completions
+SLIME can now complete keywords and character names (like #\newline).
+
+* 2.0 (April 2006)
+
+** In-place macro expansion
+Marco Baringer wrote a new minor mode to incrementally expand macros.
+
+** Improved arglist display
+SLIME now recognizes `make-instance' calls and displays the correct
+arglist if the classname is present. Similarly, for `defmethod' forms
+SLIME displays the arguments of the generic function.
+
+** Persistent REPL history
+SLIME now saves the command history from REPL buffers in a file and
+reloads it for newly created REPL buffers.
+
+** Scieneer Common Lisp
+Douglas Crosher added support for Scieneer Common Lisp.
+
+** SBCL
+Various improvements to make SLIME work well with current SBCL versions.
+
+** Corman Common Lisp
+Espen Wiborg added support for Corman Common Lisp.
+
+** Presentations
+A new feature which associates objects in Lisp with their textual
+represetation in Emacs. The text is clickable and operations on the
+associated object can be invoked from a pop-up menu.
+
+** Security
+SLIME has now a simple authentication mechanism: if the file
+~/.slime-secret exists we verify that Emacs and Lisp can access it.
+Since both parties have access to the same file system, we assume that
+we can trust each other.
+
+* 1.2 (March 2005)
+
+** New inspector
+The lisp side now returns a specially formated list of "things" to
+format which are then passed to emacs and rendered in the inspector
+buffer. Things can be either text, recursivly inspectable values, or
+functions to call. The new inspector has much better support CLOS
+objects and methods.
+
+** Unicode
+It's now possible to send non-ascii characters to Emacs, if the
+communication channel is configured properly. See the variable
+`slime-net-coding-system'.
+
+** Arglist lookup while debugging
+Previously, arglist lookup was disabled while debugging. This
+restriction was removed.
+
+** Extended tracing command
+It's now possible to trace individual a single methods or all methods
+of a generic function. Also tracing can be restricted to situations
+in which the traced function is called from a specific function.
+
+** M-x slime-browse-classes
+A simple class browser was added.
+
+** FASL files
+The fasl files for different Lisp/OS/hardware combinations are now
+placed in different directories.
+
+** Many other small improvements and bugfixes
+
+* 1.0 (September 2004)
+
+** slime-interrupt
+The default key binding for slime-interrupt is now C-c C-b.
+
+** sldb-inspect-condition
+In SLDB 'C' is now bound to sldb-inspect-condition.
+
+** More Menus
+SLDB and the REPL have now pull-down menus.
+
+** Global debugger hook.
+A new configurable *global-debugger* to control whether
+swank-debugger-hook should be installed globally is available. True by
+default.
+
+** When you call sldb-eval-in-frame with a prefix argument, the result is
+now inserted in the REPL buffer.
+
+** Compile function
+For Allegro M-. works now for functions compiled with C-c C-c.
+
+** slime-edit-definition
+Better support for Allegro: works now for different type of
+definitions not only. So M-. now works for e.g. classes in Allegro.
+
+** SBCL 0.8.13
+SBCL 0.8.12 is no longer supported. Support for 0.8.12 was broken for
+for some time now.
+
+* 1.0 beta (August 2004)
+
+** autodoc global variables
+The slime-autodoc-mode will now automatically show the value of a
+global variable at point.
+
+** Customize group
+The customize group is expanded and better-organised.
+
+** slime-interactive-eval
+Interactive-eval commands now print their results to the REPL when
+given a prefix argument.
+
+** slime-conservative-indentation
+New Elisp variable. Non-nil means that we exclude def* and with-* from
+indentation-learning. The default is t.
+
+** (slime-setup)
+New function to streamline setup in ~/.emacs
+
+** Modeline package
+The package name in the modeline is now updated on an idle timer. The
+message should now be more meaningful when moving around in files
+containing multiple IN-PACKAGE forms.
+
+** XREF bugfix
+The XREF commands did not find symbols in the right package.
+
+** REPL prompt
+The package name in the REPL's prompt is now abbreviated to the last
+`.'-delimited token, e.g. MY.COMPANY.PACKAGE would be PACKAGE. This
+can be disabled by setting SWANK::*AUTO-ABBREVIATE-DOTTED-PACKAGES* to
+NIL.
+
+** CMUCL source cache
+The source cache is now populated on `first-change-hook'. This makes
+M-. work accurately in more file modification scenarios.
+
+** SBCL compiler errors
+Detect compiler errors and make some noise. Previously certain
+problems (e.g. reader-errors) could slip by quietly.
+
+* 1.0 alpha (June 2004)
+
+The first preview release of SLIME.
+
Added: branches/bos/thirdparty/emacs/slime/PROBLEMS
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/PROBLEMS Fri Jan 18 06:05:59 2008
@@ -0,0 +1,95 @@
+Known problems with SLIME -*- outline -*-
+
+* Common to all backends
+
+** Caution: network security
+The `M-x slime' command has Lisp listen on a TCP socket and wait for
+Emacs to connect, which typically takes on the order of one second. If
+someone else were to connect to this socket then they could use the
+SLIME protocol to control the Lisp process.
+
+The listen socket is bound on the loopback interface in all Lisps that
+support this. This way remote hosts are unable to connect.
+
+** READ-CHAR-NO-HANG is broken
+
+READ-CHAR-NO-HANG doesn't work properly for slime-input-streams. Due
+to the way we request input from Emacs it's not possible to repeatedly
+poll for input. To get any input you have to call READ-CHAR (or a
+function which calls READ-CHAR).
+
+* Backend-specific problems
+
+** CMUCL
+
+The default communication style :SIGIO is reportedly unreliable with
+certain libraries (like libSDL) and certain platforms (like Solaris on
+Sparc). It generally works very well on x86 so it remains the default.
+
+** SBCL
+
+The latest released version of SBCL at the time of packaging should
+work. Older or newer SBCLs may or may not work. Do not use
+multithreading with unpatched 2.4 Linux kernels. There are also
+problems with kernel versions 2.6.5 - 2.6.10.
+
+The (v)iew-source command in the debugger can only locate exact source
+forms for code compiled at (debug 2) or higher. The default level is
+lower and SBCL itself is compiled at a lower setting. Thus only
+defun-granularity is available with default policies.
+
+The XREF commands are not implemented.
+
+** OpenMCL
+
+We support OpenMCL 0.14.3.
+
+The XREF commands are not available.
+
+** LispWorks
+
+On Windows, SLIME hangs when calling foreign functions or certain
+other functions. The reason for this problem is unknown.
+
+We only support latin1 encoding. (Unicode wouldn't be hard to add.)
+
+** Allegro CL
+
+Interrupting Allegro with C-c C-b can be slow. This is caused by the
+a relatively large process-quantum: 2 seconds by default. Allegro
+responds much faster if mp:*default-process-quantum* is set to 0.1.
+
+** CLISP
+
+We require version 2.33.2 or higher. We also require socket support, so
+you may have to start CLISP with "clisp -K full".
+
+Under Windows, interrupting (with C-c C-b) doesn't work. Emacs sends
+a SIGINT signal, but the signal is either ignored or CLISP exits
+immediately.
+
+Function arguments and local variables aren't displayed properly in
+the backtrace. Changes to CLISP's C code are needed to fix this
+problem. Interpreted code is usually easer to debug.
+
+M-. (find-definition) only works if the fasl file is in the same
+directory as the source file.
+
+The arglist doesn't include the proper names only "fake symbols" like
+`arg1'.
+
+** Armed Bear Common Lisp
+
+The ABCL support is still new and experimental.
+
+** Corman Common Lisp
+
+We require version 2.51 or higher, with several patches (available at
+http://www.grumblesmurf.org/lisp/corman-patches).
+
+The only communication style currently supported is NIL.
+
+Interrupting (with C-c C-b) doesn't work.
+
+The tracing, stepping and XREF commands are not implemented along with
+some debugger functionality.
Added: branches/bos/thirdparty/emacs/slime/README
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/README Fri Jan 18 06:05:59 2008
@@ -0,0 +1,41 @@
+Overview.
+----------------------------------------
+
+ SLIME is the Superior Lisp Interaction Mode for Emacs. It is
+ implemented in two main parts: the Emacs Lisp side (slime.el), and
+ the support library for the Common Lisp (swank.lisp and swank-*.lisp)
+
+ For a real description, see the manual in doc/
+
+Quick setup instructions
+------------------------
+
+ Add this to your ~/.emacs file and fill in the appropriate filenames:
+
+ (add-to-list 'load-path "~/hacking/lisp/slime/") ; your SLIME directory
+ (setq inferior-lisp-program "/opt/sbcl/bin/sbcl") ; your Lisp system
+ (require 'slime)
+ (slime-setup)
+
+ Make sure your `inferior-lisp-program' is set to a compatible
+ version of Lisp.
+
+ Use `M-x' slime to fire up and connect to an inferior Lisp.
+ SLIME will now automatically be available in your Lisp source
+ buffers.
+
+Licence.
+----------------------------------------
+
+ SLIME is free software. All files, unless explicitly stated
+ otherwise, are public domain.
+
+Contact.
+----------------------------------------
+
+ Questions and comments are best directed to the mailing list:
+ http://common-lisp.net/mailman/listinfo/slime-devel
+
+ The mailing list archive is also available on Gmane:
+ http://news.gmane.org/gmane.lisp.slime.devel
+
Added: branches/bos/thirdparty/emacs/slime/contrib/CVS/Entries
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/CVS/Entries Fri Jan 18 06:05:59 2008
@@ -0,0 +1,31 @@
+/ChangeLog/1.78/Fri Jan 11 13:06:45 2008//
+/README/1.3/Fri Sep 28 13:05:44 2007//
+/bridge.el/1.1/Wed Sep 19 11:47:03 2007//
+/inferior-slime.el/1.2/Mon Sep 10 21:44:48 2007//
+/slime-asdf.el/1.3/Fri Sep 21 12:44:13 2007//
+/slime-autodoc.el/1.5/Mon Oct 1 13:37:10 2007//
+/slime-banner.el/1.4/Thu Sep 20 14:55:53 2007//
+/slime-c-p-c.el/1.8/Thu Sep 20 14:55:53 2007//
+/slime-editing-commands.el/1.6/Thu Jan 10 15:32:08 2008//
+/slime-fancy-inspector.el/1.2/Thu Sep 20 14:55:53 2007//
+/slime-fancy.el/1.4/Fri Sep 28 13:05:35 2007//
+/slime-fuzzy.el/1.6/Thu Jan 10 00:39:19 2008//
+/slime-highlight-edits.el/1.3/Thu Sep 20 14:55:53 2007//
+/slime-parse.el/1.10/Thu Jan 10 20:00:04 2008//
+/slime-presentation-streams.el/1.2/Tue Aug 28 08:25:12 2007//
+/slime-presentations.el/1.11/Fri Jan 11 13:06:35 2008//
+/slime-references.el/1.4/Thu Sep 20 14:55:53 2007//
+/slime-scheme.el/1.1/Wed Jan 9 18:30:26 2008//
+/slime-scratch.el/1.4/Thu Sep 20 14:55:53 2007//
+/slime-tramp.el/1.2/Tue Sep 4 10:18:44 2007//
+/slime-typeout-frame.el/1.5/Mon Oct 1 11:50:06 2007//
+/slime-xref-browser.el/1.1/Fri Aug 24 14:47:11 2007//
+/swank-arglists.lisp/1.18/Thu Jan 10 20:00:17 2008//
+/swank-asdf.lisp/1.1/Tue Sep 4 10:32:07 2007//
+/swank-c-p-c.lisp/1.2/Wed Sep 5 19:35:35 2007//
+/swank-fancy-inspector.lisp/1.5/Tue Nov 20 21:29:41 2007//
+/swank-fuzzy.lisp/1.7/Thu Jan 10 00:39:37 2008//
+/swank-listener-hooks.lisp/1.1/Tue Aug 28 13:53:02 2007//
+/swank-presentation-streams.lisp/1.4/Tue Aug 28 16:26:32 2007//
+/swank-presentations.lisp/1.4/Tue Sep 4 09:49:10 2007//
+D
Added: branches/bos/thirdparty/emacs/slime/contrib/CVS/Repository
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/CVS/Repository Fri Jan 18 06:05:59 2008
@@ -0,0 +1 @@
+slime/contrib
Added: branches/bos/thirdparty/emacs/slime/contrib/CVS/Root
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/CVS/Root Fri Jan 18 06:05:59 2008
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous at common-lisp.net:/project/slime/cvsroot
Added: branches/bos/thirdparty/emacs/slime/contrib/CVS/Template
==============================================================================
Added: branches/bos/thirdparty/emacs/slime/contrib/ChangeLog
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/ChangeLog Fri Jan 18 06:05:59 2008
@@ -0,0 +1,646 @@
+2008-01-11 Stelian Ionescu <sionescu at common-lisp.net>
+
+ * slime-presentations.el
+ (slime-copy-or-inspect-presentation-at-mouse): Call
+ slime-copy-presentation-at-mouse-to-repl rather than
+ slime-copy-presentation-at-mouse.
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-parse.el (slime-make-form-spec-from-string): Correctly
+ handle quoted things and other non-proper "(...)" forms.
+
+ * swank-arglist.lisp (read-form-spec): Added assertion against
+ receiving junk form specs from Emacs.
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-editing-commands.el (slime-close-all-parens-in-sexp): Use
+ new portability function `slime-delete-and-extract-region'.
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-parse.lisp (slime-incomplete-form-at-point): Hopefully
+ better fix than before.
+
+2008-01-10 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Add keyboard commands (starting with C-c C-v) and a top-level menu
+ for presentation-related commands. Add a command (C-c C-v M-o) to
+ forget all objects associated with presentations, without
+ clearing the REPL buffer.
+
+ * slime-presentations.el
+ (slime-presentation-around-or-before-point-or-error): New
+ function.
+ (slime-inspect-presentation): New function, factored out from
+ slime-inspect-presentation-at-mouse.
+ (slime-inspect-presentation-at-mouse): Use it here.
+ (slime-inspect-presentation-at-point): New command.
+ (slime-copy-presentation-to-repl): New function, factored out
+ from slime-copy-presentation-at-mouse.
+ (slime-copy-presentation-at-mouse-to-repl): Renamed from
+ slime-copy-presentation-at-mouse; use the new function
+ slime-copy-presentation-to-repl.
+ (slime-copy-presentation-at-point-to-repl): New command.
+ (slime-copy-presentation-to-kill-ring): New function, factored
+ out from slime-copy-presentation-at-mouse-to-kill-ring.
+ (slime-copy-presentation-at-point-to-kill-ring): New command.
+ (slime-describe-presentation): New function, factored out from
+ slime-describe-presentation-at-mouse.
+ (slime-describe-presentation-at-mouse): Use it here.
+ (slime-describe-presentation-at-point): New command.
+ (slime-pretty-print-presentation): New function, factored out
+ from slime-pretty-print-presentation-at-mouse.
+ (slime-pretty-print-presentation-at-mouse): Use it here.
+ (slime-pretty-print-presentation-at-point): New command.
+ (slime-mark-presentation): New command.
+ (slime-previous-presentation, slime-next-presentation): New
+ commands.
+ (slime-presentation-command-map, slime-presentation-bindings):
+ New variables.
+ (slime-presentation-init-keymaps): New function.
+ (slime-presentation-around-or-before-point-p): New function.
+ (slime-presentation-easy-menu): New variable.
+ (slime-presentation-add-easy-menu): New function.
+ (slime-clear-presentations): Make interactive, remove
+ presentation markup from all presentations in the REPL buffer.
+ (slime-presentations-init): Call slime-presentation-init-keymaps
+ and slime-presentation-add-easy-menu.
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-parse.lisp (slime-incomplete-form-at-point): Take the
+ arglist index the user's point is located at correctly into
+ account. Previously `C-c C-s' on `(defun |foo' would have inserted
+ `args body...)', now it inserts `name args body...)'
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglists.lisp (read-form-spec): Changed "cons" clause to
+ "list" clause in etypecase. Fix for error on arglist display on
+ `(declare (ftype (|)))', | being point.
+
+2008-01-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-fuzzy.el (slime-fuzzy-completion-time-limit-in-msec):
+ Update docstring: Its value isn't rounded to nearest second, but
+ is really interpreted as msecs.
+
+ * swank-fuzzy.el: Updated some comments.
+ (fuzzy-generate-matchings): Sort package matchings before
+ traversal, such that they're traversed in the order of their
+ score. (Important when time limit exhausts during traversal.)
+
+2008-01-09 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Restore support for Scheme programs that was removed from core
+ SLIME on 2007-09-19, as a "slime-scheme" contrib.
+
+ * slime-scheme.el: New file.
+
+2007-12-30 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglists.lisp: Fix for `(cerror "FOO" 'type-error ...)'
+
+ (*arglist-dummy*): Removed.
+ (arglist-dummy): New structure. Wrapper around whatever could not
+ be reliably read. The clue is that its printing function does only
+ print the object this structure contains.
+ (read-conversatively-for-autodoc): Return such a structure if
+ conversative reading fails.
+
+2007-11-27 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglists.lisp (arglist-dispatch 'defmethod): Use
+ VALID-FUNCTION-NAME-P. Fixes error on certain `(defmethod (setf ...))'
+ forms.
+
+2007-11-27 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglists.lisp (print-arglist): Print initforms in &optional and
+ &key lambda list specifiers as if by PRIN1 instead of PRINC.
+ Reported by Michael Weber.
+
+2007-11-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime-fuzzy.el: Use slime-require instead of a connected-hook.
+
+2007-11-20 Helmut Eller <heller at common-lisp.net>
+
+ * swank-fancy-inspector.lisp (inspect-for-emacs function t): Don't
+ specialize the second argument, so that backend methods take
+ precedence. Reported by Maciej Katafiasz.
+
+2007-10-24 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglist.lisp (decode-arglist): Fix incompatibility with
+ ACL's modern reader mode. Thanks to Andreas Fuchs for stumbling
+ over this.
+
+2007-10-22 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglist.lisp (read-softly): Renamed to
+ READ-SOFTLY-FROM-STRING and moved to `swank.lisp'.
+ (unintern-in-home-package): Moved to `swank.lisp'.
+
+2007-10-01 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-autdoc.el (slime-autodoc-message-ok-p): Don't display an
+ arglist when the minibuffer is active.
+
+2007-10-01 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-typeout-frame.el: Messages in the typeout frame were too
+ easily overwritten by `slime-autodoc'. Fix that.
+ Reported by Geoff Wozniak.
+
+ (slime-typeout-message-aux): Split out from `slime-typeout-message'.
+ (slime-typeout-message): Wrapper around it. Additionally disable
+ the autodoc timer temporarily.
+
+2007-09-30 Geoff Wozniak <geoff at wozniak.ca>
+
+ * slime-typeout-frame.el (slime-typeout-frame-init): Fix quoted
+ FUNCTION forms in literal.
+
+2007-09-28 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * README: Updated.
+
+ * slime-fancy.el: `slime-highlighting-edits' is not enabled by
+ default anymore, as its functionality is controversial, and it's
+ easier to explicitly enable it than to disable it once it got
+ globally activated. Better to be conservative.
+
+ * slime-fancy.el: Not only load, but also enable `slime-scratch'.
+
+2007-09-21 Helmut Eller <heller at common-lisp.net>
+
+ * slime-asdf.el (slime-asdf-init, slime-asdf-unload): Fix typos.
+ Reported by Ariel Badichi.
+
+2007-09-20 Helmut Eller <heller at common-lisp.net>
+
+ Separate loading from initialization for many contribs.
+
+ * slime-asdf.el
+ * slime-autodoc.el
+ * slime-banner.el
+ * slime-c-p-c.el
+ * slime-editing-commands.el
+ * slime-fancy-inspector.el
+ * slime-fuzzy.el
+ * slime-highlight-edits.el
+ * slime-presentations.el
+ * slime-references.el
+ * slime-scratch.el
+ * slime-typeout-frame.el
+ * swank-fancy-inspector.lisp
+
+ * slime-fancy.el: As an exception, call the respective init
+ function when loading.
+
+2007-09-19 Helmut Eller <heller at common-lisp.net>
+
+ * slime-c-p-c.el (slime-complete-symbol*-fancy): Move defcustom
+ from slime.el to contrib/slime-c-p-c.el.
+
+2007-09-16 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-fuzzy.lisp: Fix regression that would not allow to fuzzy
+ complete on inputs without package qualifier like "app".
+ Reported by David J. Neu.
+
+ (%make-duplicate-symbols-filter): Return complement.
+ (fuzzy-find-matching-symbols): Treat passed filter as an acceptor
+ predicate, not as a rejector.
+
+2007-09-15 Helmut Eller <heller at common-lisp.net>
+
+ Add the necessary hooks when loading some contribs, so that those
+ contribs can be easily loaded with slime-setup.
+
+ * slime-highlight-edits.el (slime-highlight-edits-mode-on): New
+ function. Add this to slime-mode-hook by default.
+
+ * slime-autodoc.el (slime-use-autodoc-mode): Change default to t.
+
+2007-09-15 Ariel Badichi <abadichi at bezeqint.net>
+
+ * swank-fancy-inspector.lisp (inspect-for-emacs package): When
+ inspecting a package, the links in the use list and the used-by
+ list lead to inspecting package names, rather than the packages
+ themselves. Fix that.
+
+2007-09-15 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-parse.el: Fix extended arglist display on misbalanced
+ expressions like `(defun foo | ... (defun bar () 'bar)'
+ Reported by Ariel Badichi.
+
+ (slime-inside-string-p): Use `beginning-of-defun' directly than
+ relying on `slime-region-for-defun-at-point' (as this one uses
+ `end-of-defun' which signals an error on misbalanced expressions.)
+
+2007-09-15 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-fuzzy.lisp: Code reorganization and cleanup; making it
+ compute less and couple of other minor issues fixed on the
+ way. Thanks to Stelian Ionescu for testing and providing feedback!
+
+ (defstruct fuzzy-matching): New `package-name' slot.
+ (make-fuzzy-matching): Updated for new slot.
+ (format-completion-result): Renamed to `fuzzy-format-matching'.
+ (%fuzzy-extract-matching-info): Helper for `fuzzy-format-matching'.
+
+ (fuzzy-completion-set): Convert the matchings after they got
+ truncated to the passed completion-set limit from Emacs.
+ I.e. `slime-fuzzy-completion-limit' This means a huge
+ computational reduction.
+
+ (fuzzy-create-completion-set): Renamed to `fuzzy-generate-matchings'.
+ (fuzzy-generate-matchings): Returns the fuzzy matchings
+ themselves, do not yet convert them for Emacs. Do not perform two
+ sorts on the generated matchings (first alphabetically, then per
+ score), but just one with an appropriate predicate that sorts per
+ score, unless matchings are equal, then sort alphabetically. Prune
+ matchings with symbols which are found in a differenta package
+ than their home package when the home package is among the matched
+ packages. Try to take the time needed to sort the generated
+ matchings into account for the time-limit.
+ (%guess-sort-duration): Helper.
+ Tries to guess how long the sort will take.
+ (%make-duplicate-symbols-filter): Helper.
+ Used for pruning of matchings.
+ (fuzzy-matching-greaterp): New testing predicate for sorting.
+
+ (fuzzy-find-matching-symbols): Now takes a :filter keyarg; only
+ considers symbols that pass through the filter.
+ (fuzzy-find-matching-packages): Do not return matchings for all
+ nicknames of package, but just the one that matches best.
+
+2007-09-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-editing-commands.el: Automatically bind the editing
+ commands when this module is required. (Previously, one had to
+ enable them explicitly, but this is inconsistent to, for instance,
+ the `slime-c-p-c' module which also sets up its bindings
+ automatically.)
+ (slime-bind-editing-commands): Renamed to `slime-editing-commands-init'.
+ (slime-editing-commands-init): Evaluated at toplevel.
+
+2007-09-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-parse.el (slime-enclosing-form-specs): Now also works even
+ when point is inside a string.
+ (slime-inside-string-p): New function.
+ (slime-beginning-of-string): New function.
+
+2007-09-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglist.lisp (read-conversatively-for-autodoc): Also parse
+ quoted symbols explicitly. This fixed extended arglist display for
+ `(make-instance 'foo'. Reported by: Johannes Groedem.
+
+2007-09-11 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-fancy.el: Require `slime-references'.
+
+2007-09-10 Helmut Eller <heller at common-lisp.net>
+
+ * slime-parse.el (slime-cl-symbol-name, slime-cl-symbol-package):
+ Move from slime.el to contrib/slime-parse.el.
+
+2007-09-10 Helmut Eller <heller at common-lisp.net>
+
+ * inferior-slime.el: Fix installation comment.
+
+2007-09-10 Helmut Eller <heller at common-lisp.net>
+
+ Fix some of the bugs introduced with the last change.
+
+ * slime-references.el (sldb-reference-face): Add missing quote.
+ (sldb-reference-properties): We are lucky and can use keywords
+ instead of strings.
+ (sldb-maybe-insert-references): Insert newlines differently.
+
+2007-09-10 Helmut Eller <heller at common-lisp.net>
+
+ Move SBCL doc references to contrib.
+
+ * slime-references.el: New file.
+
+2007-09-10 Attila Lendvai <attila.lendvai at gmail.com>
+
+ * slime-fuzzy.el: Fixed some race condition that prevented a
+ proper closing of the *Fuzzy Completions* buffer in some
+ circumstances.
+
+ (slime-fuzzy-save-window-configuration): Removed. Hooking up
+ `window-configuration-change-hook' via `run-with-timer' was racy
+ and lead to this bug; we now set the hook explicitely at the
+ necessary place instead.
+ (slime-fuzzy-window-configuration-change-add-hook): Removed.
+ (slime-fuzzy-choices-buffer): Explicitly save the
+ window-configuration, and explicitly set the hook.
+ (slime-fuzzy-done): Explicitely remove the hook.
+
+2007-09-10 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-parse.el (slime-cl-symbol-name, slime-cl-symbol-package):
+ Moved back into slime.el.
+
+2007-09-08 Stelian Ionescu <sionescu at common-lisp.net>
+
+ * slime-banner.el: Fixed typo to provide `slime-banner', not
+ `slime-startup-animation'.
+
+2007-09-06 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime-presentations.el (slime-presentation-write): Use case, not
+ ecase, for dispatching targets. Should fix XEmacs compatibility.
+ Reported by Steven E. Harris.
+
+2007-09-05 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-c-p-c.el: This file incorrectly provided the module
+ `:swank-compound-prefix'; changed that to `:swank-c-p-c'.
+
+ This gets rid off the nasty redefinition warnings that were
+ previously signalled when loading SWANK with SBCL.
+
+ * swank-arglist.lisp (arglist-for-echo-area): Locally declare
+ `*arglist-pprint-bindings*' to be special, as the variable is
+ defined later in the file. (Gets rid of warnings during loading.)
+
+2007-09-05 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * slime-c-p-c.el (slime-c-p-c-init): Bind `slime-complete-form' to
+ `C-c C-s' in `slime-repl-mode-map'.
+
+2007-09-05 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Added extended arglist display for DECLAIM and PROCLAIM.
+
+ * slime-parse.el (slime-extended-operator-name-parser-alist): Added
+ entries for "DECLAIM", and "PROCLAIM".
+ (slime-parse-extended-operator/declare): Provide information about
+ the operator the arglist is requested for.
+ (slime-make-form-spec-from-string): Fixed for "()" as input.
+
+ * swank-arglists.lisp (valid-operator-symbol-p): Explicitly allow
+ the symbol 'DECLARE.
+ (arglist-dispatch): New method for `DECLARE'. We have to catch
+ this explicitly, as DECLARE doesn't have an arglist (in the
+ `swank-backend:arglist' sense.)
+ (*arglist-pprint-bindings*): New variable. Splitted out from
+ `decoded-arglist-to-string'.
+ (decoded-arglist-to-string): Use `*arglist-pprint-bindings*'.
+
+ (parse-first-valid-form-spec): Rewritten, because function
+ signature had to be changed: doesn't take arg-indices anymore;
+ returns position of first valid spec as second value to remedy.
+ (arglist-for-echo-area): Accomodated to new signature of
+ `parse-first-valid-form-spec'; now searchs for contextual
+ declaration operator name, to prefix a declaration arglist by
+ "declare", "declaim", or "proclaim" depending on what was used at
+ user's point in Slime. Use `*arglist-pprint-bindings*' for
+ printing the found declaration operator name.
+ (%find-declaration-operator): New helper to do this search.
+ (completions-for-keyword): Accomodated to new signature of
+ `parse-first-valid-form-spec'. Also fixed to correctly provide
+ keyword completions in nested expressions like:
+
+ `(defun foo (x)
+ (let ((bar 'quux))
+ (with-open-file (s f :|' [`|' being point]
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ * swank-arglists.lisp (parse-first-valid-form-spec): Rewrite it for
+ ABCL.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Some bug fixes for slime-complete-symbol*.
+ Patches by Mr. Madhu <enometh at meer.net>
+
+ * slime-c-p-c.el (slime-c-p-c-unambiguous-prefix-p): New variable.
+ (slime-expand-abbreviations-and-complete): Use it. Also add a
+ workaround for XEmacs issues.
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ Move asdf support to contrib:
+
+ * slime-asdf.el: New file.
+
+ * swank-asdf.lisp: New file
+ (operate-on-system, asdf-central-registry)
+ (list-all-systems-known-to-asdf): Use the asdf package in the
+ source code, i.e. write asdf:operate instead of
+ (find-symbol "OPERATE" "ASDF").
+
+2007-09-04 Helmut Eller <heller at common-lisp.net>
+
+ * slime-tramp.el: New file.
+ * slime-banner.el: New file.
+ * inferior-slime.el: New file.
+
+2007-09-01 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime-fancy.el: New meta-contrib.
+
+2007-09-01 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime-presentations.el (slime-dispatch-presentation-event):
+ Explicitly return t to indicate the events have been handled,
+ rather than relying on the return values of the called functions.
+
+2007-09-01 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime-typeout-frame.el (slime-typeout-autodoc-message): Fix for
+ messages that contain "%". Reported by Martin Simmons.
+
+2007-09-01 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Makes `slime-complete-form' work on `(eval-when |'; doesn't work
+ on `(eval-when (|' yet.
+
+ * slime-parse.el (slime-parse-sexp-at-point): Guard against
+ `(char-after)' being NIL at end of buffer (especially important
+ for use on the REPL.)
+
+ * swank-arglist.lisp (arglist-dispatch 'eval-when): Fix typo.
+ (print-decoded-arglist-as-template): Print keywords with PRIN1.
+
+2007-08-31 Tobias C. Rittweiler <tcr at freebits.de>
+
+ Added extended arglist display for EVAL-WHEN, viz:
+
+ (eval-when (&any :compile-toplevel :load-toplevel :execute) &body body)
+
+ Notice that completion works as expected on these keywords.
+
+ Die, EVAL-ALWAYS, die!
+
+ * swank-arglist (arglist-dispatch): New method for EVAL-WHEN.
+ (print-arglist): Print keywords with PRIN1 rather than PRINC,
+ to get a result as shown above for the EVAL-WHEN case.
+ (completions-for-keyword): Add support for &ANY args.
+
+2007-08-31 Tobias C. Rittweiler <tcr at freebits.de>
+
+ * swank-arglist.lisp: Do not fall back to READ when interpreting
+ the ``raw form specs'' comming from Slime's autodoc stuff. But
+ still do so for those comming from `slime-complete-form'.
+
+ (unintern-in-home-package): New.
+
+ (*arglist-dummy*): New.
+ (read-conversatively-for-autodoc): New function. Doesn't READ
+ anything that comes from Slime's autodoc. Just tries to parse
+ symbols. If that's not successfull, returns the dummy placeholder
+ datum stored in `*arglist-dummy*'.
+ (arglist-for-echo-area): Parse form-specs using
+ `read-conversatively-for-autodoc'. Use `unintern-in-home-package'.
+
+ (read-softly): New. Splitted out from `read-form-spec'. This
+ function tries to keep track of newly interned functions before
+ READing.
+ (read-form-spec): Parametrized to take a function to read the
+ elements of the passed ``raw form spec''. Uses `read-softly' as
+ default reader.
+
+ (complete-form, completions-for-keywords):
+ Use `unintern-in-home-package'.
+
+2007-08-31 Helmut Eller <heller at common-lisp.net>
+
+ * slime-autodoc.el: Add installation notes.
+ * slime-editing-commands.el: Add installation notes.
+ * slime-c-p-c.el (slime-c-p-c-init): Fix typos.
+
+2007-08-31 Helmut Eller <heller at common-lisp.net>
+
+ Move compound prefix completion and autodoc to contrib.
+ Interdependencies made it almost necessary to move parsing code
+ and editing commands in the same patch.
+
+ * slime-c-p-c.el: New file.
+ * swank-c-p-c.el: New file.
+ * slime-parse.el: New file.
+ * swank-arglists.el: New file.
+ * slime-editing-commands.el: New file.
+ * slime-autodoc.el: New file.
+
+2007-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * slime-presentations.el (slime-last-output-target-id)
+ (slime-output-target-to-marker, slime-output-target-marker)
+ (slime-redirect-trace-output): Moved back into SLIME core.
+
+ * swank-presentation-streams.lisp: Require swank-presentations.
+ (present-repl-results-via-presentation-streams): New.
+ (*send-repl-results-function*): Set this variable rather than
+ overriding send-repl-results-to-emacs.
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ * slime-presentations.el (slime-clear-presentations): New
+ function. Add it to slime-repl-clear-buffer-hook.
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ * swank-listener-hooks.lisp: New file
+
+2007-08-28 Helmut Eller <heller at common-lisp.net>
+
+ Move the rest of the presentation related code.
+
+ * swank-presentations.lisp (present-repl-results): Renamed from
+ send-repl-results-to-emacs.
+
+2007-08-28 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ * swank-presentations.lisp (send-repl-results-to-emacs):
+ Override core defun to mark up REPL results as presentations.
+
+ * swank-presentations.lisp: New file.
+ * slime-presentations.el: Load it.
+
+ * slime-presentations.el (slime-presentation-write): Remove id
+ argument.
+
+ * slime-presentation-streams.el: Require slime-presentations contrib.
+
+2007-08-27 Helmut Eller <heller at common-lisp.net>
+
+ Move presentations to contrib. (ELisp part)
+
+ * slime-presentations.el: New file.
+ * slime-scratch.el (slime-scratch-buffer): Ignore presentations.
+
+2007-08-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Some fixes to the presentation-streams contrib.
+
+ * swank-presentation-streams.lisp [sbcl]: Load the pretty-printer
+ patch only at load time. Add some trickery so that SBCL does not
+ complain about the changed layout of the pretty-stream class.
+
+ * swank-presentation-streams.lisp (slime-stream-p): Using special
+ return values, indicate whether we are printing to the
+ REPL-results stream, or a dedicated stream.
+ (presentation-record): New slot "target".
+ (presentation-start, presentation-end): Use it (rather than the
+ global variable *use-dedicated-output-stream*) to decide whether
+ to use the bridge protocol or the :presentation-start/-end
+ protocol. Also use it as the TARGET argument of
+ :presentation-start/-end messages.
+ (presenting-object-1): Use the new return values of
+ slime-stream-p.
+
+ * swank-presentation-streams.lisp (slime-stream-p) [cmu]: Use the
+ return value of slime-stream-p rather than the global variable
+ *use-dedicated-output-stream* to decide whether printing through
+ pretty streams is safe for the layout.
+
+2007-08-24 Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+
+ Make the fancy "presentation streams" feature a contrib.
+ Previously, it was only available if "present.lisp" was loaded
+ manually.
+
+ * slime-presentation-streams.el: New file.
+ * swank-presentation-streams.lisp: New file, moved here from
+ ../present.lisp
+
+2007-08-24 Helmut Eller <heller at common-lisp.net>
+
+ * slime-typeout-frame.el: New file.
+ * slime-xref-browser.el: New file.
+ * slime-highlight-edits.el: New file.
+ * slime-scratch.el: New file.
+
+2007-08-23 Helmut Eller <heller at common-lisp.net>
+
+ Move Marco Baringer's inspector to contrib.
+
+ * swank-fancy-inspector.lisp: New file. The only difference to the
+ code is that inspect-for-emacs methods in this file are
+ specialized to the new class `fancy-inspector'.
+ (fancy-inspector): New class.
+
+ * slime-fancy-inspector.el: New file.
+
+2007-08-19 Helmut Eller <heller at common-lisp.net>
+
+ Moved fuzzy completion code to contrib directory.
+
+ * slime-fuzzy.el: New file.
+ (slime-fuzzy-init): New function. Load CL code on startup.
+
+ * swank-fuzzy.lisp: New file. Common Lisp code for fuzzy
+ completion.
Added: branches/bos/thirdparty/emacs/slime/contrib/README
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/README Fri Jan 18 06:05:59 2008
@@ -0,0 +1,30 @@
+This directory contains source code which may be useful to some Slime
+users. *.el files are Emacs Lisp source and *.lisp files contain
+Common Lisp source code. If not otherwise stated in the file itself,
+the files are placed in the Public Domain.
+
+The components in this directory are more or less detached from the
+rest of Slime. They are essentially "add-ons". But Slime can also be
+used without them. The code is maintained by the respective authors.
+
+To use the packages here, you should add this directory to your Emacs
+load-path, require the contrib, and call the contrib's init function to
+enable the functionality that's provided by the respective contrib.
+
+E.g. for fuzzy completion add this to your .emacs:
+
+ (add-to-list 'load-path "<this-directory>")
+ (add-hook 'slime-load-hook (lambda () (require 'slime-fuzzy)
+ (slime-fuzzy-init)))
+
+Alternatively, you can use the `slime-setup' function which takes a
+list of contrib names, and which loads and enables them automatically
+for you:
+
+ (slime-setup '(slime-fancy slime-asdf slime-tramp ...))
+
+
+Finally, the contrib `slime-fancy' is specially noteworthy, as it
+represents a meta-contrib that'll load a bunch of commonly used
+contribs. Look into `slime-fancy.el' to find out which.
+
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/bridge.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/bridge.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,467 @@
+;;; -*-Emacs-Lisp-*-
+;;;%Header
+;;; Bridge process filter, V1.0
+;;; Copyright (C) 1991 Chris McConnell, ccm at cs.cmu.edu
+;;;
+;;; Send mail to ilisp at cons.org if you have problems.
+;;;
+;;; Send mail to majordomo at cons.org if you want to be on the
+;;; ilisp mailing list.
+
+;;; This file is part of GNU Emacs.
+
+;;; GNU Emacs is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY. No author or distributor
+;;; accepts responsibility to anyone for the consequences of using it
+;;; or for whether it serves any particular purpose or works at all,
+;;; unless he says so in writing. Refer to the GNU Emacs General Public
+;;; License for full details.
+
+;;; Everyone is granted permission to copy, modify and redistribute
+;;; GNU Emacs, but only under the conditions described in the
+;;; GNU Emacs General Public License. A copy of this license is
+;;; supposed to have been given to you along with GNU Emacs so you
+;;; can know your rights and responsibilities. It should be in a
+;;; file named COPYING. Among other things, the copyright notice
+;;; and this notice must be preserved on all copies.
+
+;;; Send any bugs or comments. Thanks to Todd Kaufmann for rewriting
+;;; the process filter for continuous handlers.
+
+;;; USAGE: M-x install-bridge will add a process output filter to the
+;;; current buffer. Any output that the process does between
+;;; bridge-start-regexp and bridge-end-regexp will be bundled up and
+;;; passed to the first handler on bridge-handlers that matches the
+;;; output using string-match. If bridge-prompt-regexp shows up
+;;; before bridge-end-regexp, the bridge will be cancelled. If no
+;;; handler matches the output, the first symbol in the output is
+;;; assumed to be a buffer name and the rest of the output will be
+;;; sent to that buffer's process. This can be used to communicate
+;;; between processes or to set up two way interactions between Emacs
+;;; and an inferior process.
+
+;;; You can write handlers that process the output in special ways.
+;;; See bridge-send-handler for the default handler. The command
+;;; hand-bridge is useful for testing. Keep in mind that all
+;;; variables are buffer local.
+
+;;; YOUR .EMACS FILE:
+;;;
+;;; ;;; Set up load path to include bridge
+;;; (setq load-path (cons "/bridge-directory/" load-path))
+;;; (autoload 'install-bridge "bridge" "Install a process bridge." t)
+;;; (setq bridge-hook
+;;; '(lambda ()
+;;; ;; Example options
+;;; (setq bridge-source-insert nil) ;Don't insert in source buffer
+;;; (setq bridge-destination-insert nil) ;Don't insert in dest buffer
+;;; ;; Handle copy-it messages yourself
+;;; (setq bridge-handlers
+;;; '(("copy-it" . my-copy-handler)))))
+
+;;; EXAMPLE:
+;;; # This pipes stdin to the named buffer in a Unix shell
+;;; alias devgnu '(echo -n "\!* "; cat -; echo -n "")'
+;;;
+;;; ls | devgnu *scratch*
+
+(eval-when-compile
+ (require 'cl))
+
+;;;%Parameters
+(defvar bridge-hook nil
+ "Hook called when a bridge is installed by install-hook.")
+
+(defvar bridge-start-regexp ""
+ "*Regular expression to match the start of a process bridge in
+process output. It should be followed by a buffer name, the data to
+be sent and a bridge-end-regexp.")
+
+(defvar bridge-end-regexp ""
+ "*Regular expression to match the end of a process bridge in process
+output.")
+
+(defvar bridge-prompt-regexp nil
+ "*Regular expression for detecting a prompt. If there is a
+comint-prompt-regexp, it will be initialized to that. A prompt before
+a bridge-end-regexp will stop the process bridge.")
+
+(defvar bridge-handlers nil
+ "Alist of (regexp . handler) for handling process output delimited
+by bridge-start-regexp and bridge-end-regexp. The first entry on the
+list whose regexp matches the output will be called on the process and
+the delimited output.")
+
+(defvar bridge-source-insert t
+ "*T to insert bridge input in the source buffer minus delimiters.")
+
+(defvar bridge-destination-insert t
+ "*T for bridge-send-handler to insert bridge input into the
+destination buffer minus delimiters.")
+
+(defvar bridge-chunk-size 512
+ "*Long inputs send to comint processes are broken up into chunks of
+this size. If your process is choking on big inputs, try lowering the
+value.")
+
+;;;%Internal variables
+(defvar bridge-old-filter nil
+ "Old filter for a bridged process buffer.")
+
+(defvar bridge-string nil
+ "The current output in the process bridge.")
+
+(defvar bridge-in-progress nil
+ "The current handler function, if any, that bridge passes strings on to,
+or nil if none.")
+
+(defvar bridge-leftovers nil
+ "Because of chunking you might get an incomplete bridge signal - start but the end is in the next packet. Save the overhanging text here.")
+
+(defvar bridge-send-to-buffer nil
+ "The buffer that the default bridge-handler (bridge-send-handler) is
+currently sending to, or nil if it hasn't started yet. Your handler
+function can use this variable also.")
+
+(defvar bridge-last-failure ()
+ "Last thing that broke the bridge handler. First item is function call
+(eval'able); last item is error condition which resulted. This is provided
+to help handler-writers in their debugging.")
+
+;;;%Utilities
+(defun bridge-insert (output)
+ "Insert process OUTPUT into the current buffer."
+ (if output
+ (let* ((buffer (current-buffer))
+ (process (get-buffer-process buffer))
+ (mark (process-mark process))
+ (window (selected-window))
+ (at-end nil))
+ (if (eq (window-buffer window) buffer)
+ (setq at-end (= (point) mark))
+ (setq window (get-buffer-window buffer)))
+ (save-excursion
+ (goto-char mark)
+ (insert output)
+ (set-marker mark (point)))
+ (if window
+ (progn
+ (if at-end (goto-char mark))
+ (if (not (pos-visible-in-window-p (point) window))
+ (let ((original (selected-window)))
+ (save-excursion
+ (select-window window)
+ (recenter '(center))
+ (select-window original)))))))))
+
+;;;
+;(defun bridge-send-string (process string)
+; "Send PROCESS the contents of STRING as input.
+;This is equivalent to process-send-string, except that long input strings
+;are broken up into chunks of size comint-input-chunk-size. Processes
+;are given a chance to output between chunks. This can help prevent processes
+;from hanging when you send them long inputs on some OS's."
+; (let* ((len (length string))
+; (i (min len bridge-chunk-size)))
+; (process-send-string process (substring string 0 i))
+; (while (< i len)
+; (let ((next-i (+ i bridge-chunk-size)))
+; (accept-process-output)
+; (process-send-string process (substring string i (min len next-i)))
+; (setq i next-i)))))
+
+;;;
+(defun bridge-call-handler (handler proc string)
+ "Funcall HANDLER on PROC, STRING carefully. Error is caught if happens,
+and user is signaled. State is put in bridge-last-failure. Returns t if
+handler executed without error."
+ (let ((inhibit-quit nil)
+ (failed nil))
+ (condition-case err
+ (funcall handler proc string)
+ (error
+ (ding)
+ (setq failed t)
+ (message "bridge-handler \"%s\" failed %s (see bridge-last-failure)"
+ handler err)
+ (setq bridge-last-failure
+ (` ((funcall '(, handler) '(, proc) (, string))
+ "Caused: "
+ (, err))))))
+ (not failed)))
+
+;;;%Handlers
+(defun bridge-send-handler (process input)
+ "Send PROCESS INPUT to the buffer name found at the start of the
+input. The input after the buffer name is sent to the buffer's
+process if it has one. If bridge-destination-insert is T, the input
+will be inserted into the buffer. If it does not have a process, it
+will be inserted at the end of the buffer."
+ (if (null input)
+ (setq bridge-send-to-buffer nil) ; end of bridge
+ (let (buffer-and-start buffer-name dest to)
+ ;; if this is first time, get the buffer out of the first line
+ (cond ((not bridge-send-to-buffer)
+ (setq buffer-and-start (read-from-string input)
+ buffer-name (format "%s" (car (read-from-string input)))
+ dest (get-buffer buffer-name)
+ to (get-buffer-process dest)
+ input (substring input (cdr buffer-and-start)))
+ (setq bridge-send-to-buffer dest))
+ (t
+ (setq buffer-name bridge-send-to-buffer
+ dest (get-buffer buffer-name)
+ to (get-buffer-process dest)
+ )))
+ (if dest
+ (let ((buffer (current-buffer)))
+ (if bridge-destination-insert
+ (unwind-protect
+ (progn
+ (set-buffer dest)
+ (if to
+ (bridge-insert process input)
+ (goto-char (point-max))
+ (insert input)))
+ (set-buffer buffer)))
+ (if to
+ ;; (bridge-send-string to input)
+ (process-send-string to input)
+ ))
+ (error "%s is not a buffer" buffer-name)))))
+
+;;;%Filter
+(defun bridge-filter (process output)
+ "Given PROCESS and some OUTPUT, check for the presence of
+bridge-start-regexp. Everything prior to this will be passed to the
+normal filter function or inserted in the buffer if it is nil. The
+output up to bridge-end-regexp will be sent to the first handler on
+bridge-handlers that matches the string. If no handlers match, the
+input will be sent to bridge-send-handler. If bridge-prompt-regexp is
+encountered before the bridge-end-regexp, the bridge will be cancelled."
+ (let ((inhibit-quit t)
+ (match-data (match-data))
+ (buffer (current-buffer))
+ (process-buffer (process-buffer process))
+ (case-fold-search t)
+ (start 0) (end 0)
+ function
+ b-start b-start-end b-end)
+ (set-buffer process-buffer) ;; access locals
+
+ ;; Handle bridge messages that straddle a packet by prepending
+ ;; them to this packet.
+
+ (when bridge-leftovers
+ (setq output (concat bridge-leftovers output))
+ (setq bridge-leftovers nil))
+
+ (setq function bridge-in-progress)
+
+ ;; How it works:
+ ;;
+ ;; start, end delimit the part of string we are interested in;
+ ;; initially both 0; after an iteration we move them to next string.
+
+ ;; b-start, b-end delimit part of string to bridge (possibly whole string);
+ ;; this will be string between corresponding regexps.
+
+ ;; There are two main cases when we come into loop:
+
+ ;; bridge in progress
+ ;;0 setq b-start = start
+ ;;1 setq b-end (or end-pattern end)
+ ;;4 process string
+ ;;5 remove handler if end found
+
+ ;; no bridge in progress
+ ;;0 setq b-start if see start-pattern
+ ;;1 setq b-end if bstart to (or end-pattern end)
+ ;;2 send (substring start b-start) to normal place
+ ;;3 find handler (in b-start, b-end) if not set
+ ;;4 process string
+ ;;5 remove handler if end found
+
+ ;; equivalent sections have the same numbers here;
+ ;; we fold them together in this code.
+
+ (block bridge-filter
+ (unwind-protect
+ (while (< end (length output))
+
+ ;;0 setq b-start if find
+ (setq b-start
+ (cond (bridge-in-progress
+ (setq b-start-end start)
+ start)
+ ((string-match bridge-start-regexp output start)
+ (setq b-start-end (match-end 0))
+ (match-beginning 0))
+ (t nil)))
+ ;;1 setq b-end
+ (setq b-end
+ (if b-start
+ (let ((end-seen (string-match bridge-end-regexp
+ output b-start-end)))
+ (if end-seen (setq end (match-end 0)))
+
+ end-seen)))
+
+ ;; Detect and save partial bridge messages
+ (when (and b-start b-start-end (not b-end))
+ (setq bridge-leftovers (substring output b-start))
+ )
+
+ (if (and b-start (not b-end))
+ (setq end b-start)
+ (if (not b-end)
+ (setq end (length output))))
+
+ ;;1.5 - if see prompt before end, remove current
+ (if (and b-start b-end)
+ (let ((prompt (string-match bridge-prompt-regexp
+ output b-start-end)))
+ (if (and prompt (<= (match-end 0) b-end))
+ (setq b-start nil ; b-start-end start
+ b-end start
+ end (match-end 0)
+ bridge-in-progress nil
+ ))))
+
+ ;;2 send (substring start b-start) to old filter, if any
+ (when (not (equal start (or b-start end))) ; don't bother on empty string
+ (let ((pass-on (substring output start (or b-start end))))
+ (if bridge-old-filter
+ (let ((old bridge-old-filter))
+ (store-match-data match-data)
+ (funcall old process pass-on)
+ ;; if filter changed, re-install ourselves
+ (let ((new (process-filter process)))
+ (if (not (eq new 'bridge-filter))
+ (progn (setq bridge-old-filter new)
+ (set-process-filter process 'bridge-filter)))))
+ (set-buffer process-buffer)
+ (bridge-insert pass-on))))
+
+ (if (and b-start-end (not b-end))
+ (return-from bridge-filter t) ; when last bit has prematurely ending message, exit early.
+ (progn
+ ;;3 find handler (in b-start, b-end) if none current
+ (if (and b-start (not bridge-in-progress))
+ (let ((handlers bridge-handlers))
+ (while (and handlers (not function))
+ (let* ((handler (car handlers))
+ (m (string-match (car handler) output b-start-end)))
+ (if (and m (< m b-end))
+ (setq function (cdr handler))
+ (setq handlers (cdr handlers)))))
+ ;; Set default handler if none
+ (if (null function)
+ (setq function 'bridge-send-handler))
+ (setq bridge-in-progress function)))
+ ;;4 process strin
+ (if function
+ (let ((ok t))
+ (if (/= b-start-end b-end)
+ (let ((send (substring output b-start-end b-end)))
+ ;; also, insert the stuff in buffer between
+ ;; iff bridge-source-insert.
+ (if bridge-source-insert (bridge-insert send))
+ ;; call handler on string
+ (setq ok (bridge-call-handler function process send))))
+ ;;5 remove handler if end found
+ ;; if function removed then tell it that's all
+ (if (or (not ok) (/= b-end end)) ;; saw end before end-of-string
+ (progn
+ (bridge-call-handler function process nil)
+ ;; have to remove function too for next time around
+ (setq function nil
+ bridge-in-progress nil)
+ ))
+ ))
+
+ ;; continue looping, in case there's more string
+ (setq start end))
+ ))
+ ;; protected forms: restore buffer, match-data
+ (set-buffer buffer)
+ (store-match-data match-data)
+ ))))
+
+
+;;;%Interface
+(defun install-bridge ()
+ "Set up a process bridge in the current buffer."
+ (interactive)
+ (if (not (get-buffer-process (current-buffer)))
+ (error "%s does not have a process" (buffer-name (current-buffer)))
+ (make-local-variable 'bridge-start-regexp)
+ (make-local-variable 'bridge-end-regexp)
+ (make-local-variable 'bridge-prompt-regexp)
+ (make-local-variable 'bridge-handlers)
+ (make-local-variable 'bridge-source-insert)
+ (make-local-variable 'bridge-destination-insert)
+ (make-local-variable 'bridge-chunk-size)
+ (make-local-variable 'bridge-old-filter)
+ (make-local-variable 'bridge-string)
+ (make-local-variable 'bridge-in-progress)
+ (make-local-variable 'bridge-send-to-buffer)
+ (make-local-variable 'bridge-leftovers)
+ (setq bridge-string nil bridge-in-progress nil
+ bridge-send-to-buffer nil)
+ (if (boundp 'comint-prompt-regexp)
+ (setq bridge-prompt-regexp comint-prompt-regexp))
+ (let ((process (get-buffer-process (current-buffer))))
+ (if process
+ (if (not (eq (process-filter process) 'bridge-filter))
+ (progn
+ (setq bridge-old-filter (process-filter process))
+ (set-process-filter process 'bridge-filter)))
+ (error "%s does not have a process"
+ (buffer-name (current-buffer)))))
+ (run-hooks 'bridge-hook)
+ (message "Process bridge is installed")))
+
+;;;
+(defun reset-bridge ()
+ "Must be called from the process's buffer. Removes any active bridge."
+ (interactive)
+ ;; for when things get wedged
+ (if bridge-in-progress
+ (unwind-protect
+ (funcall bridge-in-progress (get-buffer-process
+ (current-buffer))
+ nil)
+ (setq bridge-in-progress nil))
+ (message "No bridge in progress.")))
+
+;;;
+(defun remove-bridge ()
+ "Remove bridge from the current buffer."
+ (interactive)
+ (let ((process (get-buffer-process (current-buffer))))
+ (if (or (not process) (not (eq (process-filter process) 'bridge-filter)))
+ (error "%s has no bridge" (buffer-name (current-buffer)))
+ ;; remove any bridge-in-progress
+ (reset-bridge)
+ (set-process-filter process bridge-old-filter)
+ (funcall bridge-old-filter process bridge-string)
+ (message "Process bridge is removed."))))
+
+;;;% Utility for testing
+(defun hand-bridge (start end)
+ "With point at bridge-start, sends bridge-start + string +
+bridge-end to bridge-filter. With prefix, use current region to send."
+ (interactive "r")
+ (let ((p0 (if current-prefix-arg (min start end)
+ (if (looking-at bridge-start-regexp) (point)
+ (error "Not looking at bridge-start-regexp"))))
+ (p1 (if current-prefix-arg (max start end)
+ (if (re-search-forward bridge-end-regexp nil t)
+ (point) (error "Didn't see bridge-end-regexp")))))
+
+ (bridge-filter (get-buffer-process (current-buffer))
+ (buffer-substring-no-properties p0 p1))
+ ))
+
+(provide 'bridge)
Added: branches/bos/thirdparty/emacs/slime/contrib/inferior-slime.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/inferior-slime.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,88 @@
+;;; inferior-slime.el --- Minor mode with Slime keys for comint buffers
+;;
+;; Author: Luke Gorrie <luke at synap.se>
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'inferior-slime)))
+;; (add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode 1)))
+
+(define-minor-mode inferior-slime-mode
+ "\\<slime-mode-map>\
+Inferior SLIME mode: The Inferior Superior Lisp Mode for Emacs.
+
+This mode is intended for use with `inferior-lisp-mode'. It provides a
+subset of the bindings from `slime-mode'.
+
+\\{inferior-slime-mode-map}"
+ nil
+ nil
+ ;; Fake binding to coax `define-minor-mode' to create the keymap
+ '((" " 'undefined)))
+
+(add-to-list 'minor-mode-alist
+ '(inferior-slime-mode
+ (" Inf-Slime" slime-state-name)))
+
+(defun inferior-slime-return ()
+ "Handle the return key in the inferior-lisp buffer.
+The current input should only be sent if a whole expression has been
+entered, i.e. the parenthesis are matched.
+
+A prefix argument disables this behaviour."
+ (interactive)
+ (if (or current-prefix-arg (inferior-slime-input-complete-p))
+ (comint-send-input)
+ (insert "\n")
+ (inferior-slime-indent-line)))
+
+(defun inferior-slime-indent-line ()
+ "Indent the current line, ignoring everything before the prompt."
+ (interactive)
+ (save-restriction
+ (let ((indent-start
+ (save-excursion
+ (goto-char (process-mark (get-buffer-process (current-buffer))))
+ (let ((inhibit-field-text-motion t))
+ (beginning-of-line 1))
+ (point))))
+ (narrow-to-region indent-start (point-max)))
+ (lisp-indent-line)))
+
+(defun inferior-slime-input-complete-p ()
+ "Return true if the input is complete in the inferior lisp buffer."
+ (slime-input-complete-p (process-mark (get-buffer-process (current-buffer)))
+ (point-max)))
+
+(defun inferior-slime-closing-return ()
+ "Send the current expression to Lisp after closing any open lists."
+ (interactive)
+ (goto-char (point-max))
+ (save-restriction
+ (narrow-to-region (process-mark (get-buffer-process (current-buffer)))
+ (point-max))
+ (while (ignore-errors (save-excursion (backward-up-list 1) t))
+ (insert ")")))
+ (comint-send-input))
+
+(defun inferior-slime-init-keymap ()
+ (let ((map inferior-slime-mode-map))
+ (define-key map [return] 'inferior-slime-return)
+ (define-key map [(control return)] 'inferior-slime-closing-return)
+ (define-key map [(meta control ?m)] 'inferior-slime-closing-return)
+ (define-key map "\C-c\C-d" slime-doc-map)
+ (define-key map "\C-c\C-w" slime-who-map)
+ (loop for (key command . keys) in slime-keys do
+ (destructuring-bind (&key prefixed inferior &allow-other-keys) keys
+ (when prefixed
+ (setq key (concat slime-prefix-key key)))
+ (when inferior
+ (define-key map key command))))))
+
+(inferior-slime-init-keymap)
+
+(provide 'inferior-slime)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-asdf.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-asdf.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,113 @@
+;;; slime-asdf.el -- ASDF support
+;;
+;; Authors: Daniel Barlow <dan at telent.net>
+;; Marco Baringer <mb at bese.it>
+;; Edi Weitz <edi at agharta.de>
+;; and others
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path ".../slime/contrib")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-asdf)))
+;;
+
+;; NOTE: `system-name' is a predefined variable in Emacs. Try to
+;; avoid it as local variable name.
+
+
+(defun slime-load-system (&optional system)
+ "Compile and load an ASDF system.
+
+Default system name is taken from first file matching *.asd in current
+buffer's working directory"
+ (interactive (list (slime-read-system-name)))
+ (slime-oos system "LOAD-OP"))
+
+(defvar slime-system-history nil
+ "History list for ASDF system names.")
+
+(defun slime-read-system-name (&optional prompt initial-value)
+ "Read a system name from the minibuffer, prompting with PROMPT."
+ (setq prompt (or prompt "System: "))
+ (let* ((completion-ignore-case nil)
+ (system-names (slime-eval `(swank:list-asdf-systems)))
+ (alist (slime-bogus-completion-alist system-names)))
+ (completing-read prompt alist nil nil
+ (or initial-value (slime-find-asd system-names) "")
+ 'slime-system-history)))
+
+(defun slime-find-asd (system-names)
+ "Tries to find an ASDF system definition in the default
+directory or in the directory belonging to the current buffer and
+returns it if it's in `system-names'."
+ (let* ((asdf-systems-in-directory
+ (mapcar #'file-name-sans-extension
+ (directory-files
+ (file-name-directory (or default-directory
+ (buffer-file-name)))
+ nil "\.asd$"))))
+ (loop for system in asdf-systems-in-directory
+ for candidate = (file-name-sans-extension system)
+ when (find candidate system-names :test #'string-equal)
+ do (return candidate))))
+
+(defun slime-oos (system operation &rest keyword-args)
+ (slime-save-some-lisp-buffers)
+ (slime-display-output-buffer)
+ (message "Performing ASDF %S%s on system %S"
+ operation (if keyword-args (format " %S" keyword-args) "")
+ system)
+ (slime-eval-async
+ `(swank:operate-on-system-for-emacs ,system ,operation , at keyword-args)
+ (slime-make-compilation-finished-continuation (current-buffer))))
+
+(defslime-repl-shortcut slime-repl-load/force-system ("force-load-system")
+ (:handler (lambda ()
+ (interactive)
+ (slime-oos (slime-read-system-name) "LOAD-OP" :force t)))
+ (:one-liner "Recompile and load an ASDF system."))
+
+(defslime-repl-shortcut slime-repl-load-system ("load-system")
+ (:handler (lambda ()
+ (interactive)
+ (slime-oos (slime-read-system-name) "LOAD-OP")))
+ (:one-liner "Compile (as needed) and load an ASDF system."))
+
+(defslime-repl-shortcut slime-repl-test/force-system ("force-test-system")
+ (:handler (lambda ()
+ (interactive)
+ (slime-oos (slime-read-system-name) "TEST-OP" :force t)))
+ (:one-liner "Compile (as needed) and force test an ASDF system."))
+
+(defslime-repl-shortcut slime-repl-test-system ("test-system")
+ (:handler (lambda ()
+ (interactive)
+ (slime-oos (slime-read-system-name) "TEST-OP")))
+ (:one-liner "Compile (as needed) and test an ASDF system."))
+
+(defslime-repl-shortcut slime-repl-compile-system ("compile-system")
+ (:handler (lambda ()
+ (interactive)
+ (slime-oos (slime-read-system-name) "COMPILE-OP")))
+ (:one-liner "Compile (but not load) an ASDF system."))
+
+(defslime-repl-shortcut slime-repl-compile/force-system
+ ("force-compile-system")
+ (:handler (lambda ()
+ (interactive)
+ (slime-oos (slime-read-system-name) "COMPILE-OP" :force t)))
+ (:one-liner "Recompile (but not load) an ASDF system."))
+
+(defun slime-asdf-on-connect ()
+ (slime-eval-async '(swank:swank-require :swank-asdf)))
+
+(defun slime-asdf-init ()
+ (add-hook 'slime-connected-hook 'slime-asdf-on-connect))
+
+(defun slime-asdf-unload ()
+ (remove-hook 'slime-connected-hook 'slime-asdf-on-connect))
+
+(provide 'slime-asdf)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-autodoc.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-autodoc.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,273 @@
+;;; slime-autodoc.el --- show fancy arglist in echo area
+;;
+;; Authors: Luke Gorrie <luke at bluetail.com>
+;; Lawrence Mitchell <wence at gmx.li>
+;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-autodoc)))
+;;
+
+(require 'slime-parse)
+
+(defvar slime-use-autodoc-mode t
+ "When non-nil always enable slime-autodoc-mode in slime-mode.")
+
+(defun slime-fontify-string (string)
+ "Fontify STRING as `font-lock-mode' does in Lisp mode."
+ (with-current-buffer (get-buffer-create " *slime-fontify*")
+ (erase-buffer)
+ (if (not (eq major-mode 'lisp-mode))
+ (lisp-mode))
+ (insert string)
+ (let ((font-lock-verbose nil))
+ (font-lock-fontify-buffer))
+ (goto-char (point-min))
+ (when (re-search-forward "===> \\(\\(.\\|\n\\)*\\) <===" nil t)
+ (let ((highlight (match-string 1)))
+ ;; Can't use (replace-match highlight) here -- broken in Emacs 21
+ (delete-region (match-beginning 0) (match-end 0))
+ (slime-insert-propertized '(face highlight) highlight)))
+ (buffer-substring (point-min) (point-max))))
+
+(defun slime-arglist (name)
+ "Show the argument list for NAME."
+ (interactive (list (slime-read-symbol-name "Arglist of: ")))
+ (slime-eval-async
+ `(swank:arglist-for-echo-area (quote (,name)))
+ (lambda (arglist)
+ (if arglist
+ (message "%s" (slime-fontify-string arglist))
+ (error "Arglist not available")))))
+
+
+
+;;;; Autodocs (automatic context-sensitive help)
+
+(defvar slime-autodoc-mode nil
+ "*When non-nil, print documentation about symbols as the point moves.")
+
+(defvar slime-autodoc-cache-type 'last
+ "*Cache policy for automatically fetched documentation.
+Possible values are:
+ nil - none.
+ last - cache only the most recently-looked-at symbol's documentation.
+ The values are stored in the variable `slime-autodoc-cache'.
+
+More caching means fewer calls to the Lisp process, but at the risk of
+using outdated information.")
+
+(defvar slime-autodoc-cache nil
+ "Cache variable for when `slime-autodoc-cache-type' is 'last'.
+The value is (SYMBOL-NAME . DOCUMENTATION).")
+
+(defun slime-autodoc-mode (&optional arg)
+ "Enable `slime-autodoc'."
+ (interactive "P")
+ (cond ((< (prefix-numeric-value arg) 0) (setq slime-autodoc-mode nil))
+ (arg (setq slime-autodoc-mode t))
+ (t (setq slime-autodoc-mode (not slime-autodoc-mode))))
+ (if slime-autodoc-mode
+ (progn
+ (slime-autodoc-start-timer)
+ (add-hook 'pre-command-hook
+ 'slime-autodoc-pre-command-refresh-echo-area t))
+ (slime-autodoc-stop-timer)))
+
+(defvar slime-autodoc-last-message "")
+
+(defun slime-autodoc ()
+ "Print some apropos information about the code at point, if applicable."
+ (destructuring-bind (cache-key retrieve-form) (slime-autodoc-thing-at-point)
+ (let ((cached (slime-get-cached-autodoc cache-key)))
+ (if cached
+ (slime-autodoc-message cached)
+ ;; Asynchronously fetch, cache, and display documentation
+ (slime-eval-async
+ retrieve-form
+ (with-lexical-bindings (cache-key)
+ (lambda (doc)
+ (let ((doc (if doc (slime-fontify-string doc) "")))
+ (slime-update-autodoc-cache cache-key doc)
+ (slime-autodoc-message doc)))))))))
+
+(defcustom slime-autodoc-use-multiline-p nil
+ "If non-nil, allow long autodoc messages to resize echo area display."
+ :type 'boolean
+ :group 'slime-ui)
+
+(defvar slime-autodoc-message-function 'slime-autodoc-show-message)
+
+(defun slime-autodoc-message (doc)
+ "Display the autodoc documentation string DOC."
+ (funcall slime-autodoc-message-function doc))
+
+(defun slime-autodoc-show-message (doc)
+ (unless slime-autodoc-use-multiline-p
+ (setq doc (slime-oneliner doc)))
+ (setq slime-autodoc-last-message doc)
+ (message "%s" doc))
+
+(defun slime-autodoc-message-dimensions ()
+ "Return the available width and height for pretty printing autodoc
+messages."
+ (cond
+ (slime-autodoc-use-multiline-p
+ ;; Use the full width of the minibuffer;
+ ;; minibuffer will grow vertically if necessary
+ (values (window-width (minibuffer-window))
+ nil))
+ (t
+ ;; Try to fit everything in one line; we cut off when displaying
+ (values 1000 1))))
+
+(defun slime-autodoc-pre-command-refresh-echo-area ()
+ (unless (string= slime-autodoc-last-message "")
+ (if (slime-autodoc-message-ok-p)
+ (message "%s" slime-autodoc-last-message)
+ (setq slime-autodoc-last-message ""))))
+
+(defun slime-autodoc-thing-at-point ()
+ "Return a cache key and a swank form."
+ (let ((global (slime-autodoc-global-at-point)))
+ (if global
+ (values (slime-qualify-cl-symbol-name global)
+ `(swank:variable-desc-for-echo-area ,global))
+ (multiple-value-bind (operators arg-indices points)
+ (slime-enclosing-form-specs)
+ (values (mapcar* (lambda (designator arg-index)
+ (cons
+ (if (symbolp designator)
+ (slime-qualify-cl-symbol-name designator)
+ designator)
+ arg-index))
+ operators arg-indices)
+ (multiple-value-bind (width height)
+ (slime-autodoc-message-dimensions)
+ `(swank:arglist-for-echo-area ',operators
+ :arg-indices ',arg-indices
+ :print-right-margin ,width
+ :print-lines ,height)))))))
+
+(defun slime-autodoc-global-at-point ()
+ "Return the global variable name at point, if any."
+ (when-let (name (slime-symbol-name-at-point))
+ (if (slime-global-variable-name-p name) name)))
+
+(defcustom slime-global-variable-name-regexp "^\\(.*:\\)?\\([*+]\\).+\\2$"
+ "Regexp used to check if a symbol name is a global variable.
+
+Default value assumes +this+ or *that* naming conventions."
+ :type 'regexp
+ :group 'slime)
+
+(defun slime-global-variable-name-p (name)
+ "Is NAME a global variable?
+Globals are recognised purely by *this-naming-convention*."
+ (and (< (length name) 80) ; avoid overflows in regexp matcher
+ (string-match slime-global-variable-name-regexp name)))
+
+(defun slime-get-cached-autodoc (symbol-name)
+ "Return the cached autodoc documentation for SYMBOL-NAME, or nil."
+ (ecase slime-autodoc-cache-type
+ ((nil) nil)
+ ((last)
+ (when (equal (car slime-autodoc-cache) symbol-name)
+ (cdr slime-autodoc-cache)))
+ ((all)
+ (when-let (symbol (intern-soft symbol-name))
+ (get symbol 'slime-autodoc-cache)))))
+
+(defun slime-update-autodoc-cache (symbol-name documentation)
+ "Update the autodoc cache for SYMBOL with DOCUMENTATION.
+Return DOCUMENTATION."
+ (ecase slime-autodoc-cache-type
+ ((nil) nil)
+ ((last)
+ (setq slime-autodoc-cache (cons symbol-name documentation)))
+ ((all)
+ (put (intern symbol-name) 'slime-autodoc-cache documentation)))
+ documentation)
+
+
+;;;;; Asynchronous message idle timer
+
+(defvar slime-autodoc-idle-timer nil
+ "Idle timer for the next autodoc message.")
+
+(defvar slime-autodoc-delay 0.2
+ "*Delay before autodoc messages are fetched and displayed, in seconds.")
+
+(defun slime-autodoc-start-timer ()
+ "(Re)start the timer that prints autodocs every `slime-autodoc-delay' seconds."
+ (interactive)
+ (when slime-autodoc-idle-timer
+ (cancel-timer slime-autodoc-idle-timer))
+ (setq slime-autodoc-idle-timer
+ (run-with-idle-timer slime-autodoc-delay slime-autodoc-delay
+ 'slime-autodoc-timer-hook)))
+
+(defun slime-autodoc-stop-timer ()
+ "Stop the timer that prints autodocs.
+See also `slime-autodoc-start-timer'."
+ (when slime-autodoc-idle-timer
+ (cancel-timer slime-autodoc-idle-timer)
+ (setq slime-autodoc-idle-timer nil)))
+
+(defun slime-autodoc-timer-hook ()
+ "Function to be called after each Emacs becomes idle.
+When `slime-autodoc-mode' is non-nil, print apropos information about
+the symbol at point if applicable."
+ (when (slime-autodoc-message-ok-p)
+ (condition-case err
+ (slime-autodoc)
+ (error
+ (setq slime-autodoc-mode nil)
+ (message "Error: %S; slime-autodoc-mode now disabled." err)))))
+
+(defun slime-autodoc-message-ok-p ()
+ "Return true if printing a message is currently okay (shouldn't
+annoy the user)."
+ (and (or slime-mode (eq major-mode 'slime-repl-mode)
+ (eq major-mode 'sldb-mode))
+ slime-autodoc-mode
+ (or (null (current-message))
+ (string= (current-message) slime-autodoc-last-message))
+ (not executing-kbd-macro)
+ (not (and (boundp 'edebug-active) (symbol-value 'edebug-active)))
+ (not cursor-in-echo-area)
+ (not (active-minibuffer-window))
+ (not (eq (selected-window) (minibuffer-window)))
+ (slime-background-activities-enabled-p)))
+
+
+;;; Initialization
+
+(defun slime-autodoc-init ()
+ (setq slime-echo-arglist-function 'slime-autodoc)
+ (add-hook 'slime-connected-hook 'slime-autodoc-on-connect)
+ (dolist (h '(slime-mode-hook slime-repl-mode-hook sldb-mode-hook))
+ (add-hook h 'slime-autodoc-maybe-enable)))
+
+(defun slime-autodoc-on-connect ()
+ (slime-eval-async '(swank:swank-require :swank-arglists)))
+
+(defun slime-autodoc-maybe-enable ()
+ (when slime-use-autodoc-mode
+ (slime-autodoc-mode 1)))
+
+(defun slime-autodoc-unload ()
+ (setq slime-echo-arglist-function 'slime-show-arglist)
+ (remove-hook 'slime-connected-hook 'slime-autodoc-on-connect)
+ (dolist (h '(slime-mode-hook slime-repl-mode-hook sldb-mode-hook))
+ (remove-hook h 'slime-autodoc-maybe-enable)))
+
+(provide 'slime-autodoc)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-banner.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-banner.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,44 @@
+;;; slime-banner.el -- Persistent header line and startup animation
+;;
+;; Authors: Helmut Eller <heller at common-lisp.net>
+;; Luke Gorrie <luke at synap.se>
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path ".../slime/contrib")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-banner)))
+
+(defcustom slime-startup-animation (fboundp 'animate-string)
+ "Enable the startup animation."
+ :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil))
+ :group 'slime-ui)
+
+(defcustom slime-header-line-p (boundp 'header-line-format)
+ "If non-nil, display a header line in Slime buffers."
+ :type 'boolean
+ :group 'slime-repl)
+
+(defun slime-startup-message ()
+ (when slime-header-line-p
+ (setq header-line-format
+ (format "%s Port: %s Pid: %s"
+ (slime-lisp-implementation-type)
+ (slime-connection-port (slime-connection))
+ (slime-pid))))
+ (when (zerop (buffer-size))
+ (let ((welcome (concat "; SLIME " (or (slime-changelog-date)
+ "- ChangeLog file not found"))))
+ (if slime-startup-animation
+ (animate-string welcome 0 0)
+ (insert welcome)))))
+
+(defun slime-banner-init ()
+ (setq slime-repl-banner-function 'slime-startup-message))
+
+(defun slime-banner-unload ()
+ (setq slime-repl-banner-function 'slime-repl-insert-banner))
+
+(provide 'slime-banner)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-c-p-c.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-c-p-c.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,202 @@
+;;; slime-c-p-c.el --- ILISP style Compound Prefix Completion
+;;
+;; Authors: Luke Gorrie <luke at synap.se>
+;; Edi Weitz <edi at agharta.de>
+;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-c-p-c)))
+;;
+
+
+
+(require 'slime)
+(require 'slime-parse)
+(require 'slime-editing-commands)
+
+(defcustom slime-c-p-c-unambiguous-prefix-p t
+ "If true, set point after the unambigous prefix.
+If false, move point to the end of the inserted text."
+ :type 'boolean
+ :group 'slime-ui)
+
+(defcustom slime-complete-symbol*-fancy nil
+ "Use information from argument lists for DWIM'ish symbol completion."
+ :group 'slime-mode
+ :type 'boolean)
+
+(defun slime-complete-symbol* ()
+ "Expand abbreviations and complete the symbol at point."
+ ;; NB: It is only the name part of the symbol that we actually want
+ ;; to complete -- the package prefix, if given, is just context.
+ (or (slime-maybe-complete-as-filename)
+ (slime-expand-abbreviations-and-complete)))
+
+;; FIXME: factorize
+(defun slime-expand-abbreviations-and-complete ()
+ (let* ((end (move-marker (make-marker) (slime-symbol-end-pos)))
+ (beg (move-marker (make-marker) (slime-symbol-start-pos)))
+ (prefix (buffer-substring-no-properties beg end))
+ (completion-result (slime-contextual-completions beg end))
+ (completion-set (first completion-result))
+ (completed-prefix (second completion-result)))
+ (if (null completion-set)
+ (progn (slime-minibuffer-respecting-message
+ "Can't find completion for \"%s\"" prefix)
+ (ding)
+ (slime-complete-restore-window-configuration))
+ ;; some XEmacs issue makes this distinction necessary
+ (cond ((> (length completed-prefix) (- end beg))
+ (goto-char end)
+ (insert-and-inherit completed-prefix)
+ (delete-region beg end)
+ (goto-char (+ beg (length completed-prefix))))
+ (t nil))
+ (cond ((and (member completed-prefix completion-set)
+ (slime-length= completion-set 1))
+ (slime-minibuffer-respecting-message "Sole completion")
+ (when slime-complete-symbol*-fancy
+ (slime-complete-symbol*-fancy-bit))
+ (slime-complete-restore-window-configuration))
+ ;; Incomplete
+ (t
+ (when (member completed-prefix completion-set)
+ (slime-minibuffer-respecting-message
+ "Complete but not unique"))
+ (when slime-c-p-c-unambiguous-prefix-p
+ (let ((unambiguous-completion-length
+ (loop for c in completion-set
+ minimizing (or (mismatch completed-prefix c)
+ (length completed-prefix)))))
+ (goto-char (+ beg unambiguous-completion-length))))
+ (slime-display-or-scroll-completions completion-set
+ completed-prefix))))))
+
+(defun slime-complete-symbol*-fancy-bit ()
+ "Do fancy tricks after completing a symbol.
+\(Insert a space or close-paren based on arglist information.)"
+ (let ((arglist (slime-get-arglist (slime-symbol-name-at-point))))
+ (when arglist
+ (let ((args
+ ;; Don't intern these symbols
+ (let ((obarray (make-vector 10 0)))
+ (cdr (read arglist))))
+ (function-call-position-p
+ (save-excursion
+ (backward-sexp)
+ (equal (char-before) ?\())))
+ (when function-call-position-p
+ (if (null args)
+ (insert-and-inherit ")")
+ (insert-and-inherit " ")
+ (when (and slime-space-information-p
+ (slime-background-activities-enabled-p)
+ (not (minibuffer-window-active-p (minibuffer-window))))
+ (slime-echo-arglist))))))))
+
+(defun slime-get-arglist (symbol-name)
+ "Return the argument list for SYMBOL-NAME."
+ (slime-eval `(swank:arglist-for-echo-area (quote (,symbol-name)))))
+
+(defun* slime-contextual-completions (beg end)
+ "Return a list of completions of the token from BEG to END in the
+current buffer."
+ (let ((token (buffer-substring-no-properties beg end)))
+ (cond
+ ((and (< beg (point-max))
+ (string= (buffer-substring-no-properties beg (1+ beg)) ":"))
+ ;; Contextual keyword completion
+ (multiple-value-bind (operator-names arg-indices points)
+ (save-excursion
+ (goto-char beg)
+ (slime-enclosing-form-specs))
+ (when operator-names
+ (let ((completions
+ (slime-completions-for-keyword operator-names token
+ arg-indices)))
+ (when (first completions)
+ (return-from slime-contextual-completions completions))
+ ;; If no matching keyword was found, do regular symbol
+ ;; completion.
+ ))))
+ ((and (> beg 2)
+ (string= (buffer-substring-no-properties (- beg 2) beg) "#\\"))
+ ;; Character name completion
+ (return-from slime-contextual-completions
+ (slime-completions-for-character token))))
+ ;; Regular symbol completion
+ (slime-completions token)))
+
+(defun slime-completions (prefix)
+ (slime-eval `(swank:completions ,prefix ',(slime-current-package))))
+
+(defun slime-completions-for-keyword (operator-designator prefix
+ arg-indices)
+ (slime-eval `(swank:completions-for-keyword ',operator-designator
+ ,prefix
+ ',arg-indices)))
+
+(defun slime-completions-for-character (prefix)
+ (slime-eval `(swank:completions-for-character ,prefix)))
+
+
+;;; Complete form
+
+(defun slime-complete-form ()
+ "Complete the form at point.
+This is a superset of the functionality of `slime-insert-arglist'."
+ (interactive)
+ ;; Find the (possibly incomplete) form around point.
+ (let ((form-string (slime-incomplete-form-at-point)))
+ (let ((result (slime-eval `(swank:complete-form ',form-string))))
+ (if (eq result :not-available)
+ (error "Could not generate completion for the form `%s'" form-string)
+ (progn
+ (just-one-space)
+ (save-excursion
+ ;; SWANK:COMPLETE-FORM always returns a closing
+ ;; parenthesis; but we only want to insert one if it's
+ ;; really necessary (thinking especially of paredit.el.)
+ (insert (substring result 0 -1))
+ (let ((slime-close-parens-limit 1))
+ (slime-close-all-parens-in-sexp)))
+ (save-excursion
+ (backward-up-list 1)
+ (indent-sexp)))))))
+
+;;; Initialization
+
+(defvar slime-c-p-c-init-undo-stack nil)
+
+(defun slime-c-p-c-init ()
+ ;; save current state for unload
+ (push
+ `(progn
+ (setq slime-complete-symbol-function ',slime-complete-symbol-function)
+ (remove-hook 'slime-connected-hook 'slime-c-p-c-on-connect)
+ (define-key slime-mode-map "\C-c\C-s"
+ ',(lookup-key slime-mode-map "\C-c\C-s"))
+ (define-key slime-repl-mode-map "\C-c\C-s"
+ ',(lookup-key slime-repl-mode-map "\C-c\C-s")))
+ slime-c-p-c-init-undo-stack)
+ (setq slime-complete-symbol-function 'slime-complete-symbol*)
+ (add-hook 'slime-connected-hook 'slime-c-p-c-on-connect)
+ (define-key slime-mode-map "\C-c\C-s" 'slime-complete-form)
+ (define-key slime-repl-mode-map "\C-c\C-s" 'slime-complete-form))
+
+(defun slime-c-p-c-on-connect ()
+ (slime-eval-async '(swank:swank-require :swank-arglists)))
+
+(defun slime-c-p-c-unload ()
+ (while slime-c-p-c-init-undo-stack
+ (eval (pop slime-c-p-c-init-undo-stack))))
+
+(provide 'slime-c-p-c)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-editing-commands.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-editing-commands.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,189 @@
+;;; slime-editing-commands.el -- editing commands whithout server interaction
+;;
+;; Authors: Thomas F. Burdick <tfb at OCF.Berkeley.EDU>
+;; Luke Gorrie <luke at synap.se>
+;; Bill Clementson <billclem at gmail.com>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-editing-commands)))
+;;
+
+(defun slime-beginning-of-defun ()
+ (interactive)
+ (if (and (boundp 'slime-repl-input-start-mark)
+ slime-repl-input-start-mark)
+ (slime-repl-beginning-of-defun)
+ (beginning-of-defun)))
+
+(defun slime-end-of-defun ()
+ (interactive)
+ (if (and (boundp 'slime-repl-input-end-mark)
+ slime-repl-input-end-mark)
+ (slime-repl-end-of-defun)
+ (end-of-defun)))
+
+(defvar slime-comment-start-regexp
+ "\\(\\(^\\|[^\n\\\\]\\)\\([\\\\][\\\\]\\)*\\);+[ \t]*"
+ "Regexp to match the start of a comment.")
+
+(defun slime-beginning-of-comment ()
+ "Move point to beginning of comment.
+If point is inside a comment move to beginning of comment and return point.
+Otherwise leave point unchanged and return NIL."
+ (let ((boundary (point)))
+ (beginning-of-line)
+ (cond ((re-search-forward slime-comment-start-regexp boundary t)
+ (point))
+ (t (goto-char boundary)
+ nil))))
+
+(defun slime-close-all-parens-in-sexp (&optional region)
+ "Balance parentheses of open s-expressions at point.
+Insert enough right parentheses to balance unmatched left parentheses.
+Delete extra left parentheses. Reformat trailing parentheses
+Lisp-stylishly.
+
+If REGION is true, operate on the region. Otherwise operate on
+the top-level sexp before point."
+ (interactive "P")
+ (let ((sexp-level 0)
+ point)
+ (save-excursion
+ (save-restriction
+ (when region
+ (narrow-to-region (region-beginning) (region-end))
+ (goto-char (point-max)))
+ ;; skip over closing parens, but not into comment
+ (skip-chars-backward ") \t\n")
+ (when (slime-beginning-of-comment)
+ (forward-line)
+ (skip-chars-forward " \t"))
+ (setq point (point))
+ ;; count sexps until either '(' or comment is found at first column
+ (while (and (not (looking-at "^[(;]"))
+ (ignore-errors (backward-up-list 1) t))
+ (incf sexp-level))))
+ (when (> sexp-level 0)
+ ;; insert correct number of right parens
+ (goto-char point)
+ (dotimes (i sexp-level) (insert ")"))
+ ;; delete extra right parens
+ (setq point (point))
+ (skip-chars-forward " \t\n)")
+ (skip-chars-backward " \t\n")
+ (let* ((deleted-region (slime-delete-and-extract-region point (point)))
+ (deleted-text (substring-no-properties deleted-region))
+ (prior-parens-count (count ?\) deleted-text)))
+ ;; Remember: we always insert as many parentheses as necessary
+ ;; and only afterwards delete the superfluously-added parens.
+ (when slime-close-parens-limit
+ (let ((missing-parens (- sexp-level prior-parens-count
+ slime-close-parens-limit)))
+ (dotimes (i (max 0 missing-parens))
+ (delete-char -1))))))))
+
+(defvar slime-close-parens-limit nil
+ "Maxmimum parens for `slime-close-all-sexp' to insert. NIL
+means to insert as many parentheses as necessary to correctly
+close the form.")
+
+(defun slime-insert-balanced-comments (arg)
+ "Insert a set of balanced comments around the s-expression
+containing the point. If this command is invoked repeatedly
+\(without any other command occurring between invocations), the
+comment progressively moves outward over enclosing expressions.
+If invoked with a positive prefix argument, the s-expression arg
+expressions out is enclosed in a set of balanced comments."
+ (interactive "*p")
+ (save-excursion
+ (when (eq last-command this-command)
+ (when (search-backward "#|" nil t)
+ (save-excursion
+ (delete-char 2)
+ (while (and (< (point) (point-max)) (not (looking-at " *|#")))
+ (forward-sexp))
+ (replace-match ""))))
+ (while (> arg 0)
+ (backward-char 1)
+ (cond ((looking-at ")") (incf arg))
+ ((looking-at "(") (decf arg))))
+ (insert "#|")
+ (forward-sexp)
+ (insert "|#")))
+
+(defun slime-remove-balanced-comments ()
+ "Remove a set of balanced comments enclosing point."
+ (interactive "*")
+ (save-excursion
+ (when (search-backward "#|" nil t)
+ (delete-char 2)
+ (while (and (< (point) (point-max)) (not (looking-at " *|#")))
+ (forward-sexp))
+ (replace-match ""))))
+
+
+;; SLIME-CLOSE-PARENS-AT-POINT is obsolete:
+
+;; It doesn't work correctly on the REPL, because there
+;; BEGINNING-OF-DEFUN-FUNCTION and END-OF-DEFUN-FUNCTION is bound to
+;; SLIME-REPL-MODE-BEGINNING-OF-DEFUN (and
+;; SLIME-REPL-MODE-END-OF-DEFUN respectively) which compromises the
+;; way how they're expect to work (i.e. END-OF-DEFUN does not signal
+;; an UNBOUND-PARENTHESES error.)
+
+;; Use SLIME-CLOSE-ALL-PARENS-IN-SEXP instead.
+
+;; (defun slime-close-parens-at-point ()
+;; "Close parenthesis at point to complete the top-level-form. Simply
+;; inserts ')' characters at point until `beginning-of-defun' and
+;; `end-of-defun' execute without errors, or `slime-close-parens-limit'
+;; is exceeded."
+;; (interactive)
+;; (loop for i from 1 to slime-close-parens-limit
+;; until (save-excursion
+;; (slime-beginning-of-defun)
+;; (ignore-errors (slime-end-of-defun) t))
+;; do (insert ")")))
+
+(defun slime-reindent-defun (&optional force-text-fill)
+ "Reindent the current defun, or refill the current paragraph.
+If point is inside a comment block, the text around point will be
+treated as a paragraph and will be filled with `fill-paragraph'.
+Otherwise, it will be treated as Lisp code, and the current defun
+will be reindented. If the current defun has unbalanced parens,
+an attempt will be made to fix it before reindenting.
+
+When given a prefix argument, the text around point will always
+be treated as a paragraph. This is useful for filling docstrings."
+ (interactive "P")
+ (save-excursion
+ (if (or force-text-fill (slime-beginning-of-comment))
+ (fill-paragraph nil)
+ (let ((start (progn (unless (or (and (zerop (current-column))
+ (eq ?\( (char-after)))
+ (and slime-repl-input-start-mark
+ (slime-repl-at-prompt-start-p)))
+ (slime-beginning-of-defun))
+ (point)))
+ (end (ignore-errors (slime-end-of-defun) (point))))
+ (unless end
+ (forward-paragraph)
+ (slime-close-all-parens-in-sexp)
+ (slime-end-of-defun)
+ (setf end (point)))
+ (indent-region start end nil)))))
+
+(defun slime-editing-commands-init ()
+ (define-key slime-mode-map "\M-\C-a" 'slime-beginning-of-defun)
+ (define-key slime-mode-map "\M-\C-e" 'slime-end-of-defun)
+ (define-key slime-mode-map "\C-c\M-q" 'slime-reindent-defun))
+
+(provide 'slime-editing-commands)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-fancy-inspector.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-fancy-inspector.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,28 @@
+;;; slime-fancy-inspector.el --- Fancy inspector for CLOS objects
+;;
+;; Author: Marco Baringer <mb at bese.it> and others
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-fancy-inspector)))
+;; (add-hook 'slime-connected-hook 'slime-install-fancy-inspector)
+
+(defun slime-install-fancy-inspector ()
+ (slime-eval-async '(swank:swank-require :swank-fancy-inspector)
+ (lambda (_)
+ (slime-eval-async '(swank:fancy-inspector-init)))))
+
+(defun slime-deinstall-fancy-inspector ()
+ (slime-eval-async '(swank:fancy-inspector-unload)))
+
+(defun slime-fancy-inspector-init ()
+ (add-hook 'slime-connected-hook 'slime-install-fancy-inspector))
+
+(defun slime-fancy-inspector-unload ()
+ (remove-hook 'slime-connected-hook 'slime-install-fancy-inspector))
+
+(provide 'slime-fancy-inspector)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-fancy.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-fancy.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,74 @@
+;;; slime-fancy.el --- Load and init some fancy SLIME contribs
+;;
+;; Authors: Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-fancy)))
+;;
+;; We load all SLIME contribs that are currently working,
+;; and which only "upgrade" the behavior of SLIME in some way.
+;; This includes:
+;; * Adding new commands, keybindings, menu items
+;; * Making things clickable that would otherwise be just plain text
+
+;; Better arglist display, can be turned off by customization.
+(require 'slime-autodoc)
+(slime-autodoc-init)
+
+;; Adds new commands and installs compound-prefix-completion as
+;; default completion command. Behaves similar to standard Emacs
+;; completion, unless dashes are present. --mkoeppe
+(require 'slime-c-p-c)
+(slime-c-p-c-init)
+
+;; Just adds commands. (Well, shadows commands in lisp-mode-map)
+(require 'slime-editing-commands)
+(slime-editing-commands-init)
+
+;; Makes the inspector fancier.
+(require 'slime-fancy-inspector)
+(slime-fancy-inspector-init)
+
+;; Just adds the command C-c M-i. We do not make fuzzy completion the
+;; default completion invoked by TAB. --mkoeppe
+(require 'slime-fuzzy)
+(slime-fuzzy-init)
+
+;; Do not activate slime-highlighting-edits by default, as it's easier
+;; to explictly activate it (if a user really wants it) than to explictly
+;; deactivate it once it got globally enabled. -TCR.
+(require 'slime-highlight-edits)
+;(slime-highlight-edits-init)
+
+;; Load slime-presentations even though they seem to be a
+;; controversial feature, as they can be easily turned off by
+;; customizing swank:*record-repl-results*. --mkoeppe
+(require 'slime-presentations)
+(slime-presentations-init)
+
+;;; Do not load slime-presentation-streams, as this is an experimental
+;;; feature that installs patches into some Lisps. --mkoeppe
+;;(require 'slime-presentation-streams)
+
+(require 'slime-scratch)
+(slime-scratch-init)
+
+;;; Do not load slime-typeout-frame, as simply loading causes display of a
+;;; typeout frame, which cannot be turned off. --mkoeppe
+;;(require 'slime-typeout-frame)
+
+;; Just adds commands.
+(when (locate-library "tree-widget")
+ (require 'slime-xref-browser))
+
+;; Puts clickable references to documentation into SBCL errors.
+(require 'slime-references)
+(slime-references-init)
+
+(provide 'slime-fancy)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-fuzzy.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-fuzzy.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,596 @@
+;;; slime-fuzzy.el --- fuzzy symbol completion
+;;
+;; Authors: Brian Downing <bdowning at lavos.net>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; Attila Lendvai <attila.lendvai at gmail.com>
+;; and others
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-fuzzy)))
+;;
+
+
+;;; Code
+
+(defcustom slime-fuzzy-completion-in-place t
+ "When non-NIL the fuzzy symbol completion is done in place as
+opposed to moving the point to the completion buffer."
+ :group 'slime-mode
+ :type 'boolean)
+
+(defcustom slime-fuzzy-completion-limit 300
+ "Only return and present this many symbols from swank."
+ :group 'slime-mode
+ :type 'integer)
+
+(defcustom slime-fuzzy-completion-time-limit-in-msec 1500
+ "Limit the time spent (given in msec) in swank while gathering
+comletitions."
+ :group 'slime-mode
+ :type 'integer)
+
+(defvar slime-fuzzy-target-buffer nil
+ "The buffer that is the target of the completion activities.")
+(defvar slime-fuzzy-saved-window-configuration nil
+ "The saved window configuration before the fuzzy completion
+buffer popped up.")
+(defvar slime-fuzzy-start nil
+ "The beginning of the completion slot in the target buffer.
+This is a non-advancing marker.")
+(defvar slime-fuzzy-end nil
+ "The end of the completion slot in the target buffer.
+This is an advancing marker.")
+(defvar slime-fuzzy-original-text nil
+ "The original text that was in the completion slot in the
+target buffer. This is what is put back if completion is
+aborted.")
+(defvar slime-fuzzy-text nil
+ "The text that is currently in the completion slot in the
+target buffer. If this ever doesn't match, the target buffer has
+been modified and we abort without touching it.")
+(defvar slime-fuzzy-first nil
+ "The position of the first completion in the completions buffer.
+The descriptive text and headers are above this.")
+(defvar slime-fuzzy-last nil
+ "The position of the last completion in the completions buffer.
+If the time limit has exhausted during generation possible completion
+choices inside SWANK, an indication is printed below this.")
+(defvar slime-fuzzy-current-completion nil
+ "The current completion object. If this is the same before and
+after point moves in the completions buffer, the text is not
+replaced in the target for efficiency.")
+(defvar slime-fuzzy-current-completion-overlay nil
+ "The overlay representing the current completion in the completion
+buffer. This is used to hightlight the text.")
+
+;;;;;;; slime-target-buffer-fuzzy-completions-mode
+;; NOTE: this mode has to be able to override key mappings in slime-mode
+
+;; FIXME: clean this up
+
+(defun mimic-key-bindings (from-keymap to-keymap bindings-or-operation operation)
+ "Iterate on BINDINGS-OR-OPERATION. If an element is a symbol then
+try to look it up (as an operation) in FROM-KEYMAP. Non symbols are taken
+as default key bindings when none to be mimiced was found in FROM-KEYMAP.
+Set the resulting list of keys in TO-KEYMAP to OPERATION."
+ (let ((mimic-keys nil)
+ (direct-keys nil))
+ (dolist (key-or-operation bindings-or-operation)
+ (if (symbolp key-or-operation)
+ (setf mimic-keys (append mimic-keys (where-is-internal key-or-operation from-keymap nil t)))
+ (push key-or-operation direct-keys)))
+ (dolist (key (or mimic-keys direct-keys))
+ (define-key to-keymap key operation))))
+
+(defvar slime-target-buffer-fuzzy-completions-map
+ (let* ((map (make-sparse-keymap)))
+ (flet ((remap (keys to)
+ (mimic-key-bindings global-map map keys to)))
+
+ (remap (list 'keyboard-quit (kbd "C-g")) 'slime-fuzzy-abort)
+
+ (remap (list 'slime-fuzzy-indent-and-complete-symbol
+ 'slime-indent-and-complete-symbol
+ (kbd "<tab>"))
+ 'slime-fuzzy-select-or-update-completions)
+ (remap (list 'previous-line (kbd "<up>")) 'slime-fuzzy-prev)
+ (remap (list 'next-line (kbd "<down>")) 'slime-fuzzy-next)
+ (remap (list 'isearch-forward (kbd "C-s"))
+ (lambda ()
+ (interactive)
+ (select-window (get-buffer-window (slime-get-fuzzy-buffer)))
+ (call-interactively 'isearch-forward)))
+
+ ;; some unconditional direct bindings
+ (dolist (key (list (kbd "<return>") (kbd "RET") (kbd "<SPC>") "(" ")" "[" "]"))
+ (define-key map key 'slime-fuzzy-select-and-process-event-in-target-buffer)))
+ map
+ )
+ "Keymap for slime-target-buffer-fuzzy-completions-mode. This will override the key
+bindings in the target buffer temporarily during completion.")
+
+;; Make sure slime-fuzzy-target-buffer-completions-mode's map is
+;; before everything else.
+(setf minor-mode-map-alist
+ (stable-sort minor-mode-map-alist
+ (lambda (a b)
+ (eq a 'slime-fuzzy-target-buffer-completions-mode))
+ :key #'car))
+
+
+(define-minor-mode slime-fuzzy-target-buffer-completions-mode
+ "This minor mode is intented to override key bindings during fuzzy
+completions in the target buffer. Most of the bindings will do an implicit select
+in the completion window and let the keypress be processed in the target buffer."
+ nil
+ nil
+ slime-target-buffer-fuzzy-completions-map)
+
+(add-to-list 'minor-mode-alist
+ '(slime-fuzzy-target-buffer-completions-mode
+ " Fuzzy Target Buffer Completions"))
+
+(define-derived-mode slime-fuzzy-completions-mode
+ fundamental-mode "Fuzzy Completions"
+ "Major mode for presenting fuzzy completion results.
+
+When you run `slime-fuzzy-complete-symbol', the symbol token at
+point is completed using the Fuzzy Completion algorithm; this
+means that the token is taken as a sequence of characters and all
+the various possibilities that this sequence could meaningfully
+represent are offered as selectable choices, sorted by how well
+they deem to be a match for the token. (For instance, the first
+choice of completing on \"mvb\" would be \"multiple-value-bind\".)
+
+Therefore, a new buffer (*Fuzzy Completions*) will pop up that
+contains the different completion choices. Simultaneously, a
+special minor-mode will be temporarily enabled in the original
+buffer where you initiated fuzzy completion (also called the
+``target buffer'') in order to navigate through the *Fuzzy
+Completions* buffer without leaving.
+
+With focus in *Fuzzy Completions*:
+ Type `n' and `p' (`UP', `DOWN') to navigate between completions.
+ Type `RET' or `TAB' to select the completion near point.
+ Type `q' to abort.
+
+With focus in the target buffer:
+ Type `UP' and `DOWN' to navigate between completions.
+ Type a character that does not constitute a symbol name
+ to insert the current choice and then that character (`(', `)',
+ `SPACE', `RET'.) Use `TAB' to simply insert the current choice.
+ Use C-g to abort.
+
+Alternatively, you can click <mouse-2> on a completion to select it.
+
+
+Complete listing of keybindings within the target buffer:
+
+\\<slime-target-buffer-fuzzy-completions-map>\
+\\{slime-target-buffer-fuzzy-completions-map}
+
+Complete listing of keybindings with *Fuzzy Completions*:
+
+\\<slime-fuzzy-completions-map>\
+\\{slime-fuzzy-completions-map}"
+ (use-local-map slime-fuzzy-completions-map))
+
+(defvar slime-fuzzy-completions-map
+ (let* ((map (make-sparse-keymap)))
+ (flet ((remap (keys to)
+ (mimic-key-bindings global-map map keys to)))
+ (remap (list 'keyboard-quit (kbd "C-g")) 'slime-fuzzy-abort)
+ (define-key map "q" 'slime-fuzzy-abort)
+
+ (remap (list 'previous-line (kbd "<up>")) 'slime-fuzzy-prev)
+ (remap (list 'next-line (kbd "<down>")) 'slime-fuzzy-next)
+
+ (define-key map "n" 'slime-fuzzy-next)
+ (define-key map "\M-n" 'slime-fuzzy-next)
+
+ (define-key map "p" 'slime-fuzzy-prev)
+ (define-key map "\M-p" 'slime-fuzzy-prev)
+
+ (define-key map "\d" 'scroll-down)
+
+ (remap (list 'slime-fuzzy-indent-and-complete-symbol
+ 'slime-indent-and-complete-symbol
+ (kbd "<tab>"))
+ 'slime-fuzzy-select)
+
+ (define-key map (kbd "<mouse-2>") 'slime-fuzzy-select/mouse))
+
+ (define-key map (kbd "RET") 'slime-fuzzy-select)
+ (define-key map (kbd "<SPC>") 'slime-fuzzy-select)
+
+ map)
+ "Keymap for slime-fuzzy-completions-mode when in the completion buffer.")
+
+(defun slime-fuzzy-completions (prefix &optional default-package)
+ "Get the list of sorted completion objects from completing
+`prefix' in `package' from the connected Lisp."
+ (let ((prefix (etypecase prefix
+ (symbol (symbol-name prefix))
+ (string prefix))))
+ (slime-eval `(swank:fuzzy-completions ,prefix
+ ,(or default-package
+ (slime-find-buffer-package)
+ (slime-current-package))
+ :limit ,slime-fuzzy-completion-limit
+ :time-limit-in-msec ,slime-fuzzy-completion-time-limit-in-msec))))
+
+(defun slime-fuzzy-selected (prefix completion)
+ "Tell the connected Lisp that the user selected completion
+`completion' as the completion for `prefix'."
+ (let ((no-properties (copy-sequence prefix)))
+ (set-text-properties 0 (length no-properties) nil no-properties)
+ (slime-eval `(swank:fuzzy-completion-selected ,no-properties
+ ',completion))))
+
+(defun slime-fuzzy-indent-and-complete-symbol ()
+ "Indent the current line and perform fuzzy symbol completion. First
+indent the line. If indenting doesn't move point, complete the
+symbol. If there's no symbol at the point, show the arglist for the
+most recently enclosed macro or function."
+ (interactive)
+ (let ((pos (point)))
+ (unless (get-text-property (line-beginning-position) 'slime-repl-prompt)
+ (lisp-indent-line))
+ (when (= pos (point))
+ (cond ((save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t))
+ (slime-fuzzy-complete-symbol))
+ ((memq (char-before) '(?\t ?\ ))
+ (slime-echo-arglist))))))
+
+(defun* slime-fuzzy-complete-symbol ()
+ "Fuzzily completes the abbreviation at point into a symbol."
+ (interactive)
+ (when (save-excursion (re-search-backward "\"[^ \t\n]+\\=" nil t))
+ (return-from slime-fuzzy-complete-symbol
+ (if slime-when-complete-filename-expand
+ (comint-replace-by-expanded-filename)
+ (comint-dynamic-complete-as-filename))))
+ (let* ((end (move-marker (make-marker) (slime-symbol-end-pos)))
+ (beg (move-marker (make-marker) (slime-symbol-start-pos)))
+ (prefix (buffer-substring-no-properties beg end)))
+ (destructuring-bind (completion-set interrupted-p)
+ (slime-fuzzy-completions prefix)
+ (if (null completion-set)
+ (progn (slime-minibuffer-respecting-message
+ "Can't find completion for \"%s\"" prefix)
+ (ding)
+ (slime-fuzzy-done))
+ (goto-char end)
+ (cond ((slime-length= completion-set 1)
+ (insert-and-inherit (caar completion-set)) ; insert completed string
+ (delete-region beg end)
+ (goto-char (+ beg (length (caar completion-set))))
+ (slime-minibuffer-respecting-message "Sole completion")
+ (slime-fuzzy-done))
+ ;; Incomplete
+ (t
+ (slime-minibuffer-respecting-message "Complete but not unique")
+ (slime-fuzzy-choices-buffer completion-set interrupted-p beg end)))))))
+
+
+(defun slime-get-fuzzy-buffer ()
+ (get-buffer-create "*Fuzzy Completions*"))
+
+(defvar slime-fuzzy-explanation
+ "For help on how the use this buffer, see `slime-fuzzy-completions-mode'.
+
+Flags: boundp fboundp generic-function class macro special-operator package
+\n"
+ "The explanation that gets inserted at the beginning of the
+*Fuzzy Completions* buffer.")
+
+(defun slime-fuzzy-insert-completion-choice (completion max-length)
+ "Inserts the completion object `completion' as a formatted
+completion choice into the current buffer, and mark it with the
+proper text properties."
+ (let ((start (point))
+ (symbol-name (first completion))
+ (score (second completion))
+ (chunks (third completion))
+ (flags (fourth completion)))
+ (insert symbol-name)
+ (let ((end (point)))
+ (dolist (chunk chunks)
+ (put-text-property (+ start (first chunk))
+ (+ start (first chunk)
+ (length (second chunk)))
+ 'face 'bold))
+ (put-text-property start (point) 'mouse-face 'highlight)
+ (dotimes (i (- max-length (- end start)))
+ (insert " "))
+ (insert (format " %s%s%s%s%s%s%s %8.2f"
+ (if (member :boundp flags) "b" "-")
+ (if (member :fboundp flags) "f" "-")
+ (if (member :generic-function flags) "g" "-")
+ (if (member :class flags) "c" "-")
+ (if (member :macro flags) "m" "-")
+ (if (member :special-operator flags) "s" "-")
+ (if (member :package flags) "p" "-")
+ score))
+ (insert "\n")
+ (put-text-property start (point) 'completion completion))))
+
+(defun slime-fuzzy-insert (text)
+ "Inserts `text' into the target buffer in the completion slot.
+If the buffer has been modified in the meantime, abort the
+completion process. Otherwise, update all completion variables
+so that the new text is present."
+ (with-current-buffer slime-fuzzy-target-buffer
+ (cond
+ ((not (string-equal slime-fuzzy-text
+ (buffer-substring slime-fuzzy-start
+ slime-fuzzy-end)))
+ (slime-fuzzy-done)
+ (beep)
+ (message "Target buffer has been modified!"))
+ (t
+ (goto-char slime-fuzzy-start)
+ (delete-region slime-fuzzy-start slime-fuzzy-end)
+ (insert-and-inherit text)
+ (setq slime-fuzzy-text text)
+ (goto-char slime-fuzzy-end)))))
+
+(defun slime-fuzzy-choices-buffer (completions interrupted-p start end)
+ "Creates (if neccessary), populates, and pops up the *Fuzzy
+Completions* buffer with the completions from `completions' and
+the completion slot in the current buffer bounded by `start' and
+`end'. This saves the window configuration before popping the
+buffer so that it can possibly be restored when the user is
+done."
+ (let ((new-completion-buffer (not slime-fuzzy-target-buffer)))
+ (when new-completion-buffer
+ (setq slime-fuzzy-saved-window-configuration
+ (current-window-configuration)))
+ (slime-fuzzy-enable-target-buffer-completions-mode)
+ (setq slime-fuzzy-target-buffer (current-buffer))
+ (setq slime-fuzzy-start (move-marker (make-marker) start))
+ (setq slime-fuzzy-end (move-marker (make-marker) end))
+ (set-marker-insertion-type slime-fuzzy-end t)
+ (setq slime-fuzzy-original-text (buffer-substring start end))
+ (setq slime-fuzzy-text slime-fuzzy-original-text)
+ (slime-fuzzy-fill-completions-buffer completions interrupted-p)
+ (pop-to-buffer (slime-get-fuzzy-buffer))
+ (when new-completion-buffer
+ ;; Hook to nullify window-config restoration if the user changes
+ ;; the window configuration himself.
+ (when (boundp 'window-configuration-change-hook)
+ (add-hook 'window-configuration-change-hook
+ 'slime-fuzzy-window-configuration-change))
+ (add-local-hook 'kill-buffer-hook 'slime-fuzzy-abort)
+ (setq buffer-quit-function 'slime-fuzzy-abort)) ; M-Esc Esc
+ (when slime-fuzzy-completion-in-place
+ ;; switch back to the original buffer
+ (switch-to-buffer-other-window slime-fuzzy-target-buffer))))
+
+(defun slime-fuzzy-fill-completions-buffer (completions interrupted-p)
+ "Erases and fills the completion buffer with the given completions."
+ (with-current-buffer (slime-get-fuzzy-buffer)
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (slime-fuzzy-completions-mode)
+ (insert slime-fuzzy-explanation)
+ (let ((max-length 12))
+ (dolist (completion completions)
+ (setf max-length (max max-length (length (first completion)))))
+
+ (insert "Completion:")
+ (dotimes (i (- max-length 10)) (insert " "))
+ ;; Flags: Score:
+ ;; ... ------- --------
+ ;; bfgcmsp
+ (insert "Flags: Score:\n")
+ (dotimes (i max-length) (insert "-"))
+ (insert " ------- --------\n")
+ (setq slime-fuzzy-first (point))
+
+ (dolist (completion completions)
+ (setq slime-fuzzy-last (point)) ; will eventually become the last entry
+ (slime-fuzzy-insert-completion-choice completion max-length))
+
+ (when interrupted-p
+ (insert "...\n")
+ (insert "[Interrupted: time limit exhausted]"))
+
+ (setq buffer-read-only t))
+ (setq slime-fuzzy-current-completion
+ (caar completions))
+ (goto-char 0)
+ (slime-fuzzy-next)))
+
+(defun slime-fuzzy-enable-target-buffer-completions-mode ()
+ "Store the target buffer's local map, so that we can restore it."
+ (unless slime-fuzzy-target-buffer-completions-mode
+; (slime-log-event "Enabling target buffer completions mode")
+ (slime-fuzzy-target-buffer-completions-mode 1)))
+
+(defun slime-fuzzy-disable-target-buffer-completions-mode ()
+ "Restores the target buffer's local map when completion is finished."
+ (when slime-fuzzy-target-buffer-completions-mode
+; (slime-log-event "Disabling target buffer completions mode")
+ (slime-fuzzy-target-buffer-completions-mode 0)))
+
+(defun slime-fuzzy-insert-from-point ()
+ "Inserts the completion that is under point in the completions
+buffer into the target buffer. If the completion in question had
+already been inserted, it does nothing."
+ (with-current-buffer (slime-get-fuzzy-buffer)
+ (let ((current-completion (get-text-property (point) 'completion)))
+ (when (and current-completion
+ (not (eq slime-fuzzy-current-completion
+ current-completion)))
+ (slime-fuzzy-insert
+ (first (get-text-property (point) 'completion)))
+ (setq slime-fuzzy-current-completion
+ current-completion)))))
+
+(defun slime-fuzzy-post-command-hook ()
+ "The post-command-hook for the *Fuzzy Completions* buffer.
+This makes sure the completion slot in the target buffer matches
+the completion that point is on in the completions buffer."
+ (condition-case err
+ (when slime-fuzzy-target-buffer
+ (slime-fuzzy-insert-from-point))
+ (error
+ ;; Because this is called on the post-command-hook, we mustn't let
+ ;; errors propagate.
+ (message "Error in slime-fuzzy-post-command-hook: %S" err))))
+
+(defun slime-fuzzy-next ()
+ "Moves point directly to the next completion in the completions
+buffer."
+ (interactive)
+ (with-current-buffer (slime-get-fuzzy-buffer)
+ (slime-fuzzy-dehighlight-current-completion)
+ (let ((point (next-single-char-property-change (point) 'completion nil slime-fuzzy-last)))
+ (set-window-point (get-buffer-window (current-buffer)) point)
+ (goto-char point))
+ (slime-fuzzy-highlight-current-completion)))
+
+(defun slime-fuzzy-prev ()
+ "Moves point directly to the previous completion in the
+completions buffer."
+ (interactive)
+ (with-current-buffer (slime-get-fuzzy-buffer)
+ (slime-fuzzy-dehighlight-current-completion)
+ (let ((point (previous-single-char-property-change (point) 'completion nil slime-fuzzy-first)))
+ (set-window-point (get-buffer-window (current-buffer)) point)
+ (goto-char point))
+ (slime-fuzzy-highlight-current-completion)))
+
+(defun slime-fuzzy-dehighlight-current-completion ()
+ "Restores the original face for the current completion."
+ (when slime-fuzzy-current-completion-overlay
+ (overlay-put slime-fuzzy-current-completion-overlay 'face 'nil)))
+
+(defun slime-fuzzy-highlight-current-completion ()
+ "Highlights the current completion, so that the user can see it on the screen."
+ (let ((pos (point)))
+ (setq slime-fuzzy-current-completion-overlay
+ (make-overlay (point) (1- (search-forward " "))
+ (current-buffer) t nil))
+ (overlay-put slime-fuzzy-current-completion-overlay 'face 'secondary-selection)
+ (goto-char pos)))
+
+(defun slime-fuzzy-abort ()
+ "Aborts the completion process, setting the completions slot in
+the target buffer back to its original contents."
+ (interactive)
+ (when slime-fuzzy-target-buffer
+ (slime-fuzzy-done)))
+
+(defun slime-fuzzy-select ()
+ "Selects the current completion, making sure that it is inserted
+into the target buffer. This tells the connected Lisp what completion
+was selected."
+ (interactive)
+ (when slime-fuzzy-target-buffer
+ (with-current-buffer (slime-get-fuzzy-buffer)
+ (let ((completion (get-text-property (point) 'completion)))
+ (when completion
+ (slime-fuzzy-insert (first completion))
+ (slime-fuzzy-selected slime-fuzzy-original-text
+ completion)
+ (slime-fuzzy-done))))))
+
+(defun slime-fuzzy-select-or-update-completions ()
+ "If there were no changes since the last time fuzzy completion was started
+this function will select the current completion. Otherwise refreshes the completion
+list based on the changes made."
+ (interactive)
+; (slime-log-event "Selecting or updating completions")
+ (if (string-equal slime-fuzzy-original-text
+ (buffer-substring slime-fuzzy-start
+ slime-fuzzy-end))
+ (slime-fuzzy-select)
+ (slime-fuzzy-complete-symbol)))
+
+(defun slime-fuzzy-process-event-in-completions-buffer ()
+ "Simply processes the event in the target buffer"
+ (interactive)
+ (with-current-buffer (slime-get-fuzzy-buffer)
+ (push last-input-event unread-command-events)))
+
+(defun slime-fuzzy-select-and-process-event-in-target-buffer ()
+ "Selects the current completion, making sure that it is inserted
+into the target buffer and processes the event in the target buffer."
+ (interactive)
+; (slime-log-event "Selecting and processing event in target buffer")
+ (when slime-fuzzy-target-buffer
+ (let ((buff slime-fuzzy-target-buffer))
+ (slime-fuzzy-select)
+ (with-current-buffer buff
+ (slime-fuzzy-disable-target-buffer-completions-mode)
+ (push last-input-event unread-command-events)))))
+
+(defun slime-fuzzy-select/mouse (event)
+ "Handle a mouse-2 click on a completion choice as if point were
+on the completion choice and the slime-fuzzy-select command was
+run."
+ (interactive "e")
+ (with-current-buffer (window-buffer (posn-window (event-end event)))
+ (save-excursion
+ (goto-char (posn-point (event-end event)))
+ (when (get-text-property (point) 'mouse-face)
+ (slime-fuzzy-insert-from-point)
+ (slime-fuzzy-select)))))
+
+(defun slime-fuzzy-done ()
+ "Cleans up after the completion process. This removes all hooks,
+and attempts to restore the window configuration. If this fails,
+it just burys the completions buffer and leaves the window
+configuration alone."
+ (when slime-fuzzy-target-buffer
+ (set-buffer slime-fuzzy-target-buffer)
+ (slime-fuzzy-disable-target-buffer-completions-mode)
+ (if (slime-fuzzy-maybe-restore-window-configuration)
+ (bury-buffer (slime-get-fuzzy-buffer))
+ ;; We couldn't restore the windows, so just bury the fuzzy
+ ;; completions buffer and let something else fill it in.
+ (pop-to-buffer (slime-get-fuzzy-buffer))
+ (bury-buffer))
+ (pop-to-buffer slime-fuzzy-target-buffer)
+ (goto-char slime-fuzzy-end)
+ (setq slime-fuzzy-target-buffer nil)
+ (remove-hook 'window-configuration-change-hook
+ 'slime-fuzzy-window-configuration-change)))
+
+(defun slime-fuzzy-maybe-restore-window-configuration ()
+ "Restores the saved window configuration if it has not been
+nullified."
+ (when (boundp 'window-configuration-change-hook)
+ (remove-hook 'window-configuration-change-hook
+ 'slime-fuzzy-window-configuration-change))
+ (if (not slime-fuzzy-saved-window-configuration)
+ nil
+ (set-window-configuration slime-fuzzy-saved-window-configuration)
+ (setq slime-fuzzy-saved-window-configuration nil)
+ t))
+
+(defun slime-fuzzy-window-configuration-change ()
+ "Called on window-configuration-change-hook. Since the window
+configuration was changed, we nullify our saved configuration."
+ (setq slime-fuzzy-saved-window-configuration nil))
+
+;;; Initialization
+
+(defun slime-fuzzy-init ()
+ (slime-fuzzy-bind-keys))
+
+(defun slime-fuzzy-bind-keys ()
+ (define-key slime-mode-map "\C-c\M-i" 'slime-fuzzy-complete-symbol)
+ (define-key slime-repl-mode-map "\C-c\M-i" 'slime-fuzzy-complete-symbol))
+
+(slime-require :swank-fuzzy)
+
+(provide 'slime-fuzzy)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-highlight-edits.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-highlight-edits.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,99 @@
+;;; slime-higlight-edits --- highlight edited, i.e. not yet compiled, code
+;;
+;; Author: William Bland <doctorbill.news at gmail.com> and others
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this your .emacs:
+;;
+;; (add-to-list 'load-path "<contrib-dir>")
+;; (autoload 'slime-highlight-edits-mode "slime-highlight-edits")
+;; (add-hook 'slime-mode-hook (lambda () (slime-highlight-edits-mode 1)))
+
+(defface slime-highlight-edits-face
+ `((((class color) (background light))
+ (:background "lightgray"))
+ (((class color) (background dark))
+ (:background "dimgray"))
+ (t (:background "yellow")))
+ "Face for displaying edit but not compiled code."
+ :group 'slime-mode-faces)
+
+(define-minor-mode slime-highlight-edits-mode
+ "Minor mode to highlight not-yet-compiled code." nil)
+
+(add-hook 'slime-highlight-edits-mode-on-hook
+ 'slime-highlight-edits-init-buffer)
+
+(add-hook 'slime-highlight-edits-mode-off-hook
+ 'slime-highlight-edits-reset-buffer)
+
+(defun slime-highlight-edits-init-buffer ()
+ (make-local-variable 'after-change-functions)
+ (add-to-list 'after-change-functions
+ 'slime-highlight-edits)
+ (add-to-list 'slime-before-compile-functions
+ 'slime-highlight-edits-compile-hook))
+
+(defun slime-highlight-edits-reset-buffer ()
+ (setq after-change-functions
+ (remove 'slime-highlight-edits after-change-functions))
+ (slime-remove-edits (point-min) (point-max)))
+
+;; FIXME: what's the LEN arg for?
+(defun slime-highlight-edits (beg end &optional len)
+ (save-match-data
+ (when (and (slime-connected-p)
+ (not (slime-inside-comment-p beg end))
+ (not (slime-only-whitespace-p beg end)))
+ (let ((overlay (make-overlay beg end)))
+ (overlay-put overlay 'face 'slime-highlight-edits-face)
+ (overlay-put overlay 'slime-edit t)))))
+
+(defun slime-remove-edits (start end)
+ "Delete the existing Slime edit hilights in the current buffer."
+ (save-excursion
+ (goto-char start)
+ (while (< (point) end)
+ (dolist (o (overlays-at (point)))
+ (when (overlay-get o 'slime-edit)
+ (delete-overlay o)))
+ (goto-char (next-overlay-change (point))))))
+
+(defun slime-highlight-edits-compile-hook (start end)
+ (when slime-highlight-edits-mode
+ (let ((start (save-excursion (goto-char start)
+ (skip-chars-backward " \t\n\r")
+ (point)))
+ (end (save-excursion (goto-char end)
+ (skip-chars-forward " \t\n\r")
+ (point))))
+ (slime-remove-edits start end))))
+
+(defun slime-inside-comment-p (beg end)
+ "Is the region from BEG to END in a comment?"
+ (save-excursion
+ (goto-char beg)
+ (let* ((hs-c-start-regexp ";\\|#|")
+ (comment (hs-inside-comment-p)))
+ (and comment
+ (destructuring-bind (cbeg cend) comment
+ (<= end cend))))))
+
+(defun slime-only-whitespace-p (beg end)
+ "Contains the region from BEG to END only whitespace?"
+ (save-excursion
+ (goto-char beg)
+ (skip-chars-forward " \n\t\r" end)
+ (<= end (point))))
+
+(defun slime-highlight-edits-mode-on () (slime-highlight-edits-mode 1))
+
+(defun slime-highlight-edits-init ()
+ (add-hook 'slime-mode-hook 'slime-highlight-edits-mode-on))
+
+(defun slime-highlight-edits-unload ()
+ (remove-hook 'slime-mode-hook 'slime-highlight-edits-mode-on))
+
+(provide 'slime-highlight-edits)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-parse.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-parse.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,382 @@
+;;; slime-parse.el --- parsing of Common Lisp source code
+;;
+;; Authors: Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+
+(defun slime-incomplete-form-at-point ()
+ "Looks for a ``raw form spec'' around point to be processed by
+SWANK::PARSE-FORM-SPEC. It is similiar to
+SLIME-INCOMPLETE-SEXP-AT-POINT but looks further back than just
+one sexp to find out the context."
+ (multiple-value-bind (operators arg-indices points)
+ (slime-enclosing-form-specs)
+ (if (null operators)
+ ""
+ (let ((op (first operators))
+ (op-start (first points))
+ (arg-index (first arg-indices)))
+ (destructure-case (slime-ensure-list op)
+ ((:declaration declspec) op)
+ ((:type-specifier typespec) op)
+ (t
+ (slime-make-form-spec-from-string
+ (concat (slime-incomplete-sexp-at-point) ")"))))))))
+
+;; XXX: unused function
+(defun slime-cl-symbol-external-ref-p (symbol)
+ "Does SYMBOL refer to an external symbol?
+FOO:BAR is an external reference.
+FOO::BAR is not, and nor is BAR."
+ (let ((name (if (stringp symbol) symbol (symbol-name symbol))))
+ (and (string-match ":" name)
+ (not (string-match "::" name)))))
+
+(defun slime-cl-symbol-name (symbol)
+ (let ((n (if (stringp symbol) symbol (symbol-name symbol))))
+ (if (string-match ":\\([^:]*\\)$" n)
+ (let ((symbol-part (match-string 1 n)))
+ (if (string-match "^|\\(.*\\)|$" symbol-part)
+ (match-string 1 symbol-part)
+ symbol-part))
+ n)))
+
+(defun slime-cl-symbol-package (symbol &optional default)
+ (let ((n (if (stringp symbol) symbol (symbol-name symbol))))
+ (if (string-match "^\\([^:]*\\):" n)
+ (match-string 1 n)
+ default)))
+
+;; XXX: unused function
+(defun slime-qualify-cl-symbol (symbol-or-name)
+ "Like `slime-qualify-cl-symbol-name', but interns the result."
+ (intern (slime-qualify-cl-symbol-name symbol-or-name)))
+
+(defun slime-qualify-cl-symbol-name (symbol-or-name)
+ "Return a package-qualified symbol-name that indicates the CL symbol
+SYMBOL. If SYMBOL doesn't already have a package prefix the current
+package is used."
+ (let ((s (if (stringp symbol-or-name)
+ symbol-or-name
+ (symbol-name symbol-or-name))))
+ (if (slime-cl-symbol-package s)
+ s
+ (format "%s::%s"
+ (let* ((package (slime-current-package)))
+ ;; package is a string like ":cl-user" or "CL-USER".
+ (if (and package (string-match "^:" package))
+ (substring package 1)
+ package))
+ (slime-cl-symbol-name s)))))
+
+
+(defun slime-parse-sexp-at-point (&optional n skip-blanks-p)
+ "Return the sexp at point as a string, otherwise nil.
+If N is given and greater than 1, a list of all such sexps
+following the sexp at point is returned. (If there are not
+as many sexps as N, a list with < N sexps is returned.)
+
+If SKIP-BLANKS-P is true, leading whitespaces &c are skipped.
+"
+ (interactive "p") (or n (setq n 1))
+ (flet ((sexp-at-point (first-choice)
+ (let ((string (if (eq first-choice :symbol-first)
+ (or (slime-symbol-name-at-point)
+ (thing-at-point 'sexp))
+ (or (thing-at-point 'sexp)
+ (slime-symbol-name-at-point)))))
+ (if string (substring-no-properties string) nil))))
+ ;; `thing-at-point' depends upon the current syntax table; otherwise
+ ;; keywords like `:foo' are not recognized as sexps. (This function
+ ;; may be called from temporary buffers etc.)
+ (with-syntax-table lisp-mode-syntax-table
+ (save-excursion
+ (when skip-blanks-p ; e.g. `( foo bat)' where point is after ?\(.
+ (slime-forward-blanks))
+ (let ((result nil))
+ (dotimes (i n)
+ ;; `foo(bar baz)' where point is at ?\( or ?\).
+ (if (and (char-after) (member (char-syntax (char-after)) '(?\( ?\) ?\')))
+ (push (sexp-at-point :sexp-first) result)
+ (push (sexp-at-point :symbol-first) result))
+ (ignore-errors (forward-sexp) (slime-forward-blanks))
+ (save-excursion
+ (unless (slime-point-moves-p (ignore-errors (forward-sexp)))
+ (return))))
+ (if (slime-length= result 1)
+ (first result)
+ (nreverse result)))))))
+
+(defun slime-incomplete-sexp-at-point (&optional n)
+ (interactive "p") (or n (setq n 1))
+ (buffer-substring-no-properties (save-excursion (backward-up-list n) (point))
+ (point)))
+
+
+(defun slime-parse-extended-operator-name (user-point forms indices points)
+ "Assume that point is directly at the operator that should be parsed.
+USER-POINT is the value of `point' where the user was looking at.
+OPS, INDICES and POINTS are updated to reflect the new values after
+parsing, and are then returned back as multiple values."
+ ;; OPS, INDICES and POINTS are like the finally returned values of
+ ;; SLIME-ENCLOSING-FORM-SPECS except that they're in reversed order,
+ ;; i.e. the leftmost (that is the latest) operator comes
+ ;; first.
+ (save-excursion
+ (ignore-errors
+ (let* ((current-op (first (first forms)))
+ (op-name (upcase (slime-cl-symbol-name current-op)))
+ (assoc (assoc op-name slime-extended-operator-name-parser-alist))
+ (entry (cdr assoc))
+ (parser (if (and entry (listp entry))
+ (apply (first entry) (rest entry))
+ entry)))
+ (ignore-errors
+ (forward-char (1+ (length current-op)))
+ (slime-forward-blanks))
+ (when parser
+ (multiple-value-setq (forms indices points)
+ (funcall parser op-name user-point forms indices points))))))
+ (values forms indices points))
+
+
+(defvar slime-extended-operator-name-parser-alist
+ '(("MAKE-INSTANCE" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("MAKE-CONDITION" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("ERROR" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("SIGNAL" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("WARN" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("CERROR" . (slime-make-extended-operator-parser/look-ahead 2))
+ ("CHANGE-CLASS" . (slime-make-extended-operator-parser/look-ahead 2))
+ ("DEFMETHOD" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("APPLY" . (slime-make-extended-operator-parser/look-ahead 1))
+ ("DECLARE" . slime-parse-extended-operator/declare)
+ ("DECLAIM" . slime-parse-extended-operator/declare)
+ ("PROCLAIM" . slime-parse-extended-operator/declare)))
+
+(defun slime-make-extended-operator-parser/look-ahead (steps)
+ "Returns a parser that parses the current operator at point
+plus STEPS-many additional sexps on the right side of the
+operator."
+ (lexical-let ((n steps))
+ #'(lambda (name user-point current-forms current-indices current-points)
+ (let ((old-forms (rest current-forms)))
+ (let* ((args (slime-ensure-list (slime-parse-sexp-at-point n)))
+ (arg-specs (mapcar #'slime-make-form-spec-from-string args)))
+ (setq current-forms (cons `(,name , at arg-specs) old-forms))))
+ (values current-forms current-indices current-points)
+ )))
+
+(defun slime-parse-extended-operator/declare
+ (name user-point current-forms current-indices current-points)
+ (when (string= (thing-at-point 'char) "(")
+ (let ((orig-point (point)))
+ (goto-char user-point)
+ (slime-end-of-symbol)
+ ;; Head of CURRENT-FORMS is "declare" at this point, but we're
+ ;; interested in what comes next.
+ (let* ((decl-ops (rest current-forms))
+ (decl-indices (rest current-indices))
+ (decl-points (rest current-points))
+ (decl-pos (1- (first decl-points)))
+ (nesting (slime-nesting-until-point decl-pos))
+ (declspec-str (concat (slime-incomplete-sexp-at-point nesting)
+ (make-string nesting ?\)))))
+ (save-match-data ; `(declare ((foo ...))' or `(declare (type (foo ...)))' ?
+ (if (or (eql 0 (string-match "\\s-*(\\((\\(\\sw\\|\\s_\\|\\s-\\)*)\\))$"
+ declspec-str))
+ (eql 0 (string-match "\\s-*(type\\s-*\\((\\(\\sw\\|\\s_\\|\\s-\\)*)\\))$"
+ declspec-str)))
+ (let* ((typespec-str (match-string 1 declspec-str))
+ (typespec (slime-make-form-spec-from-string typespec-str)))
+ (setq current-forms (list `(:type-specifier ,typespec)))
+ (setq current-indices (list (second decl-indices)))
+ (setq current-points (list (second decl-points))))
+ (let ((declspec (slime-make-form-spec-from-string declspec-str)))
+ (setq current-forms (list `(,name) `(:declaration ,declspec)))
+ (setq current-indices (list (first current-indices)
+ (first decl-indices)))
+ (setq current-points (list (first current-points)
+ (first decl-points)))))))))
+ (values current-forms current-indices current-points))
+
+(defun slime-nesting-until-point (target-point)
+ "Returns the nesting level between current point and TARGET-POINT.
+If TARGET-POINT could not be reached, 0 is returned. (As a result
+TARGET-POINT should always be placed just before a `?\('.)"
+ (save-excursion
+ (let ((nesting 0))
+ (while (> (point) target-point)
+ (backward-up-list)
+ (incf nesting))
+ (if (= (point) target-point)
+ nesting
+ 0))))
+
+(defun slime-make-form-spec-from-string (string &optional strip-operator-p)
+ "If STRIP-OPERATOR-P is T and STRING is the string
+representation of a form, the string representation of this form
+is stripped from the form. This can be important to avoid mutual
+recursion between this function, `slime-enclosing-form-specs' and
+`slime-parse-extended-operator-name'.
+
+Examples:
+
+ \"(foo (bar 1 (baz :quux)) 'toto)\"
+
+ => (\"foo\" (\"bar\" \"1\" (\"baz\" \":quux\")) \"'toto\")
+"
+ (cond ((slime-length= string 0) "") ; ""
+ ((equal string "()") '()) ; "()"
+ ((eql (char-syntax (aref string 0)) ?\') string) ; "'(foo)", "#(foo)" &c
+ ((not (eql (aref string 0) ?\()) string) ; "foo"
+ (t ; "(op arg1 arg2 ...)"
+ (with-temp-buffer
+ ;; Do NEVER ever try to activate `lisp-mode' here with
+ ;; `slime-use-autodoc-mode' enabled, as this function is used
+ ;; to compute the current autodoc itself.
+ (erase-buffer)
+ (insert string)
+ (when strip-operator-p ; `(OP arg1 arg2 ...)' ==> `(arg1 arg2 ...)'
+ (goto-char (point-min))
+ (when (string= (thing-at-point 'char) "(")
+ (ignore-errors (forward-char 1)
+ (forward-sexp)
+ (slime-forward-blanks))
+ (delete-region (point-min) (point))
+ (insert "(")))
+ (goto-char (1- (point-max))) ; `(OP arg1 ... argN|)'
+ (assert (eql (char-after) ?\)))
+ (multiple-value-bind (forms indices points)
+ (slime-enclosing-form-specs 1)
+ (if (null forms)
+ string
+ (let ((n (first (last indices))))
+ (goto-char (1+ (point-min))) ; `(|OP arg1 ... argN)'
+ (mapcar #'(lambda (s)
+ (assert (not (equal s string))) ; trap against
+ (slime-make-form-spec-from-string s)) ; endless recursion.
+ (slime-ensure-list
+ (slime-parse-sexp-at-point (1+ n) t))))))))))
+
+
+(defun slime-enclosing-form-specs (&optional max-levels)
+ "Return the list of ``raw form specs'' of all the forms
+containing point from right to left.
+
+As a secondary value, return a list of indices: Each index tells
+for each corresponding form spec in what argument position the
+user's point is.
+
+As tertiary value, return the positions of the operators that are
+contained in the returned form specs.
+
+When MAX-LEVELS is non-nil, go up at most this many levels of
+parens.
+
+\(See SWANK::PARSE-FORM-SPEC for more information about what
+exactly constitutes a ``raw form specs'')
+
+Examples:
+
+ A return value like the following
+
+ (values ((\"quux\") (\"bar\") (\"foo\")) (3 2 1) (p1 p2 p3))
+
+ can be interpreted as follows:
+
+ The user point is located in the 3rd argument position of a
+ form with the operator name \"quux\" (which starts at P1.)
+
+ This form is located in the 2nd argument position of a form
+ with the operator name \"bar\" (which starts at P2.)
+
+ This form again is in the 1st argument position of a form
+ with the operator name \"foo\" (which itself begins at P3.)
+
+ For instance, the corresponding buffer content could have looked
+ like `(foo (bar arg1 (quux 1 2 |' where `|' denotes point.
+"
+ (let ((level 1)
+ (parse-sexp-lookup-properties nil)
+ (initial-point (point))
+ (result '()) (arg-indices '()) (points '()))
+ ;; The expensive lookup of syntax-class text properties is only
+ ;; used for interactive balancing of #<...> in presentations; we
+ ;; do not need them in navigating through the nested lists.
+ ;; This speeds up this function significantly.
+ (ignore-errors
+ (save-excursion
+ ;; Make sure we get the whole thing at point.
+ (if (not (slime-inside-string-p))
+ (slime-end-of-symbol)
+ (slime-beginning-of-string)
+ (forward-sexp))
+ (save-restriction
+ ;; Don't parse more than 20000 characters before point, so we don't spend
+ ;; too much time.
+ (narrow-to-region (max (point-min) (- (point) 20000)) (point-max))
+ (narrow-to-region (save-excursion (beginning-of-defun) (point))
+ (min (1+ (point)) (point-max)))
+ (while (or (not max-levels)
+ (<= level max-levels))
+ (let ((arg-index 0))
+ ;; Move to the beginning of the current sexp if not already there.
+ (if (or (and (char-after)
+ (member (char-syntax (char-after)) '(?\( ?')))
+ (member (char-syntax (char-before)) '(?\ ?>)))
+ (incf arg-index))
+ (ignore-errors (backward-sexp 1))
+ (while (and (< arg-index 64)
+ (ignore-errors (backward-sexp 1)
+ (> (point) (point-min))))
+ (incf arg-index))
+ (backward-up-list 1)
+ (when (member (char-syntax (char-after)) '(?\( ?'))
+ (incf level)
+ (forward-char 1)
+ (let ((name (slime-symbol-name-at-point)))
+ (cond
+ (name
+ (save-restriction
+ (widen) ; to allow looking-ahead/back in extended parsing.
+ (multiple-value-bind (new-result new-indices new-points)
+ (slime-parse-extended-operator-name initial-point
+ (cons `(,name) result) ; minimal form spec
+ (cons arg-index arg-indices)
+ (cons (point) points))
+ (setq result new-result)
+ (setq arg-indices new-indices)
+ (setq points new-points))))
+ (t
+ (push nil result)
+ (push arg-index arg-indices)
+ (push (point) points))))
+ (backward-up-list 1)))))))
+ (values
+ (nreverse result)
+ (nreverse arg-indices)
+ (nreverse points))))
+
+
+(defun slime-ensure-list (thing)
+ (if (listp thing) thing (list thing)))
+
+(defun slime-inside-string-p ()
+ (let* ((toplevel-begin (save-excursion (beginning-of-defun) (point)))
+ (parse-result (parse-partial-sexp toplevel-begin (point)))
+ (inside-string-p (nth 3 parse-result))
+ (string-start-pos (nth 8 parse-result)))
+ (and inside-string-p string-start-pos)))
+
+(defun slime-beginning-of-string ()
+ (let ((string-start-pos (slime-inside-string-p)))
+ (if string-start-pos
+ (goto-char string-start-pos)
+ (error "We're not within a string"))))
+
+(provide 'slime-parse)
+
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-presentation-streams.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-presentation-streams.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,29 @@
+;;; swank-presentation-streams.el --- Streams that allow attaching object identities
+;;; to portions of output
+;;;
+;;; Authors: Alan Ruttenberg <alanr-l at mumble.net>
+;;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;;; Helmut Eller <heller at common-lisp.net>
+;;;
+;;; License: GNU GPL (same license as Emacs)
+;;;
+;;; Installation
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-presentation-streams)))
+;;
+
+
+;;; Initialization
+
+(require 'slime-presentations)
+
+(add-hook 'slime-connected-hook 'slime-install-presentation-streams)
+
+(defun slime-install-presentation-streams ()
+ (slime-eval-async '(swank:swank-require :swank-presentation-streams)))
+
+(provide 'slime-presentation-streams)
+
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-presentations.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-presentations.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,807 @@
+;;; swank-presentations.el --- imitat LispM' presentations
+;;;
+;;; Authors: Alan Ruttenberg <alanr-l at mumble.net>
+;;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;;;
+;;; License: GNU GPL (same license as Emacs)
+;;;
+;;; Installation
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-presentations)))
+;;
+
+(defface slime-repl-output-mouseover-face
+ (if (featurep 'xemacs)
+ '((t (:bold t)))
+ (if (slime-face-inheritance-possible-p)
+ '((t
+ (:box
+ (:line-width 1 :color "black" :style released-button)
+ :inherit
+ slime-repl-inputed-output-face)))
+ '((t (:box (:line-width 1 :color "black"))))))
+ "Face for Lisp output in the SLIME REPL, when the mouse hovers over it"
+ :group 'slime-repl)
+
+(defface slime-repl-inputed-output-face
+ '((((class color) (background light)) (:foreground "Red"))
+ (((class color) (background dark)) (:foreground "Red"))
+ (t (:slant italic)))
+ "Face for the result of an evaluation in the SLIME REPL."
+ :group 'slime-repl)
+
+;; FIXME: This conditional is not right - just used because the code
+;; here does not work in XEmacs.
+(when (boundp 'text-property-default-nonsticky)
+ (pushnew '(slime-repl-presentation . t) text-property-default-nonsticky
+ :test 'equal)
+ (pushnew '(slime-repl-result-face . t) text-property-default-nonsticky
+ :test 'equal))
+
+(make-variable-buffer-local
+ (defvar slime-presentation-start-to-point (make-hash-table)))
+
+(defun slime-mark-presentation-start (id &optional target)
+ "Mark the beginning of a presentation with the given ID.
+TARGET can be nil (regular process output) or :repl-result."
+ (setf (gethash id slime-presentation-start-to-point)
+ ;; We use markers because text can also be inserted before this presentation.
+ ;; (Output arrives while we are writing presentations within REPL results.)
+ (copy-marker (slime-output-target-marker target) nil)))
+
+(defun slime-mark-presentation-start-handler (process string)
+ (if (and string (string-match "<\\([-0-9]+\\)" string))
+ (let* ((match (substring string (match-beginning 1) (match-end 1)))
+ (id (car (read-from-string match))))
+ (slime-mark-presentation-start id))))
+
+(defun slime-mark-presentation-end (id &optional target)
+ "Mark the end of a presentation with the given ID.
+TARGET can be nil (regular process output) or :repl-result."
+ (let ((start (gethash id slime-presentation-start-to-point)))
+ (remhash id slime-presentation-start-to-point)
+ (when start
+ (let* ((marker (slime-output-target-marker target))
+ (buffer (and marker (marker-buffer marker))))
+ (with-current-buffer buffer
+ (let ((end (marker-position marker)))
+ (slime-add-presentation-properties start end
+ id nil)))))))
+
+(defun slime-mark-presentation-end-handler (process string)
+ (if (and string (string-match ">\\([-0-9]+\\)" string))
+ (let* ((match (substring string (match-beginning 1) (match-end 1)))
+ (id (car (read-from-string match))))
+ (slime-mark-presentation-end id))))
+
+(defstruct slime-presentation text id)
+
+(defvar slime-presentation-syntax-table
+ (let ((table (copy-syntax-table lisp-mode-syntax-table)))
+ ;; We give < and > parenthesis syntax, so that #< ... > is treated
+ ;; as a balanced expression. This allows to use C-M-k, C-M-SPC,
+ ;; etc. to deal with a whole presentation. (For Lisp mode, this
+ ;; is not desirable, since we do not wish to get a mismatched
+ ;; paren highlighted everytime we type < or >.)
+ (modify-syntax-entry ?< "(>" table)
+ (modify-syntax-entry ?> ")<" table)
+ table)
+ "Syntax table for presentations.")
+
+(defun slime-add-presentation-properties (start end id result-p)
+ "Make the text between START and END a presentation with ID.
+RESULT-P decides whether a face for a return value or output text is used."
+ (let* ((text (buffer-substring-no-properties start end))
+ (presentation (make-slime-presentation :text text :id id)))
+ (let ((inhibit-modification-hooks t))
+ (add-text-properties start end
+ `(modification-hooks (slime-after-change-function)
+ insert-in-front-hooks (slime-after-change-function)
+ insert-behind-hooks (slime-after-change-function)
+ syntax-table ,slime-presentation-syntax-table
+ rear-nonsticky t))
+ ;; Use the presentation as the key of a text property
+ (case (- end start)
+ (0)
+ (1
+ (add-text-properties start end
+ `(slime-repl-presentation ,presentation
+ ,presentation :start-and-end)))
+ (t
+ (add-text-properties start (1+ start)
+ `(slime-repl-presentation ,presentation
+ ,presentation :start))
+ (when (> (- end start) 2)
+ (add-text-properties (1+ start) (1- end)
+ `(,presentation :interior)))
+ (add-text-properties (1- end) end
+ `(slime-repl-presentation ,presentation
+ ,presentation :end))))
+ ;; Also put an overlay for the face and the mouse-face. This enables
+ ;; highlighting of nested presentations. However, overlays get lost
+ ;; when we copy a presentation; their removal is also not undoable.
+ ;; In these cases the mouse-face text properties need to take over ---
+ ;; but they do not give nested highlighting.
+ (slime-ensure-presentation-overlay start end presentation))))
+
+(defun slime-ensure-presentation-overlay (start end presentation)
+ (unless (find presentation (overlays-at start)
+ :key (lambda (overlay)
+ (overlay-get overlay 'slime-repl-presentation)))
+ (let ((overlay (make-overlay start end (current-buffer) t nil)))
+ (overlay-put overlay 'slime-repl-presentation presentation)
+ (overlay-put overlay 'mouse-face 'slime-repl-output-mouseover-face)
+ (overlay-put overlay 'help-echo
+ (if (eq major-mode 'slime-repl-mode)
+ "mouse-2: copy to input; mouse-3: menu"
+ "mouse-2: inspect; mouse-3: menu"))
+ (overlay-put overlay 'face 'slime-repl-inputed-output-face)
+ (overlay-put overlay 'keymap slime-presentation-map))))
+
+(defun slime-remove-presentation-properties (from to presentation)
+ (let ((inhibit-read-only t))
+ (remove-text-properties from to
+ `(,presentation t syntax-table t rear-nonsticky t))
+ (when (eq (get-text-property from 'slime-repl-presentation) presentation)
+ (remove-text-properties from (1+ from) `(slime-repl-presentation t)))
+ (when (eq (get-text-property (1- to) 'slime-repl-presentation) presentation)
+ (remove-text-properties (1- to) to `(slime-repl-presentation t)))
+ (dolist (overlay (overlays-at from))
+ (when (eq (overlay-get overlay 'slime-repl-presentation) presentation)
+ (delete-overlay overlay)))))
+
+(defun slime-insert-presentation (string output-id &optional rectangle)
+ "Insert STRING in current buffer and mark it as a presentation
+corresponding to OUTPUT-ID. If RECTANGLE is true, indent multi-line
+strings to line up below the current point."
+ (flet ((insert-it ()
+ (if rectangle
+ (slime-insert-indented string)
+ (insert string))))
+ (let ((start (point)))
+ (insert-it)
+ (slime-add-presentation-properties start (point) output-id t))))
+
+(defun slime-presentation-whole-p (presentation start end &optional object)
+ (let ((object (or object (current-buffer))))
+ (string= (etypecase object
+ (buffer (with-current-buffer object
+ (buffer-substring-no-properties start end)))
+ (string (substring-no-properties object start end)))
+ (slime-presentation-text presentation))))
+
+(defun slime-presentations-around-point (point &optional object)
+ (let ((object (or object (current-buffer))))
+ (loop for (key value . rest) on (text-properties-at point object) by 'cddr
+ when (slime-presentation-p key)
+ collect key)))
+
+(defun slime-presentation-start-p (tag)
+ (memq tag '(:start :start-and-end)))
+
+(defun slime-presentation-stop-p (tag)
+ (memq tag '(:end :start-and-end)))
+
+(defun* slime-presentation-start (point presentation
+ &optional (object (current-buffer)))
+ "Find start of `presentation' at `point' in `object'.
+Return buffer index and whether a start-tag was found."
+ (let* ((this-presentation (get-text-property point presentation object)))
+ (while (not (slime-presentation-start-p this-presentation))
+ (let ((change-point (previous-single-property-change
+ point presentation object)))
+ (unless change-point
+ (return-from slime-presentation-start
+ (values (etypecase object
+ (buffer (with-current-buffer object 1))
+ (string 0))
+ nil)))
+ (setq this-presentation (get-text-property change-point
+ presentation object))
+ (unless this-presentation
+ (return-from slime-presentation-start
+ (values point nil)))
+ (setq point change-point)))
+ (values point t)))
+
+(defun* slime-presentation-end (point presentation
+ &optional (object (current-buffer)))
+ "Find end of presentation at `point' in `object'. Return buffer
+index (after last character of the presentation) and whether an
+end-tag was found."
+ (let* ((this-presentation (get-text-property point presentation object)))
+ (while (not (slime-presentation-stop-p this-presentation))
+ (let ((change-point (next-single-property-change
+ point presentation object)))
+ (unless change-point
+ (return-from slime-presentation-end
+ (values (etypecase object
+ (buffer (with-current-buffer object (point-max)))
+ (string (length object)))
+ nil)))
+ (setq point change-point)
+ (setq this-presentation (get-text-property point
+ presentation object))))
+ (if this-presentation
+ (let ((after-end (next-single-property-change point
+ presentation object)))
+ (if (not after-end)
+ (values (etypecase object
+ (buffer (with-current-buffer object (point-max)))
+ (string (length object)))
+ t)
+ (values after-end t)))
+ (values point nil))))
+
+(defun* slime-presentation-bounds (point presentation
+ &optional (object (current-buffer)))
+ "Return start index and end index of `presentation' around `point'
+in `object', and whether the presentation is complete."
+ (multiple-value-bind (start good-start)
+ (slime-presentation-start point presentation object)
+ (multiple-value-bind (end good-end)
+ (slime-presentation-end point presentation object)
+ (values start end
+ (and good-start good-end
+ (slime-presentation-whole-p presentation
+ start end object))))))
+
+(defun slime-presentation-around-point (point &optional object)
+ "Return presentation, start index, end index, and whether the
+presentation is complete."
+ (let ((object (or object (current-buffer)))
+ (innermost-presentation nil)
+ (innermost-start 0)
+ (innermost-end most-positive-fixnum))
+ (dolist (presentation (slime-presentations-around-point point object))
+ (multiple-value-bind (start end whole-p)
+ (slime-presentation-bounds point presentation object)
+ (when whole-p
+ (when (< (- end start) (- innermost-end innermost-start))
+ (setq innermost-start start
+ innermost-end end
+ innermost-presentation presentation)))))
+ (values innermost-presentation
+ innermost-start innermost-end)))
+
+(defun slime-presentation-around-or-before-point (point &optional object)
+ (let ((object (or object (current-buffer))))
+ (multiple-value-bind (presentation start end whole-p)
+ (slime-presentation-around-point point object)
+ (if presentation
+ (values presentation start end whole-p)
+ (slime-presentation-around-point (1- point) object)))))
+
+(defun slime-presentation-around-or-before-point-or-error (point)
+ (multiple-value-bind (presentation start end whole-p)
+ (slime-presentation-around-or-before-point point)
+ (unless presentation
+ (error "No presentation at point"))
+ (values presentation start end whole-p)))
+
+(defun* slime-for-each-presentation-in-region (from to function &optional (object (current-buffer)))
+ "Call `function' with arguments `presentation', `start', `end',
+`whole-p' for every presentation in the region `from'--`to' in the
+string or buffer `object'."
+ (flet ((handle-presentation (presentation point)
+ (multiple-value-bind (start end whole-p)
+ (slime-presentation-bounds point presentation object)
+ (funcall function presentation start end whole-p))))
+ ;; Handle presentations active at `from'.
+ (dolist (presentation (slime-presentations-around-point from object))
+ (handle-presentation presentation from))
+ ;; Use the `slime-repl-presentation' property to search for new presentations.
+ (let ((point from))
+ (while (< point to)
+ (setq point (next-single-property-change point 'slime-repl-presentation object to))
+ (let* ((presentation (get-text-property point 'slime-repl-presentation object))
+ (status (get-text-property point presentation object)))
+ (when (slime-presentation-start-p status)
+ (handle-presentation presentation point)))))))
+
+;; XEmacs compatibility hack, from message by Stephen J. Turnbull on
+;; xemacs-beta at xemacs.org of 18 Mar 2002
+(unless (boundp 'undo-in-progress)
+ (defvar undo-in-progress nil
+ "Placeholder defvar for XEmacs compatibility from SLIME.")
+ (defadvice undo-more (around slime activate)
+ (let ((undo-in-progress t)) ad-do-it)))
+
+(defun slime-after-change-function (start end &rest ignore)
+ "Check all presentations within and adjacent to the change.
+When a presentation has been altered, change it to plain text."
+ (let ((inhibit-modification-hooks t))
+ (let ((real-start (max 1 (1- start)))
+ (real-end (min (1+ (buffer-size)) (1+ end)))
+ (any-change nil))
+ ;; positions around the change
+ (slime-for-each-presentation-in-region
+ real-start real-end
+ (lambda (presentation from to whole-p)
+ (cond
+ (whole-p
+ (slime-ensure-presentation-overlay from to presentation))
+ ((not undo-in-progress)
+ (slime-remove-presentation-properties from to
+ presentation)
+ (setq any-change t)))))
+ (when any-change
+ (undo-boundary)))))
+
+(defun slime-presentation-around-click (event)
+ "Return the presentation around the position of the mouse-click EVENT.
+If there is no presentation, signal an error.
+Also return the start position, end position, and buffer of the presentation."
+ (when (and (featurep 'xemacs) (not (button-press-event-p event)))
+ (error "Command must be bound to a button-press-event"))
+ (let ((point (if (featurep 'xemacs) (event-point event) (posn-point (event-end event))))
+ (window (if (featurep 'xemacs) (event-window event) (caadr event))))
+ (with-current-buffer (window-buffer window)
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-point point)
+ (unless presentation
+ (error "No presentation at click"))
+ (values presentation start end (current-buffer))))))
+
+(defun slime-copy-or-inspect-presentation-at-mouse (event)
+ (interactive "e") ; no "@" -- we don't want to select the clicked-at window
+ (multiple-value-bind (presentation start end buffer)
+ (slime-presentation-around-click event)
+ (if (with-current-buffer buffer
+ (eq major-mode 'slime-repl-mode))
+ (slime-copy-presentation-at-mouse-to-repl event)
+ (slime-inspect-presentation-at-mouse event))))
+
+(defun slime-inspect-presentation (presentation start end buffer)
+ (let ((reset-p
+ (with-current-buffer buffer
+ (not (eq major-mode 'slime-inspector-mode)))))
+ (slime-eval-async `(swank:inspect-presentation ',(slime-presentation-id presentation) ,reset-p)
+ 'slime-open-inspector)))
+
+(defun slime-inspect-presentation-at-mouse (event)
+ (interactive "e")
+ (multiple-value-bind (presentation start end buffer)
+ (slime-presentation-around-click event)
+ (slime-inspect-presentation presentation start end buffer)))
+
+(defun slime-inspect-presentation-at-point (point)
+ (interactive "d")
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-or-before-point-or-error point)
+ (slime-inspect-presentation presentation start end (current-buffer))))
+
+(defun slime-copy-presentation-to-repl (presentation start end buffer)
+ (let ((presentation-text
+ (with-current-buffer buffer
+ (buffer-substring start end))))
+ (unless (eql major-mode 'slime-repl-mode)
+ (slime-switch-to-output-buffer))
+ (flet ((do-insertion ()
+ (when (not (string-match "\\s-"
+ (buffer-substring (1- (point)) (point))))
+ (insert " "))
+ (insert presentation-text)
+ (when (and (not (eolp)) (not (looking-at "\\s-")))
+ (insert " "))))
+ (if (>= (point) slime-repl-prompt-start-mark)
+ (do-insertion)
+ (save-excursion
+ (goto-char (point-max))
+ (do-insertion))))))
+
+(defun slime-copy-presentation-at-mouse-to-repl (event)
+ (interactive "e")
+ (multiple-value-bind (presentation start end buffer)
+ (slime-presentation-around-click event)
+ (slime-copy-presentation-to-repl presentation start end buffer)))
+
+(defun slime-copy-presentation-at-point-to-repl (point)
+ (interactive "d")
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-or-before-point-or-error point)
+ (slime-copy-presentation-to-repl presentation start end (current-buffer))))
+
+(defun slime-copy-presentation-at-mouse-to-point (event)
+ (interactive "e")
+ (multiple-value-bind (presentation start end buffer)
+ (slime-presentation-around-click event)
+ (let ((presentation-text
+ (with-current-buffer buffer
+ (buffer-substring start end))))
+ (when (not (string-match "\\s-"
+ (buffer-substring (1- (point)) (point))))
+ (insert " "))
+ (insert presentation-text)
+ (slime-after-change-function (point) (point))
+ (when (and (not (eolp)) (not (looking-at "\\s-")))
+ (insert " ")))))
+
+(defun slime-copy-presentation-to-kill-ring (presentation start end buffer)
+ (let ((presentation-text
+ (with-current-buffer buffer
+ (buffer-substring start end))))
+ (kill-new presentation-text)
+ (message "Saved presentation \"%s\" to kill ring" presentation-text)))
+
+(defun slime-copy-presentation-at-mouse-to-kill-ring (event)
+ (interactive "e")
+ (multiple-value-bind (presentation start end buffer)
+ (slime-presentation-around-click event)
+ (slime-copy-presentation-to-kill-ring presentation start end buffer)))
+
+(defun slime-copy-presentation-at-point-to-kill-ring (point)
+ (interactive "d")
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-or-before-point-or-error point)
+ (slime-copy-presentation-to-kill-ring presentation start end (current-buffer))))
+
+(defun slime-describe-presentation (presentation)
+ (slime-eval-describe
+ `(swank::describe-to-string
+ (swank::lookup-presented-object ',(slime-presentation-id presentation)))))
+
+(defun slime-describe-presentation-at-mouse (event)
+ (interactive "@e")
+ (multiple-value-bind (presentation) (slime-presentation-around-click event)
+ (slime-describe-presentation presentation)))
+
+(defun slime-describe-presentation-at-point (point)
+ (interactive "d")
+ (multiple-value-bind (presentation)
+ (slime-presentation-around-or-before-point-or-error point)
+ (slime-describe-presentation presentation)))
+
+(defun slime-pretty-print-presentation (presentation)
+ (slime-eval-describe
+ `(swank::swank-pprint
+ (cl:list
+ (swank::lookup-presented-object ',(slime-presentation-id presentation))))))
+
+(defun slime-pretty-print-presentation-at-mouse (event)
+ (interactive "@e")
+ (multiple-value-bind (presentation) (slime-presentation-around-click event)
+ (slime-pretty-print-presentation presentation)))
+
+(defun slime-pretty-print-presentation-at-point (point)
+ (interactive "d")
+ (multiple-value-bind (presentation)
+ (slime-presentation-around-or-before-point-or-error point)
+ (slime-pretty-print-presentation presentation)))
+
+(defun slime-mark-presentation (point)
+ (interactive "d")
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-or-before-point-or-error point)
+ (goto-char start)
+ (push-mark end nil t)))
+
+(defun slime-previous-presentation ()
+ "Move point to the beginning of the first presentation before point."
+ (interactive)
+ ;; First skip outside the current surrounding presentation (if any)
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-point (point))
+ (when presentation
+ (goto-char start)))
+ (let ((p (previous-single-property-change (point) 'slime-repl-presentation)))
+ (unless p
+ (error "No previous presentation"))
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-or-before-point-or-error p)
+ (goto-char start))))
+
+(defun slime-next-presentation ()
+ "Move point to the beginning of the next presentation after point."
+ (interactive)
+ ;; First skip outside the current surrounding presentation (if any)
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-point (point))
+ (when presentation
+ (goto-char end)))
+ (let ((p (next-single-property-change (point) 'slime-repl-presentation)))
+ (unless p
+ (error "No next presentation"))
+ (multiple-value-bind (presentation start end)
+ (slime-presentation-around-or-before-point-or-error p)
+ (goto-char start))))
+
+(defvar slime-presentation-map (make-sparse-keymap))
+
+(define-key slime-presentation-map [mouse-2] 'slime-copy-or-inspect-presentation-at-mouse)
+(define-key slime-presentation-map [mouse-3] 'slime-presentation-menu)
+
+(when (featurep 'xemacs)
+ (define-key slime-presentation-map [button2] 'slime-copy-or-inspect-presentation-at-mouse)
+ (define-key slime-presentation-map [button3] 'slime-presentation-menu))
+
+;; protocol for handling up a menu.
+;; 1. Send lisp message asking for menu choices for this object.
+;; Get back list of strings.
+;; 2. Let used choose
+;; 3. Call back to execute menu choice, passing nth and string of choice
+
+(defun slime-menu-choices-for-presentation (presentation buffer from to choice-to-lambda)
+ "Return a menu for `presentation' at `from'--`to' in `buffer', suitable for `x-popup-menu'."
+ (let* ((what (slime-presentation-id presentation))
+ (choices (with-current-buffer buffer
+ (slime-eval
+ `(swank::menu-choices-for-presentation-id ',what)))))
+ (flet ((savel (f) ;; IMPORTANT - xemacs can't handle lambdas in x-popup-menu. So give them a name
+ (let ((sym (gensym)))
+ (setf (gethash sym choice-to-lambda) f)
+ sym)))
+ (etypecase choices
+ (list
+ `(,(format "Presentation %s" what)
+ (""
+ ("Inspect" . ,(savel 'slime-inspect-presentation-at-mouse))
+ ("Describe" . ,(savel 'slime-describe-presentation-at-mouse))
+ ("Pretty-print" . ,(savel 'slime-pretty-print-presentation-at-mouse))
+ ("Copy to REPL" . ,(savel 'slime-copy-presentation-at-mouse-to-repl))
+ ("Copy to kill ring" . ,(savel 'slime-copy-presentation-at-mouse-to-kill-ring))
+ ,@(unless buffer-read-only
+ `(("Copy to point" . ,(savel 'slime-copy-presentation-at-mouse-to-point))))
+ ,@(let ((nchoice 0))
+ (mapcar
+ (lambda (choice)
+ (incf nchoice)
+ (cons choice
+ (savel `(lambda ()
+ (interactive)
+ (slime-eval
+ '(swank::execute-menu-choice-for-presentation-id
+ ',what ,nchoice ,(nth (1- nchoice) choices)))))))
+ choices)))))
+ (symbol ; not-present
+ (with-current-buffer buffer
+ (slime-remove-presentation-properties from to presentation))
+ (sit-for 0) ; allow redisplay
+ `("Object no longer recorded"
+ ("sorry" . ,(if (featurep 'xemacs) nil '(nil)))))))))
+
+(defun slime-presentation-menu (event)
+ (interactive "e")
+ (let* ((point (if (featurep 'xemacs) (event-point event)
+ (posn-point (event-end event))))
+ (window (if (featurep 'xemacs) (event-window event) (caadr event)))
+ (buffer (window-buffer window))
+ (choice-to-lambda (make-hash-table)))
+ (multiple-value-bind (presentation from to)
+ (with-current-buffer buffer
+ (slime-presentation-around-point point))
+ (unless presentation
+ (error "No presentation at event position"))
+ (let ((menu (slime-menu-choices-for-presentation
+ presentation buffer from to choice-to-lambda)))
+ (let ((choice (x-popup-menu event menu)))
+ (when choice
+ (call-interactively (gethash choice choice-to-lambda))))))))
+
+(defun slime-presentation-expression (presentation)
+ "Return a string that contains a CL s-expression accessing
+the presented object."
+ (let ((id (slime-presentation-id presentation)))
+ (etypecase id
+ (number
+ ;; Make sure it works even if *read-base* is not 10.
+ (format "(swank:get-repl-result #10r%d)" id))
+ (list
+ ;; for frame variables and inspector parts
+ (format "(swank:get-repl-result '%s)" id)))))
+
+(defun slime-buffer-substring-with-reified-output (start end)
+ (let ((str-props (buffer-substring start end))
+ (str-no-props (buffer-substring-no-properties start end)))
+ (slime-reify-old-output str-props str-no-props)))
+
+(defun slime-reify-old-output (str-props str-no-props)
+ (let ((pos (slime-property-position 'slime-repl-presentation str-props)))
+ (if (null pos)
+ str-no-props
+ (multiple-value-bind (presentation start-pos end-pos whole-p)
+ (slime-presentation-around-point pos str-props)
+ (if (not presentation)
+ str-no-props
+ (concat (substring str-no-props 0 pos)
+ ;; Eval in the reader so that we play nice with quote.
+ ;; -luke (19/May/2005)
+ "#." (slime-presentation-expression presentation)
+ (slime-reify-old-output (substring str-props end-pos)
+ (substring str-no-props end-pos))))))))
+
+
+
+(defun slime-repl-grab-old-output (replace)
+ "Resend the old REPL output at point.
+If replace it non-nil the current input is replaced with the old
+output; otherwise the new input is appended."
+ (multiple-value-bind (presentation beg end)
+ (slime-presentation-around-or-before-point (point))
+ (let ((old-output (buffer-substring beg end))) ;;keep properties
+ ;; Append the old input or replace the current input
+ (cond (replace (goto-char slime-repl-input-start-mark))
+ (t (goto-char slime-repl-input-end-mark)
+ (unless (eq (char-before) ?\ )
+ (insert " "))))
+ (delete-region (point) slime-repl-input-end-mark)
+ (let ((inhibit-read-only t))
+ (insert old-output)))))
+
+;;; Presentation-related key bindings, non-context menu
+
+(defvar slime-presentation-command-map (make-sparse-keymap)
+ "Keymap for presentation-related commands. Bound to a prefix key.")
+
+(defvar slime-presentation-bindings
+ '((?i slime-inspect-presentation-at-point)
+ (?d slime-describe-presentation-at-point)
+ (?w slime-copy-presentation-at-point-to-kill-ring)
+ (?r slime-copy-presentation-at-point-to-repl)
+ (?p slime-previous-presentation)
+ (?n slime-next-presentation)
+ (? slime-mark-presentation)))
+
+(defun slime-presentation-init-keymaps ()
+ (setq slime-presentation-command-map (make-sparse-keymap))
+ (loop for (key command) in slime-presentation-bindings
+ do (progn
+ ;; We bind both unmodified and with control.
+ (define-key slime-presentation-command-map (vector key) command)
+ (let ((modified (slime-control-modified-char key)))
+ (define-key slime-presentation-command-map (vector modified) command))))
+ (define-key slime-presentation-command-map "\M-o" 'slime-clear-presentations)
+ ;; C-c C-v is the prefix for the presentation-command map.
+ (slime-define-key "\C-v" slime-presentation-command-map :prefixed t :inferior t)
+ (define-key slime-repl-mode-map "\C-c\C-v" slime-presentation-command-map)
+ (define-key sldb-mode-map "\C-c\C-v" slime-presentation-command-map)
+ (define-key slime-inspector-mode-map "\C-c\C-v" slime-presentation-command-map))
+
+(defun slime-presentation-around-or-before-point-p ()
+ (multiple-value-bind (presentation beg end)
+ (slime-presentation-around-or-before-point (point))
+ presentation))
+
+(defvar slime-presentation-easy-menu
+ (let ((P '(slime-presentation-around-or-before-point-p)))
+ `("Presentations"
+ [ "Inspect" slime-inspect-presentation-at-point ,P ]
+ [ "Describe" slime-describe-presentation-at-point ,P ]
+ [ "Pretty-print" slime-pretty-print-presentation-at-point ,P ]
+ [ "Copy to REPL" slime-copy-presentation-at-point-to-repl ,P ]
+ [ "Copy to kill ring" slime-copy-presentation-at-point-to-kill-ring ,P ]
+ [ "Mark" slime-mark-presentation ,P ]
+ "--"
+ [ "Previous presentation" slime-previous-presentation ]
+ [ "Next presentation" slime-next-presentation ]
+ "--"
+ [ "Clear all presentations" slime-clear-presentations ])))
+
+(defun slime-presentation-add-easy-menu ()
+ (easy-menu-define menubar-slime-presentation slime-mode-map "Presentations" slime-presentation-easy-menu)
+ (easy-menu-define menubar-slime-presentation slime-repl-mode-map "Presentations" slime-presentation-easy-menu)
+ (easy-menu-define menubar-slime-presentation sldb-mode-map "Presentations" slime-presentation-easy-menu)
+ (easy-menu-add slime-presentation-easy-menu 'slime-mode-map)
+ (easy-menu-add slime-presentation-easy-menu 'slime-repl-mode-map)
+ (easy-menu-add slime-presentation-easy-menu 'sldb-mode-map))
+
+;;; hook functions (hard to isolate stuff)
+
+(defun slime-dispatch-presentation-event (event)
+ (destructure-case event
+ ((:presentation-start id &optional target)
+ (slime-mark-presentation-start id target)
+ t)
+ ((:presentation-end id &optional target)
+ (slime-mark-presentation-end id target)
+ t)
+ (t nil)))
+
+(defun slime-presentation-write (string &optional target)
+ (case target
+ ((nil) ; Regular process output
+ (with-current-buffer (slime-output-buffer)
+ (slime-with-output-end-mark
+ (slime-propertize-region '(face slime-repl-output-face
+ rear-nonsticky (face))
+ (insert string))
+ (set-marker slime-output-end (point))
+ (when (and (= (point) slime-repl-prompt-start-mark)
+ (not (bolp)))
+ (insert "\n")
+ (set-marker slime-output-end (1- (point))))
+ (if (< slime-repl-input-start-mark (point))
+ (set-marker slime-repl-input-start-mark
+ (point))))))
+ (:repl-result
+ (with-current-buffer (slime-output-buffer)
+ (let ((marker (slime-output-target-marker target)))
+ (goto-char marker)
+ (let ((result-start (point)))
+ (slime-propertize-region `(face slime-repl-result-face
+ rear-nonsticky (face))
+ (insert string))
+ ;; Move the input-start marker after the REPL result.
+ (set-marker marker (point))))))
+ (t
+ (let* ((marker (slime-output-target-marker target))
+ (buffer (and marker (marker-buffer marker))))
+ (when buffer
+ (with-current-buffer buffer
+ (save-excursion
+ ;; Insert STRING at MARKER, then move MARKER behind
+ ;; the insertion.
+ (goto-char marker)
+ (insert-before-markers string)
+ (set-marker marker (point)))))))))
+
+(defun slime-presentation-current-input (&optional until-point-p)
+ "Return the current input as string.
+The input is the region from after the last prompt to the end of
+buffer. Presentations of old results are expanded into code."
+ (slime-buffer-substring-with-reified-output slime-repl-input-start-mark
+ (if (and until-point-p
+ (<= (point) slime-repl-input-end-mark))
+ (point)
+ slime-repl-input-end-mark)))
+(defun slime-presentation-on-return-pressed ()
+ (cond ((and (car (slime-presentation-around-or-before-point (point)))
+ (< (point) slime-repl-input-start-mark))
+ (slime-repl-grab-old-output end-of-input)
+ (slime-repl-recenter-if-needed)
+ t)
+ (t nil)))
+
+(defun slime-presentation-on-stream-open (stream)
+ (require 'bridge)
+ (defun bridge-insert (process output)
+ (slime-output-filter process (or output "")))
+ (install-bridge)
+ (setq bridge-destination-insert nil)
+ (setq bridge-source-insert nil)
+ (setq bridge-handlers
+ (list* '("<" . slime-mark-presentation-start-handler)
+ '(">" . slime-mark-presentation-end-handler)
+ bridge-handlers)))
+
+(defun slime-clear-presentations ()
+ "Forget all objects associated to SLIME presentations.
+This allows the garbage collector to remove these objects
+even on Common Lisp implementations without weak hash tables."
+ (interactive)
+ (slime-eval-async `(swank:clear-repl-results))
+ (unless (eql major-mode 'slime-repl-mode)
+ (slime-switch-to-output-buffer))
+ (slime-for-each-presentation-in-region 1 (1+ (buffer-size))
+ (lambda (presentation from to whole-p)
+ (slime-remove-presentation-properties from to
+ presentation))))
+
+;;; Initialization
+
+(defun slime-presentations-init ()
+ (add-hook 'slime-repl-mode-hook
+ (lambda ()
+ ;; Respect the syntax text properties of presentation.
+ (set (make-local-variable 'parse-sexp-lookup-properties) t)
+ (add-local-hook 'after-change-functions
+ 'slime-after-change-function)))
+ (add-hook 'slime-event-hooks 'slime-dispatch-presentation-event)
+ (setq slime-write-string-function 'slime-presentation-write)
+ (add-hook 'slime-repl-return-hooks 'slime-presentation-on-return-pressed)
+ (add-hook 'slime-repl-current-input-hooks 'slime-presentation-current-input)
+ (add-hook 'slime-open-stream-hooks 'slime-presentation-on-stream-open)
+ (add-hook 'slime-repl-clear-buffer-hook 'slime-clear-presentations)
+ (add-hook 'slime-connected-hook 'slime-install-presentations)
+ (slime-presentation-init-keymaps)
+ (slime-presentation-add-easy-menu))
+
+(defun slime-install-presentations ()
+ (slime-eval-async '(swank:swank-require :swank-presentations)))
+
+(slime-presentations-init)
+
+(provide 'slime-presentations)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-references.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-references.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,135 @@
+;;; slime-references.el --- Clickable references to documentation (SBCL only)
+;;
+;; Authors: Christophe Rhodes <csr21 at cantab.net>
+;; Luke Gorrie <luke at bluetail.com>
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;;
+
+(defcustom slime-sbcl-manual-root "http://www.sbcl.org/manual/"
+ "*The base URL of the SBCL manual, for documentation lookup."
+ :type 'string
+ :group 'slime-mode)
+
+(defface sldb-reference-face
+ (list (list t '(:underline t)))
+ "Face for references."
+ :group 'slime-debugger)
+
+(defun slime-note.references (note)
+ (plist-get note :references))
+
+(defun slime-tree-print-with-references (tree)
+ ;; for SBCL-style references
+ (slime-tree-default-printer tree)
+ (when-let (note (plist-get (slime-tree.plist tree) 'note))
+ (when-let (references (slime-note.references note))
+ (terpri (current-buffer))
+ (princ "See also:" (current-buffer))
+ (terpri (current-buffer))
+ (slime-tree-insert-references references))))
+
+(defun slime-tree-insert-references (references)
+ "Insert documentation references from a condition.
+See SWANK-BACKEND:CONDITION-REFERENCES for the datatype."
+ (loop for refs on references
+ for ref = (car refs)
+ do
+ (destructuring-bind (where type what) ref
+ ;; FIXME: this is poorly factored, and shares some code and
+ ;; data with sldb that it shouldn't: notably
+ ;; sldb-reference-face. Probably the names of
+ ;; sldb-reference-foo should be altered to be not sldb
+ ;; specific.
+ (insert " " (sldb-format-reference-source where) ", ")
+ (slime-insert-propertized (sldb-reference-properties ref)
+ (sldb-format-reference-node what))
+ (insert (format " [%s]" type))
+ (when (cdr refs)
+ (terpri (current-buffer))))))
+
+
+;;;;; SLDB references (rather SBCL specific)
+
+(defun sldb-insert-references (references)
+ "Insert documentation references from a condition.
+See SWANK-BACKEND:CONDITION-REFERENCES for the datatype."
+ (dolist (ref references)
+ (destructuring-bind (where type what) ref
+ (insert "\n" (sldb-format-reference-source where) ", ")
+ (slime-insert-propertized (sldb-reference-properties ref)
+ (sldb-format-reference-node what))
+ (insert (format " [%s]" type)))))
+
+(defun sldb-reference-properties (reference)
+ "Return the properties for a reference.
+Only add clickability to properties we actually know how to lookup."
+ (destructuring-bind (where type what) reference
+ (if (or (and (eq where :sbcl) (eq type :node))
+ (and (eq where :ansi-cl)
+ (memq type '(:function :special-operator :macro
+ :section :glossary :issue))))
+ `(sldb-default-action
+ sldb-lookup-reference
+ ;; FIXME: this is a hack! slime-compiler-notes and sldb are a
+ ;; little too intimately entwined.
+ slime-compiler-notes-default-action sldb-lookup-reference
+ sldb-reference ,reference
+ face sldb-reference-face
+ mouse-face highlight))))
+
+(defun sldb-format-reference-source (where)
+ (case where
+ (:amop "The Art of the Metaobject Protocol")
+ (:ansi-cl "Common Lisp Hyperspec")
+ (:sbcl "SBCL Manual")
+ (t (format "%S" where))))
+
+(defun sldb-format-reference-node (what)
+ (if (listp what)
+ (mapconcat #'prin1-to-string what ".")
+ what))
+
+(defun sldb-lookup-reference ()
+ "Browse the documentation reference at point."
+ (destructuring-bind (where type what)
+ (get-text-property (point) 'sldb-reference)
+ (case where
+ (:ansi-cl
+ (case type
+ (:section
+ (browse-url (funcall common-lisp-hyperspec-section-fun what)))
+ (:glossary
+ (browse-url (funcall common-lisp-glossary-fun what)))
+ (:issue
+ (browse-url (funcall 'common-lisp-issuex what)))
+ (t
+ (hyperspec-lookup what))))
+ (t
+ (let ((url (format "%s%s.html" slime-sbcl-manual-root
+ (subst-char-in-string ?\ ?\- what))))
+ (browse-url url))))))
+
+(defun sldb-maybe-insert-references (extra)
+ (destructure-case extra
+ ((:references references)
+ (when references
+ (insert "\nSee also:")
+ (slime-with-rigid-indentation 2
+ (sldb-insert-references references)))
+ t)
+ (t nil)))
+
+
+;;; Initialization
+
+(defun slime-references-init ()
+ (setq slime-tree-printer 'slime-tree-print-with-references)
+ (add-hook 'sldb-extras-hooks 'sldb-maybe-insert-references))
+
+(defun slime-references-unload ()
+ (setq slime-tree-printer 'slime-tree-default-printer)
+ (remove-hook 'sldb-extras-hooks 'sldb-maybe-insert-references))
+
+(provide 'slime-references)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-scheme.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-scheme.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,38 @@
+;;; slime-scheme.el --- Support Scheme programs running under Common Lisp
+;;
+;; Authors: Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;;
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-scheme)))
+;;
+
+(defun slime-scheme-mode-hook ()
+ (slime-mode 1))
+
+(defun slime-scheme-indentation-update (symbol indent)
+ ;; Does the symbol have an indentation value that we set?
+ (when (equal (get symbol 'scheme-indent-function)
+ (get symbol 'slime-scheme-indent))
+ (put symbol 'slime-scheme-indent indent)
+ (put symbol 'scheme-indent-function indent)))
+
+
+;;; Initialization
+
+(defun slime-scheme-init ()
+ (add-hook 'scheme-mode-hook 'slime-scheme-mode-hook)
+ (add-hook 'slime-indentation-update-hooks 'slime-scheme-indentation-update)
+ (add-to-list 'slime-lisp-modes 'scheme-mode))
+
+(defun slime-scheme-unload ()
+ (remove-hook 'scheme-mode-hook 'slime-scheme-mode-hook)
+ (remove-hook 'slime-indentation-update-hooks 'slime-scheme-indentation-update)
+ (setq slime-lisp-modes (remove 'scheme-mode slime-lisp-modes)))
+
+(provide 'slime-scheme)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-scratch.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-scratch.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,48 @@
+;;; slime-scratch.el --- imitate Emacs' *scratch* buffer
+;;
+;; Author: Helmut Eller <heller at common-lisp.net>
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path ".../slime/contrib")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-scratch)))
+;;
+
+
+;;; Code
+
+(defvar slime-scratch-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map lisp-mode-map)
+ map))
+
+(defun slime-scratch ()
+ (interactive)
+ (slime-switch-to-scratch-buffer))
+
+(defun slime-switch-to-scratch-buffer ()
+ (set-buffer (slime-scratch-buffer))
+ (unless (eq (current-buffer) (window-buffer))
+ (pop-to-buffer (current-buffer) t)))
+
+(defun slime-scratch-buffer ()
+ "Return the scratch buffer, create it if necessary."
+ (or (get-buffer "*slime-scratch*")
+ (with-current-buffer (get-buffer-create "*slime-scratch*")
+ (lisp-mode)
+ (use-local-map slime-scratch-mode-map)
+ (slime-mode t)
+ (current-buffer))))
+
+(slime-define-keys slime-scratch-mode-map
+ ("\C-j" 'slime-eval-print-last-expression))
+
+(defun slime-scratch-init ()
+ (def-slime-selector-method ?s
+ "*slime-scratch* buffer."
+ (slime-scratch-buffer)))
+
+(provide 'slime-scratch)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-tramp.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-tramp.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,55 @@
+;;; slime-tramp.el --- Filename translations for tramp
+;;
+;; Authors: Marco Baringer <mb at bese.it>
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path ".../slime/contrib")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-tramp)))
+;;
+
+(defun slime-make-tramp-file-name (username remote-host lisp-filename)
+ "Old (with multi-hops) tramp compatability function"
+ (require 'tramp)
+ (if (boundp 'tramp-multi-methods)
+ (tramp-make-tramp-file-name nil nil
+ username
+ remote-host
+ lisp-filename)
+ (tramp-make-tramp-file-name nil
+ username
+ remote-host
+ lisp-filename)))
+
+(defun* slime-create-filename-translator (&key machine-instance
+ remote-host
+ username)
+ "Creates a three element list suitable for push'ing onto
+slime-filename-translations which uses Tramp to load files on
+hostname using username. MACHINE-INSTANCE is a required
+parameter, REMOTE-HOST defaults to MACHINE-INSTANCE and USERNAME
+defaults to (user-login-name).
+
+MACHINE-INSTANCE is the value returned by slime-machine-instance,
+which is just the value returned by cl:machine-instance on the
+remote lisp. REMOTE-HOST is the fully qualified domain name (or
+just the IP) of the remote machine. USERNAME is the username we
+should login with.
+The functions created here expect your tramp-default-method or
+ tramp-default-method-alist to be setup correctly."
+ (lexical-let ((remote-host (or remote-host machine-instance))
+ (username (or username (user-login-name))))
+ (list (concat "^" machine-instance "$")
+ (lambda (emacs-filename)
+ (tramp-file-name-localname
+ (tramp-dissect-file-name emacs-filename)))
+ `(lambda (lisp-filename)
+ (slime-make-tramp-file-name
+ ,username
+ ,remote-host
+ lisp-filename)))))
+
+(provide 'slime-tramp)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-typeout-frame.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-typeout-frame.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,91 @@
+;;; slime-typeout-frame.el --- display some message in a dedicated frame
+;;
+;; Author: Luke Gorrie <luke at synap.se>
+;; License: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add something like this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-typeout-frame)))
+;;
+
+
+;;;; Typeout frame
+
+;; When a "typeout frame" exists it is used to display certain
+;; messages instead of the echo area or pop-up windows.
+
+(defvar slime-typeout-window nil
+ "The current typeout window.")
+
+(defvar slime-typeout-frame-properties
+ '((height . 10) (minibuffer . nil))
+ "The typeout frame properties (passed to `make-frame').")
+
+(defun slime-typeout-active-p ()
+ (and slime-typeout-window
+ (window-live-p slime-typeout-window)))
+
+(defun slime-typeout-message-aux (format-string &rest format-args)
+ (slime-ensure-typeout-frame)
+ (with-current-buffer (window-buffer slime-typeout-window)
+ (let ((msg (apply #'format format-string format-args)))
+ (unless (string= msg "")
+ (erase-buffer)
+ (insert msg)))))
+
+(defun slime-typeout-message (format-string &rest format-args)
+ (apply #'slime-typeout-message-aux format-string format-args)
+ ;; Disable the timer for autodoc temporarily, as it would overwrite
+ ;; the current typeout message otherwise.
+ (when (and (featurep 'slime-autodoc) slime-autodoc-mode)
+ (slime-autodoc-stop-timer)
+ (add-hook 'pre-command-hook #'slime-autodoc-start-timer)))
+
+(defun slime-make-typeout-frame ()
+ "Create a frame for displaying messages (e.g. arglists)."
+ (interactive)
+ (let ((frame (make-frame slime-typeout-frame-properties)))
+ (save-selected-window
+ (select-window (frame-selected-window frame))
+ (switch-to-buffer "*SLIME-Typeout*")
+ (setq slime-typeout-window (selected-window)))))
+
+(defun slime-ensure-typeout-frame ()
+ "Create the typeout frame unless it already exists."
+ (interactive)
+ (unless (slime-typeout-active-p)
+ (slime-make-typeout-frame)))
+
+(defun slime-typeout-autodoc-message (doc)
+ ;; No need for refreshing per `slime-autodoc-pre-command-refresh-echo-area'.
+ (setq slime-autodoc-last-message "")
+ (slime-typeout-message-aux "%s" doc))
+
+
+;;; Initialization
+
+(defvar slime-typeout-frame-unbind-stack ())
+
+(defun slime-typeout-frame-init ()
+ (add-hook 'slime-connected-hook 'slime-ensure-typeout-frame)
+ (loop for (var value) in
+ '((slime-message-function slime-typeout-message)
+ (slime-background-message-function slime-typeout-message)
+ (slime-autodoc-message-function slime-typeout-autodoc-message))
+ do (slime-typeout-frame-init-var var value)))
+
+(defun slime-typeout-frame-init-var (var value)
+ (push (list var (if (boundp var) (symbol-value var) 'slime-unbound))
+ slime-typeout-frame-unbind-stack)
+ (set var value))
+
+(defun slime-typeout-frame-unload ()
+ (remove-hook 'slime-connected-hook 'slime-ensure-typeout-frame)
+ (loop for (var value) in slime-typeout-frame-unbind-stack
+ do (cond ((eq var 'slime-unbound) (makunbound var))
+ (t (set var value)))))
+
+(provide 'slime-typeout-frame)
Added: branches/bos/thirdparty/emacs/slime/contrib/slime-xref-browser.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/slime-xref-browser.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,104 @@
+;;; slime-xref-browser.el --- xref browsing with tree-widget
+;;
+;; Author: Rui Patrocínio <rui.patrocinio at netvisao.pt>
+;; Licencse: GNU GPL (same license as Emacs)
+;;
+;;; Installation:
+;;
+;; Add this to your .emacs:
+;;
+;; (add-to-list 'load-path "<directory-of-this-file>")
+;; (add-hook 'slime-load-hook (lambda () (require 'slime-xref-browser)))
+;;
+
+
+;;;; classes browser
+
+(defun slime-expand-class-node (widget)
+ (or (widget-get widget :args)
+ (let ((name (widget-get widget :tag)))
+ (loop for kid in (slime-eval `(swank:mop :subclasses ,name))
+ collect `(tree-widget :tag ,kid
+ :dynargs slime-expand-class-node
+ :has-children t)))))
+
+(defun slime-browse-classes (name)
+ "Read the name of a class and show its subclasses."
+ (interactive (list (slime-read-symbol-name "Class Name: ")))
+ (slime-call-with-browser-setup
+ "*slime class browser*" (slime-current-package) "Class Browser"
+ (lambda ()
+ (widget-create 'tree-widget :tag name
+ :dynargs 'slime-expand-class-node
+ :has-echildren t))))
+
+(defvar slime-browser-map nil
+ "Keymap for tree widget browsers")
+
+(require 'tree-widget)
+(unless slime-browser-map
+ (setq slime-browser-map (make-sparse-keymap))
+ (set-keymap-parent slime-browser-map widget-keymap)
+ (define-key slime-browser-map "q" 'bury-buffer))
+
+(defun slime-call-with-browser-setup (buffer package title fn)
+ (switch-to-buffer buffer)
+ (kill-all-local-variables)
+ (setq slime-buffer-package package)
+ (let ((inhibit-read-only t)) (erase-buffer))
+ (widget-insert title "\n\n")
+ (save-excursion
+ (funcall fn))
+ (lisp-mode-variables t)
+ (slime-mode t)
+ (use-local-map slime-browser-map)
+ (widget-setup))
+
+
+;;;; Xref browser
+
+(defun slime-fetch-browsable-xrefs (type name)
+ "Return a list ((LABEL DSPEC)).
+LABEL is just a string for display purposes.
+DSPEC can be used to expand the node."
+ (let ((xrefs '()))
+ (loop for (_file . specs) in (slime-eval `(swank:xref ,type ,name)) do
+ (loop for (dspec . _location) in specs do
+ (let ((exp (ignore-errors (read (downcase dspec)))))
+ (cond ((and (consp exp) (eq 'flet (car exp)))
+ ;; we can't expand FLET references so they're useless
+ )
+ ((and (consp exp) (eq 'method (car exp)))
+ ;; this isn't quite right, but good enough for now
+ (push (list dspec (string (second exp))) xrefs))
+ (t
+ (push (list dspec dspec) xrefs))))))
+ xrefs))
+
+(defun slime-expand-xrefs (widget)
+ (or (widget-get widget :args)
+ (let* ((type (widget-get widget :xref-type))
+ (dspec (widget-get widget :xref-dspec))
+ (xrefs (slime-fetch-browsable-xrefs type dspec)))
+ (loop for (label dspec) in xrefs
+ collect `(tree-widget :tag ,label
+ :xref-type ,type
+ :xref-dspec ,dspec
+ :dynargs slime-expand-xrefs
+ :has-children t)))))
+
+(defun slime-browse-xrefs (name type)
+ "Show the xref graph of a function in a tree widget."
+ (interactive
+ (list (slime-read-from-minibuffer "Name: "
+ (slime-symbol-name-at-point))
+ (read (completing-read "Type: " (slime-bogus-completion-alist
+ '(":callers" ":callees" ":calls"))
+ nil t ":"))))
+ (slime-call-with-browser-setup
+ "*slime xref browser*" (slime-current-package) "Xref Browser"
+ (lambda ()
+ (widget-create 'tree-widget :tag name :xref-type type :xref-dspec name
+ :dynargs 'slime-expand-xrefs :has-echildren t))))
+
+(provide 'slime-xref-browser)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-arglists.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-arglists.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,1212 @@
+;;; swank-arglists.lisp --- arglist related code ??
+;;
+;; Authors: Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: Public Domain
+;;
+
+(in-package :swank)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (swank-require :swank-c-p-c))
+
+(defun valid-operator-symbol-p (symbol)
+ "Is SYMBOL the name of a function, a macro, or a special-operator?"
+ (or (fboundp symbol)
+ (macro-function symbol)
+ (special-operator-p symbol)
+ (eq symbol 'declare)))
+
+(defun valid-operator-name-p (string)
+ "Is STRING the name of a function, macro, or special-operator?"
+ (let ((symbol (parse-symbol string)))
+ (valid-operator-symbol-p symbol)))
+
+(defslimefun arglist-for-echo-area (raw-specs &key arg-indices
+ print-right-margin print-lines)
+ "Return the arglist for the first valid ``form spec'' in
+RAW-SPECS. A ``form spec'' is a superset of functions, macros,
+special-ops, declarations and type specifiers.
+
+For more information about the format of ``raw form specs'' and
+``form specs'', please see PARSE-FORM-SPEC."
+ (handler-case
+ (with-buffer-syntax ()
+ (multiple-value-bind (form-spec position newly-interned-symbols)
+ (parse-first-valid-form-spec raw-specs #'read-conversatively-for-autodoc)
+ (unwind-protect
+ (when form-spec
+ (let ((arglist (arglist-from-form-spec form-spec :remove-args nil)))
+ (unless (eql arglist :not-available)
+ (multiple-value-bind (type operator arguments)
+ (split-form-spec form-spec)
+ (declare (ignore arguments))
+ (multiple-value-bind (stringified-arglist)
+ (decoded-arglist-to-string
+ arglist
+ :operator operator
+ :print-right-margin print-right-margin
+ :print-lines print-lines
+ :highlight (let ((index (nth position arg-indices)))
+ ;; don't highlight the operator
+ (and index (not (zerop index)) index)))
+ ;; Post formatting:
+ (case type
+ (:type-specifier (format nil "[Typespec] ~A" stringified-arglist))
+ (:declaration
+ (locally (declare (special *arglist-pprint-bindings*))
+ (with-bindings *arglist-pprint-bindings*
+ (let ((op (%find-declaration-operator raw-specs position)))
+ (if op
+ (format nil "(~A ~A)" op stringified-arglist)
+ (format nil "[Declaration] ~A" stringified-arglist))))))
+ (t stringified-arglist)))))))
+ (mapc #'unintern-in-home-package newly-interned-symbols))))
+ (error (cond)
+ (format nil "ARGLIST (error): ~A" cond))
+ ))
+
+(defun %find-declaration-operator (raw-specs position)
+ (let ((op-rawspec (nth (1+ position) raw-specs)))
+ (first (parse-form-spec op-rawspec #'read-conversatively-for-autodoc))))
+
+;; This is a wrapper object around anything that came from Slime and
+;; could not reliably be read.
+(defstruct (arglist-dummy
+ (:conc-name #:arglist-dummy.)
+ (:print-object (lambda (struct stream)
+ (with-struct (arglist-dummy. string-representation) struct
+ (write-string string-representation stream)))))
+ string-representation)
+
+(defun read-conversatively-for-autodoc (string)
+ "Tries to find the symbol that's represented by STRING.
+
+If it can't, this either means that STRING does not represent a
+symbol, or that the symbol behind STRING would have to be freshly
+interned. Because this function is supposed to be called from the
+automatic arglist display stuff from Slime, interning freshly
+symbols is a big no-no.
+
+In such a case (that no symbol could be found), an object of type
+ARGLIST-DUMMY is returned instead, which works as a placeholder
+datum for subsequent logics to rely on."
+ (let* ((string (string-left-trim '(#\Space #\Tab #\Newline) string))
+ (quoted? (eql (aref string 0) #\')))
+ (multiple-value-bind (symbol found?)
+ (parse-symbol (if quoted? (subseq string 1) string))
+ (if found?
+ (if quoted? `(quote ,symbol) symbol)
+ (make-arglist-dummy :string-representation string)))))
+
+
+(defun parse-form-spec (raw-spec &optional reader)
+ "Takes a raw (i.e. unparsed) form spec from SLIME and returns a
+proper form spec for further processing within SWANK. Returns NIL
+if RAW-SPEC could not be parsed. Symbols that had to be interned
+in course of the conversion, are returned as secondary return value.
+
+A ``raw form spec'' can be either:
+
+ i) a list of strings representing a Common Lisp form
+
+ ii) a list of strings as of i), but which additionally
+ contains other raw form specs
+
+ iii) one of:
+
+ a) (:declaration declspec)
+
+ where DECLSPEC is a raw form spec.
+
+ b) (:type-specifier typespec)
+
+ where TYPESPEC is a raw form spec.
+
+
+A ``form spec'' is either
+
+ 1) a normal Common Lisp form
+
+ 2) a Common Lisp form with a list as its CAR specifying what namespace
+ the operator is supposed to be interpreted in:
+
+ a) ((:declaration decl-identifier) declarg1 declarg2 ...)
+
+ b) ((:type-specifier typespec-op) typespec-arg1 typespec-arg2 ...)
+
+
+Examples:
+
+ (\"defmethod\") => (defmethod)
+ (\"cl:defmethod\") => (cl:defmethod)
+ (\"defmethod\" \"print-object\") => (defmethod print-object)
+
+ (\"foo\" (\"bar\" (\"quux\")) \"baz\" => (foo (bar (quux)) baz)
+
+ (:declaration \"optimize\" \"(optimize)\") => ((:declaration optimize))
+ (:declaration \"type\" \"(type string)\") => ((:declaration type) string)
+ (:type-specifier \"float\" \"(float)\") => ((:type-specifier float))
+ (:type-specifier \"float\" \"(float 0 100)\") => ((:type-specifier float) 0 100)
+"
+ (flet ((parse-extended-spec (raw-extension extension-flag)
+ (when (and (stringp (first raw-extension)) ; (:DECLARATION (("a" "b" ("c")) "d"))
+ (nth-value 1 (parse-symbol (first raw-extension))))
+ (multiple-value-bind (extension introduced-symbols)
+ (read-form-spec raw-extension reader)
+ (unless (recursively-empty-p extension) ; (:DECLARATION (())) &c.
+ (destructuring-bind (identifier &rest args) extension
+ (values `((,extension-flag ,identifier) , at args)
+ introduced-symbols)))))))
+ (when (consp raw-spec)
+ (destructure-case raw-spec
+ ((:declaration raw-declspec)
+ (parse-extended-spec raw-declspec :declaration))
+ ((:type-specifier raw-typespec)
+ (parse-extended-spec raw-typespec :type-specifier))
+ (t
+ (when (every #'(lambda (x) (or (stringp x) (consp x))) raw-spec)
+ (destructuring-bind (raw-operator &rest raw-args) raw-spec
+ (multiple-value-bind (operator found?) (parse-symbol raw-operator)
+ (when (and found? (valid-operator-symbol-p operator))
+ (multiple-value-bind (parsed-args introduced-symbols)
+ (read-form-spec raw-args reader)
+ (values `(,operator , at parsed-args) introduced-symbols)))))))))))
+
+
+(defun split-form-spec (spec)
+ "Returns all three relevant information a ``form spec''
+contains: the operator type, the operator, and the operands."
+ (destructuring-bind (operator-designator &rest arguments) spec
+ (multiple-value-bind (type operator)
+ (if (listp operator-designator)
+ (values (first operator-designator) (second operator-designator))
+ (values :function operator-designator)) ; functions, macros, special ops
+ (values type operator arguments)))) ; are all fbound.
+
+(defun parse-first-valid-form-spec (raw-specs &optional reader)
+ "Returns the first parsed form spec in RAW-SPECS that can
+successfully be parsed. Additionally returns that spec's position
+as secondary, and all newly interned symbols as tertiary return
+value."
+ (loop for raw-spec in raw-specs
+ for pos upfrom 0
+ do (multiple-value-bind (spec symbols) (parse-form-spec raw-spec reader)
+ (when spec (return (values spec pos symbols))))))
+
+(defun read-form-spec (spec &optional reader)
+ "Turns the ``raw form spec'' SPEC into a proper Common Lisp
+form. As secondary return value, it returns all the symbols that
+had to be newly interned during the conversion.
+
+READER is a function that takes a string, and returns two values:
+the Common Lisp datum that the string represents, a flag whether
+the returned datum is a symbol and has been newly interned in
+some package.
+
+If READER is not explicitly given, the function
+READ-SOFTLY-FROM-STRING* is used instead."
+ (when spec
+ (with-buffer-syntax ()
+ (call-with-ignored-reader-errors
+ #'(lambda ()
+ (let ((result) (newly-interned-symbols) (ok))
+ (unwind-protect
+ (dolist (element spec (setq ok t))
+ (etypecase element
+ (string
+ (multiple-value-bind (sexp newly-interned?)
+ (funcall (or reader 'read-softly-from-string*) element)
+ (push sexp result)
+ (when newly-interned?
+ (push sexp newly-interned-symbols))))
+ (list
+ (multiple-value-bind (read-spec interned-symbols)
+ (read-form-spec element reader)
+ (push read-spec result)
+ (setf newly-interned-symbols
+ (append interned-symbols
+ newly-interned-symbols))))))
+ (unless ok
+ (mapc #'unintern-in-home-package newly-interned-symbols)))
+ (values (nreverse result)
+ (nreverse newly-interned-symbols))))))))
+
+(defun read-softly-from-string* (string)
+ "Like READ-SOFTLY-FROM-STRING, but only returns the sexp and
+the flag if a symbol had to be interned."
+ (multiple-value-bind (sexp pos interned?)
+ (read-softly-from-string string)
+ ;; To make sure that we haven't got any junk from Emacs.
+ (assert (= pos (length string)))
+ (values sexp interned?)))
+
+
+(defstruct (arglist (:conc-name arglist.) (:predicate arglist-p))
+ provided-args ; list of the provided actual arguments
+ required-args ; list of the required arguments
+ optional-args ; list of the optional arguments
+ key-p ; whether &key appeared
+ keyword-args ; list of the keywords
+ rest ; name of the &rest or &body argument (if any)
+ body-p ; whether the rest argument is a &body
+ allow-other-keys-p ; whether &allow-other-keys appeared
+ aux-args ; list of &aux variables
+ any-p ; whether &any appeared
+ any-args ; list of &any arguments [*]
+ known-junk ; &whole, &environment
+ unknown-junk) ; unparsed stuff
+
+;;;
+;;; [*] The &ANY lambda keyword is an extension to ANSI Common Lisp,
+;;; and is only used to describe certain arglists that cannot be
+;;; described in another way.
+;;;
+;;; &ANY is very similiar to &KEY but while &KEY is based upon
+;;; the idea of a plist (key1 value1 key2 value2), &ANY is a
+;;; cross between &OPTIONAL, &KEY and *FEATURES* lists:
+;;;
+;;; a) (&ANY :A :B :C) means that you can provide any (non-null)
+;;; set consisting of the keywords `:A', `:B', or `:C' in
+;;; the arglist. E.g. (:A) or (:C :B :A).
+;;;
+;;; (This is not restricted to keywords only, but any self-evaluating
+;;; expression is allowed.)
+;;;
+;;; b) (&ANY (key1 v1) (key2 v2) (key3 v3)) means that you can
+;;; provide any (non-null) set consisting of lists where
+;;; the CAR of the list is one of `key1', `key2', or `key3'.
+;;; E.g. ((key1 100) (key3 42)), or ((key3 66) (key2 23))
+;;;
+;;;
+;;; For example, a) let us describe the situations of EVAL-WHEN as
+;;;
+;;; (EVAL-WHEN (&ANY :compile-toplevel :load-toplevel :execute) &BODY body)
+;;;
+;;; and b) let us describe the optimization qualifiers that are valid
+;;; in the declaration specifier `OPTIMIZE':
+;;;
+;;; (DECLARE (OPTIMIZE &ANY (compilation-speed 1) (safety 1) ...))
+;;;
+
+;; FIXME: This really ought to be rewritten.
+(defun print-arglist (arglist &key operator highlight)
+ (let ((index 0)
+ (need-space nil))
+ (labels ((print-arg (arg)
+ (typecase arg
+ (arglist ; destructuring pattern
+ (print-arglist arg))
+ (optional-arg
+ (let ((enc-arg (encode-optional-arg arg)))
+ (if (symbolp enc-arg)
+ (princ enc-arg)
+ (destructuring-bind (var &optional (initform nil initform-p)) enc-arg
+ (pprint-logical-block (nil nil :prefix "(" :suffix ")")
+ (format t "~A~:[~; ~S~]" var initform-p initform))))))
+ (keyword-arg
+ (let ((enc-arg (encode-keyword-arg arg)))
+ (etypecase enc-arg
+ (symbol (princ enc-arg))
+ ((cons symbol)
+ (destructuring-bind (keyarg initform) enc-arg
+ (pprint-logical-block (nil nil :prefix "(" :suffix ")")
+ (format t "~A ~S" keyarg initform))))
+ ((cons cons)
+ (destructuring-bind ((keyword-name var) &optional (initform nil initform-p))
+ enc-arg
+ (pprint-logical-block (nil nil :prefix "(" :suffix ")")
+ (pprint-logical-block (nil nil :prefix "(" :suffix ")")
+ (format t "~S ~A" keyword-name var))
+ (when initform-p
+ (format t " ~S" initform))))))))
+ (t ; required formal or provided actual arg
+ (if (keywordp arg)
+ (prin1 arg) ; for &ANY args.
+ (princ arg)))))
+ (print-space ()
+ (ecase need-space
+ ((nil))
+ ((:miser)
+ (write-char #\space)
+ (pprint-newline :miser))
+ ((t)
+ (write-char #\space)
+ (pprint-newline :fill)))
+ (setq need-space t))
+ (print-with-space (obj)
+ (print-space)
+ (print-arg obj))
+ (print-with-highlight (arg &optional (index-ok-p #'=))
+ (print-space)
+ (cond
+ ((and highlight (funcall index-ok-p index highlight))
+ (princ "===> ")
+ (print-arg arg)
+ (princ " <==="))
+ (t
+ (print-arg arg)))
+ (incf index)))
+ (pprint-logical-block (nil nil :prefix "(" :suffix ")")
+ (when operator
+ (print-with-highlight operator)
+ (setq need-space :miser))
+ (mapc #'print-with-highlight
+ (arglist.provided-args arglist))
+ (mapc #'print-with-highlight
+ (arglist.required-args arglist))
+ (when (arglist.optional-args arglist)
+ (print-with-space '&optional)
+ (mapc #'print-with-highlight
+ (arglist.optional-args arglist)))
+ (when (arglist.key-p arglist)
+ (print-with-space '&key)
+ (mapc #'print-with-space
+ (arglist.keyword-args arglist)))
+ (when (arglist.allow-other-keys-p arglist)
+ (print-with-space '&allow-other-keys))
+ (when (arglist.any-args arglist)
+ (print-with-space '&any)
+ (mapc #'print-with-space
+ (arglist.any-args arglist)))
+ (cond ((not (arglist.rest arglist)))
+ ((arglist.body-p arglist)
+ (print-with-space '&body)
+ (print-with-highlight (arglist.rest arglist) #'<=))
+ (t
+ (print-with-space '&rest)
+ (print-with-highlight (arglist.rest arglist) #'<=)))
+ (mapc #'print-with-space
+ (arglist.unknown-junk arglist))))))
+
+(defvar *arglist-pprint-bindings*
+ '((*print-case* . :downcase)
+ (*print-pretty* . t)
+ (*print-circle* . nil)
+ (*print-readably* . nil)
+ (*print-level* . 10)
+ (*print-length* . 20)
+ (*print-escape* . nil))) ; no package qualifiers.
+
+(defun decoded-arglist-to-string (arglist
+ &key operator highlight (package *package*)
+ print-right-margin print-lines)
+ "Print the decoded ARGLIST for display in the echo area. The
+argument name are printed without package qualifiers and pretty
+printing of (function foo) as #'foo is suppressed. If HIGHLIGHT is
+non-nil, it must be the index of an argument; highlight this argument.
+If OPERATOR is non-nil, put it in front of the arglist."
+ (with-output-to-string (*standard-output*)
+ (with-standard-io-syntax
+ (with-bindings *arglist-pprint-bindings*
+ (let ((*package* package)
+ (*print-right-margin* print-right-margin)
+ (*print-lines* print-lines))
+ (print-arglist arglist :operator operator :highlight highlight))))))
+
+(defslimefun variable-desc-for-echo-area (variable-name)
+ "Return a short description of VARIABLE-NAME, or NIL."
+ (with-buffer-syntax ()
+ (let ((sym (parse-symbol variable-name)))
+ (if (and sym (boundp sym))
+ (let ((*print-pretty* nil) (*print-level* 4)
+ (*print-length* 10) (*print-circle* t))
+ (format nil "~A => ~A" sym (symbol-value sym)))))))
+
+(defun decode-required-arg (arg)
+ "ARG can be a symbol or a destructuring pattern."
+ (etypecase arg
+ (symbol arg)
+ (list (decode-arglist arg))))
+
+(defun encode-required-arg (arg)
+ (etypecase arg
+ (symbol arg)
+ (arglist (encode-arglist arg))))
+
+(defstruct (keyword-arg
+ (:conc-name keyword-arg.)
+ (:constructor make-keyword-arg (keyword arg-name default-arg)))
+ keyword
+ arg-name
+ default-arg)
+
+(defun decode-keyword-arg (arg)
+ "Decode a keyword item of formal argument list.
+Return three values: keyword, argument name, default arg."
+ (cond ((symbolp arg)
+ (make-keyword-arg (intern (symbol-name arg) keyword-package)
+ arg
+ nil))
+ ((and (consp arg)
+ (consp (car arg)))
+ (make-keyword-arg (caar arg)
+ (decode-required-arg (cadar arg))
+ (cadr arg)))
+ ((consp arg)
+ (make-keyword-arg (intern (symbol-name (car arg)) keyword-package)
+ (car arg)
+ (cadr arg)))
+ (t
+ (error "Bad keyword item of formal argument list"))))
+
+(defun encode-keyword-arg (arg)
+ (cond
+ ((arglist-p (keyword-arg.arg-name arg))
+ ;; Destructuring pattern
+ (let ((keyword/name (list (keyword-arg.keyword arg)
+ (encode-required-arg
+ (keyword-arg.arg-name arg)))))
+ (if (keyword-arg.default-arg arg)
+ (list keyword/name
+ (keyword-arg.default-arg arg))
+ (list keyword/name))))
+ ((eql (intern (symbol-name (keyword-arg.arg-name arg))
+ keyword-package)
+ (keyword-arg.keyword arg))
+ (if (keyword-arg.default-arg arg)
+ (list (keyword-arg.arg-name arg)
+ (keyword-arg.default-arg arg))
+ (keyword-arg.arg-name arg)))
+ (t
+ (let ((keyword/name (list (keyword-arg.keyword arg)
+ (keyword-arg.arg-name arg))))
+ (if (keyword-arg.default-arg arg)
+ (list keyword/name
+ (keyword-arg.default-arg arg))
+ (list keyword/name))))))
+
+(progn
+ (assert (equalp (decode-keyword-arg 'x)
+ (make-keyword-arg :x 'x nil)))
+ (assert (equalp (decode-keyword-arg '(x t))
+ (make-keyword-arg :x 'x t)))
+ (assert (equalp (decode-keyword-arg '((:x y)))
+ (make-keyword-arg :x 'y nil)))
+ (assert (equalp (decode-keyword-arg '((:x y) t))
+ (make-keyword-arg :x 'y t))))
+
+(defstruct (optional-arg
+ (:conc-name optional-arg.)
+ (:constructor make-optional-arg (arg-name default-arg)))
+ arg-name
+ default-arg)
+
+(defun decode-optional-arg (arg)
+ "Decode an optional item of a formal argument list.
+Return an OPTIONAL-ARG structure."
+ (etypecase arg
+ (symbol (make-optional-arg arg nil))
+ (list (make-optional-arg (decode-required-arg (car arg))
+ (cadr arg)))))
+
+(defun encode-optional-arg (optional-arg)
+ (if (or (optional-arg.default-arg optional-arg)
+ (arglist-p (optional-arg.arg-name optional-arg)))
+ (list (encode-required-arg
+ (optional-arg.arg-name optional-arg))
+ (optional-arg.default-arg optional-arg))
+ (optional-arg.arg-name optional-arg)))
+
+(progn
+ (assert (equalp (decode-optional-arg 'x)
+ (make-optional-arg 'x nil)))
+ (assert (equalp (decode-optional-arg '(x t))
+ (make-optional-arg 'x t))))
+
+(define-modify-macro nreversef () nreverse "Reverse the list in PLACE.")
+
+(defun decode-arglist (arglist)
+ "Parse the list ARGLIST and return an ARGLIST structure."
+ (let ((mode nil)
+ (result (make-arglist)))
+ (dolist (arg arglist)
+ (cond
+ ((eql mode '&unknown-junk)
+ ;; don't leave this mode -- we don't know how the arglist
+ ;; after unknown lambda-list keywords is interpreted
+ (push arg (arglist.unknown-junk result)))
+ ((eql arg '&allow-other-keys)
+ (setf (arglist.allow-other-keys-p result) t))
+ ((eql arg '&key)
+ (setf (arglist.key-p result) t
+ mode arg))
+ ((member arg '(&optional &rest &body &aux))
+ (setq mode arg))
+ ((member arg '(&whole &environment))
+ (setq mode arg)
+ (push arg (arglist.known-junk result)))
+ ((and (symbolp arg)
+ (string= (symbol-name arg) (string '#:&any))) ; may be interned
+ (setf (arglist.any-p result) t) ; in any *package*.
+ (setq mode '&any))
+ ((member arg lambda-list-keywords)
+ (setq mode '&unknown-junk)
+ (push arg (arglist.unknown-junk result)))
+ (t
+ (ecase mode
+ (&key
+ (push (decode-keyword-arg arg)
+ (arglist.keyword-args result)))
+ (&optional
+ (push (decode-optional-arg arg)
+ (arglist.optional-args result)))
+ (&body
+ (setf (arglist.body-p result) t
+ (arglist.rest result) arg))
+ (&rest
+ (setf (arglist.rest result) arg))
+ (&aux
+ (push (decode-optional-arg arg)
+ (arglist.aux-args result)))
+ ((nil)
+ (push (decode-required-arg arg)
+ (arglist.required-args result)))
+ ((&whole &environment)
+ (setf mode nil)
+ (push arg (arglist.known-junk result)))
+ (&any
+ (push arg (arglist.any-args result)))))))
+ (nreversef (arglist.required-args result))
+ (nreversef (arglist.optional-args result))
+ (nreversef (arglist.keyword-args result))
+ (nreversef (arglist.aux-args result))
+ (nreversef (arglist.any-args result))
+ (nreversef (arglist.known-junk result))
+ (nreversef (arglist.unknown-junk result))
+ (assert (or (and (not (arglist.key-p result)) (not (arglist.any-p result)))
+ (exactly-one-p (arglist.key-p result) (arglist.any-p result))))
+ result))
+
+(defun encode-arglist (decoded-arglist)
+ (append (mapcar #'encode-required-arg (arglist.required-args decoded-arglist))
+ (when (arglist.optional-args decoded-arglist)
+ '(&optional))
+ (mapcar #'encode-optional-arg (arglist.optional-args decoded-arglist))
+ (when (arglist.key-p decoded-arglist)
+ '(&key))
+ (mapcar #'encode-keyword-arg (arglist.keyword-args decoded-arglist))
+ (when (arglist.allow-other-keys-p decoded-arglist)
+ '(&allow-other-keys))
+ (when (arglist.any-args decoded-arglist)
+ `(&any ,@(arglist.any-args decoded-arglist)))
+ (cond ((not (arglist.rest decoded-arglist))
+ '())
+ ((arglist.body-p decoded-arglist)
+ `(&body ,(arglist.rest decoded-arglist)))
+ (t
+ `(&rest ,(arglist.rest decoded-arglist))))
+ (when (arglist.aux-args decoded-arglist)
+ `(&aux ,(arglist.aux-args decoded-arglist)))
+ (arglist.known-junk decoded-arglist)
+ (arglist.unknown-junk decoded-arglist)))
+
+(defun arglist-keywords (arglist)
+ "Return the list of keywords in ARGLIST.
+As a secondary value, return whether &allow-other-keys appears."
+ (let ((decoded-arglist (decode-arglist arglist)))
+ (values (arglist.keyword-args decoded-arglist)
+ (arglist.allow-other-keys-p decoded-arglist))))
+
+(defun methods-keywords (methods)
+ "Collect all keywords in the arglists of METHODS.
+As a secondary value, return whether &allow-other-keys appears somewhere."
+ (let ((keywords '())
+ (allow-other-keys nil))
+ (dolist (method methods)
+ (multiple-value-bind (kw aok)
+ (arglist-keywords
+ (swank-mop:method-lambda-list method))
+ (setq keywords (remove-duplicates (append keywords kw)
+ :key #'keyword-arg.keyword)
+ allow-other-keys (or allow-other-keys aok))))
+ (values keywords allow-other-keys)))
+
+(defun generic-function-keywords (generic-function)
+ "Collect all keywords in the methods of GENERIC-FUNCTION.
+As a secondary value, return whether &allow-other-keys appears somewhere."
+ (methods-keywords
+ (swank-mop:generic-function-methods generic-function)))
+
+(defun applicable-methods-keywords (generic-function arguments)
+ "Collect all keywords in the methods of GENERIC-FUNCTION that are
+applicable for argument of CLASSES. As a secondary value, return
+whether &allow-other-keys appears somewhere."
+ (methods-keywords
+ (multiple-value-bind (amuc okp)
+ (swank-mop:compute-applicable-methods-using-classes
+ generic-function (mapcar #'class-of arguments))
+ (if okp
+ amuc
+ (compute-applicable-methods generic-function arguments)))))
+
+(defun decoded-arglist-to-template-string (decoded-arglist package &key (prefix "(") (suffix ")"))
+ (with-output-to-string (*standard-output*)
+ (with-standard-io-syntax
+ (let ((*package* package) (*print-case* :downcase)
+ (*print-pretty* t) (*print-circle* nil) (*print-readably* nil)
+ (*print-level* 10) (*print-length* 20))
+ (print-decoded-arglist-as-template decoded-arglist
+ :prefix prefix
+ :suffix suffix)))))
+
+(defun print-decoded-arglist-as-template (decoded-arglist &key
+ (prefix "(") (suffix ")"))
+ (pprint-logical-block (nil nil :prefix prefix :suffix suffix)
+ (let ((first-p t))
+ (flet ((space ()
+ (unless first-p
+ (write-char #\space)
+ (pprint-newline :fill))
+ (setq first-p nil))
+ (print-arg-or-pattern (arg)
+ (etypecase arg
+ (symbol (if (keywordp arg) (prin1 arg) (princ arg)))
+ (string (princ arg))
+ (list (princ arg))
+ (arglist (print-decoded-arglist-as-template arg)))))
+ (dolist (arg (arglist.required-args decoded-arglist))
+ (space)
+ (print-arg-or-pattern arg))
+ (dolist (arg (arglist.optional-args decoded-arglist))
+ (space)
+ (princ "[")
+ (print-arg-or-pattern (optional-arg.arg-name arg))
+ (princ "]"))
+ (dolist (keyword-arg (arglist.keyword-args decoded-arglist))
+ (space)
+ (let ((arg-name (keyword-arg.arg-name keyword-arg))
+ (keyword (keyword-arg.keyword keyword-arg)))
+ (format t "~W "
+ (if (keywordp keyword) keyword `',keyword))
+ (print-arg-or-pattern arg-name)))
+ (dolist (any-arg (arglist.any-args decoded-arglist))
+ (space)
+ (print-arg-or-pattern any-arg))
+ (when (and (arglist.rest decoded-arglist)
+ (or (not (arglist.keyword-args decoded-arglist))
+ (arglist.allow-other-keys-p decoded-arglist)))
+ (if (arglist.body-p decoded-arglist)
+ (pprint-newline :mandatory)
+ (space))
+ (format t "~A..." (arglist.rest decoded-arglist)))))
+ (pprint-newline :fill)))
+
+
+(defgeneric extra-keywords (operator &rest args)
+ (:documentation "Return a list of extra keywords of OPERATOR (a
+symbol) when applied to the (unevaluated) ARGS.
+As a secondary value, return whether other keys are allowed.
+As a tertiary value, return the initial sublist of ARGS that was needed
+to determine the extra keywords."))
+
+(defun keywords-of-operator (operator)
+ "Return a list of KEYWORD-ARGs that OPERATOR accepts.
+This function is useful for writing EXTRA-KEYWORDS methods for
+user-defined functions which are declared &ALLOW-OTHER-KEYS and which
+forward keywords to OPERATOR."
+ (let ((arglist (arglist-from-form-spec (ensure-list operator)
+ :remove-args nil)))
+ (unless (eql arglist :not-available)
+ (values
+ (arglist.keyword-args arglist)
+ (arglist.allow-other-keys-p arglist)))))
+
+(defmethod extra-keywords (operator &rest args)
+ ;; default method
+ (declare (ignore args))
+ (let ((symbol-function (symbol-function operator)))
+ (if (typep symbol-function 'generic-function)
+ (generic-function-keywords symbol-function)
+ nil)))
+
+(defun class-from-class-name-form (class-name-form)
+ (when (and (listp class-name-form)
+ (= (length class-name-form) 2)
+ (eq (car class-name-form) 'quote))
+ (let* ((class-name (cadr class-name-form))
+ (class (find-class class-name nil)))
+ (when (and class
+ (not (swank-mop:class-finalized-p class)))
+ ;; Try to finalize the class, which can fail if
+ ;; superclasses are not defined yet
+ (handler-case (swank-mop:finalize-inheritance class)
+ (program-error (c)
+ (declare (ignore c)))))
+ class)))
+
+(defun extra-keywords/slots (class)
+ (multiple-value-bind (slots allow-other-keys-p)
+ (if (swank-mop:class-finalized-p class)
+ (values (swank-mop:class-slots class) nil)
+ (values (swank-mop:class-direct-slots class) t))
+ (let ((slot-init-keywords
+ (loop for slot in slots append
+ (mapcar (lambda (initarg)
+ (make-keyword-arg
+ initarg
+ (swank-mop:slot-definition-name slot)
+ (swank-mop:slot-definition-initform slot)))
+ (swank-mop:slot-definition-initargs slot)))))
+ (values slot-init-keywords allow-other-keys-p))))
+
+(defun extra-keywords/make-instance (operator &rest args)
+ (declare (ignore operator))
+ (unless (null args)
+ (let* ((class-name-form (car args))
+ (class (class-from-class-name-form class-name-form)))
+ (when class
+ (multiple-value-bind (slot-init-keywords class-aokp)
+ (extra-keywords/slots class)
+ (multiple-value-bind (allocate-instance-keywords ai-aokp)
+ (applicable-methods-keywords
+ #'allocate-instance (list class))
+ (multiple-value-bind (initialize-instance-keywords ii-aokp)
+ (applicable-methods-keywords
+ #'initialize-instance (list (swank-mop:class-prototype class)))
+ (multiple-value-bind (shared-initialize-keywords si-aokp)
+ (applicable-methods-keywords
+ #'shared-initialize (list (swank-mop:class-prototype class) t))
+ (values (append slot-init-keywords
+ allocate-instance-keywords
+ initialize-instance-keywords
+ shared-initialize-keywords)
+ (or class-aokp ai-aokp ii-aokp si-aokp)
+ (list class-name-form))))))))))
+
+(defun extra-keywords/change-class (operator &rest args)
+ (declare (ignore operator))
+ (unless (null args)
+ (let* ((class-name-form (car args))
+ (class (class-from-class-name-form class-name-form)))
+ (when class
+ (multiple-value-bind (slot-init-keywords class-aokp)
+ (extra-keywords/slots class)
+ (declare (ignore class-aokp))
+ (multiple-value-bind (shared-initialize-keywords si-aokp)
+ (applicable-methods-keywords
+ #'shared-initialize (list (swank-mop:class-prototype class) t))
+ ;; FIXME: much as it would be nice to include the
+ ;; applicable keywords from
+ ;; UPDATE-INSTANCE-FOR-DIFFERENT-CLASS, I don't really see
+ ;; how to do it: so we punt, always declaring
+ ;; &ALLOW-OTHER-KEYS.
+ (declare (ignore si-aokp))
+ (values (append slot-init-keywords shared-initialize-keywords)
+ t
+ (list class-name-form))))))))
+
+(defmacro multiple-value-or (&rest forms)
+ (if (null forms)
+ nil
+ (let ((first (first forms))
+ (rest (rest forms)))
+ `(let* ((values (multiple-value-list ,first))
+ (primary-value (first values)))
+ (if primary-value
+ (values-list values)
+ (multiple-value-or , at rest))))))
+
+(defmethod extra-keywords ((operator (eql 'make-instance))
+ &rest args)
+ (multiple-value-or (apply #'extra-keywords/make-instance operator args)
+ (call-next-method)))
+
+(defmethod extra-keywords ((operator (eql 'make-condition))
+ &rest args)
+ (multiple-value-or (apply #'extra-keywords/make-instance operator args)
+ (call-next-method)))
+
+(defmethod extra-keywords ((operator (eql 'error))
+ &rest args)
+ (multiple-value-or (apply #'extra-keywords/make-instance operator args)
+ (call-next-method)))
+
+(defmethod extra-keywords ((operator (eql 'signal))
+ &rest args)
+ (multiple-value-or (apply #'extra-keywords/make-instance operator args)
+ (call-next-method)))
+
+(defmethod extra-keywords ((operator (eql 'warn))
+ &rest args)
+ (multiple-value-or (apply #'extra-keywords/make-instance operator args)
+ (call-next-method)))
+
+(defmethod extra-keywords ((operator (eql 'cerror))
+ &rest args)
+ (multiple-value-bind (keywords aok determiners)
+ (apply #'extra-keywords/make-instance operator
+ (cdr args))
+ (if keywords
+ (values keywords aok
+ (cons (car args) determiners))
+ (call-next-method))))
+
+(defmethod extra-keywords ((operator (eql 'change-class))
+ &rest args)
+ (multiple-value-bind (keywords aok determiners)
+ (apply #'extra-keywords/change-class operator (cdr args))
+ (if keywords
+ (values keywords aok
+ (cons (car args) determiners))
+ (call-next-method))))
+
+(defun enrich-decoded-arglist-with-keywords (decoded-arglist keywords allow-other-keys-p)
+ "Modify DECODED-ARGLIST using KEYWORDS and ALLOW-OTHER-KEYS-P."
+ (when keywords
+ (setf (arglist.key-p decoded-arglist) t)
+ (setf (arglist.keyword-args decoded-arglist)
+ (remove-duplicates
+ (append (arglist.keyword-args decoded-arglist)
+ keywords)
+ :key #'keyword-arg.keyword)))
+ (setf (arglist.allow-other-keys-p decoded-arglist)
+ (or (arglist.allow-other-keys-p decoded-arglist)
+ allow-other-keys-p)))
+
+(defun enrich-decoded-arglist-with-extra-keywords (decoded-arglist form)
+ "Determine extra keywords from the function call FORM, and modify
+DECODED-ARGLIST to include them. As a secondary return value, return
+the initial sublist of ARGS that was needed to determine the extra
+keywords. As a tertiary return value, return whether any enrichment
+was done."
+ (multiple-value-bind (extra-keywords extra-aok determining-args)
+ (apply #'extra-keywords form)
+ ;; enrich the list of keywords with the extra keywords
+ (enrich-decoded-arglist-with-keywords decoded-arglist
+ extra-keywords extra-aok)
+ (values decoded-arglist
+ determining-args
+ (or extra-keywords extra-aok))))
+
+(defgeneric compute-enriched-decoded-arglist (operator-form argument-forms)
+ (:documentation
+ "Return three values: DECODED-ARGLIST, DETERMINING-ARGS, and
+ANY-ENRICHMENT, just like enrich-decoded-arglist-with-extra-keywords.
+If the arglist is not available, return :NOT-AVAILABLE."))
+
+(defmethod compute-enriched-decoded-arglist (operator-form argument-forms)
+ (let ((arglist (arglist operator-form)))
+ (etypecase arglist
+ ((member :not-available)
+ :not-available)
+ (list
+ (let ((decoded-arglist (decode-arglist arglist)))
+ (enrich-decoded-arglist-with-extra-keywords decoded-arglist
+ (cons operator-form
+ argument-forms)))))))
+
+(defmethod compute-enriched-decoded-arglist ((operator-form (eql 'with-open-file))
+ argument-forms)
+ (declare (ignore argument-forms))
+ (multiple-value-bind (decoded-arglist determining-args)
+ (call-next-method)
+ (let ((first-arg (first (arglist.required-args decoded-arglist)))
+ (open-arglist (compute-enriched-decoded-arglist 'open nil)))
+ (when (and (arglist-p first-arg) (arglist-p open-arglist))
+ (enrich-decoded-arglist-with-keywords
+ first-arg
+ (arglist.keyword-args open-arglist)
+ nil)))
+ (values decoded-arglist determining-args t)))
+
+(defmethod compute-enriched-decoded-arglist ((operator-form (eql 'apply))
+ argument-forms)
+ (let ((function-name-form (car argument-forms)))
+ (when (and (listp function-name-form)
+ (length= function-name-form 2)
+ (member (car function-name-form) '(quote function)))
+ (let ((function-name (cadr function-name-form)))
+ (when (valid-operator-symbol-p function-name)
+ (let ((function-arglist
+ (compute-enriched-decoded-arglist function-name
+ (cdr argument-forms))))
+ (return-from compute-enriched-decoded-arglist
+ (values (make-arglist :required-args
+ (list 'function)
+ :optional-args
+ (append
+ (mapcar #'(lambda (arg)
+ (make-optional-arg arg nil))
+ (arglist.required-args function-arglist))
+ (arglist.optional-args function-arglist))
+ :key-p
+ (arglist.key-p function-arglist)
+ :keyword-args
+ (arglist.keyword-args function-arglist)
+ :rest
+ 'args
+ :allow-other-keys-p
+ (arglist.allow-other-keys-p function-arglist))
+ (list function-name-form)
+ t)))))))
+ (call-next-method))
+
+(defvar *remove-keywords-alist*
+ '((:test :test-not)
+ (:test-not :test)))
+
+(defun remove-actual-args (decoded-arglist actual-arglist)
+ "Remove from DECODED-ARGLIST the arguments that have already been
+provided in ACTUAL-ARGLIST."
+ (assert (or (and (not (arglist.key-p decoded-arglist))
+ (not (arglist.any-p decoded-arglist)))
+ (exactly-one-p (arglist.key-p decoded-arglist)
+ (arglist.any-p decoded-arglist))))
+ (loop while (and actual-arglist
+ (arglist.required-args decoded-arglist))
+ do (progn (pop actual-arglist)
+ (pop (arglist.required-args decoded-arglist))))
+ (loop while (and actual-arglist
+ (arglist.optional-args decoded-arglist))
+ do (progn (pop actual-arglist)
+ (pop (arglist.optional-args decoded-arglist))))
+ (if (arglist.any-p decoded-arglist)
+ (remove-&any-args decoded-arglist actual-arglist)
+ (remove-&key-args decoded-arglist actual-arglist))
+ decoded-arglist)
+
+(defun remove-&key-args (decoded-arglist key-args)
+ (loop for keyword in key-args by #'cddr
+ for keywords-to-remove = (cdr (assoc keyword *remove-keywords-alist*))
+ do (setf (arglist.keyword-args decoded-arglist)
+ (remove-if (lambda (kw)
+ (or (eql kw keyword)
+ (member kw keywords-to-remove)))
+ (arglist.keyword-args decoded-arglist)
+ :key #'keyword-arg.keyword))) )
+
+(defun remove-&any-args (decoded-arglist any-args)
+ (setf (arglist.any-args decoded-arglist)
+ (remove-if #'(lambda (x) (member x any-args))
+ (arglist.any-args decoded-arglist)
+ :key #'(lambda (x) (first (ensure-list x))))))
+
+
+(defun arglist-from-form-spec (form-spec &key (remove-args t))
+ "Returns the decoded arglist that corresponds to FORM-SPEC. If
+REMOVE-ARGS is T, the arguments that are contained in FORM-SPEC
+are removed from the result arglist.
+
+Examples:
+
+ (arglist-from-form-spec '(defun))
+
+ ~=> (name args &body body)
+
+ (arglist-from-form-spec '(defun foo))
+
+ ~=> (args &body body)
+
+ (arglist-from-form-spec '(defun foo) :remove-args nil))
+
+ ~=> (name args &body body))
+
+ (arglist-from-form-spec '((:type-specifier float) 42) :remove-args nil)
+
+ ~=> (&optional lower-limit upper-limit)
+"
+ (if (null form-spec)
+ :not-available
+ (multiple-value-bind (type operator arguments)
+ (split-form-spec form-spec)
+ (arglist-dispatch type operator arguments :remove-args remove-args))))
+
+(defmacro with-availability ((var) form &body body)
+ `(let ((,var ,form))
+ (if (eql ,var :not-available)
+ :not-available
+ (progn , at body))))
+
+(defgeneric arglist-dispatch (operator-type operator arguments &key remove-args))
+
+(defmethod arglist-dispatch (operator-type operator arguments &key (remove-args t))
+ (when (and (symbolp operator)
+ (valid-operator-symbol-p operator))
+ (multiple-value-bind (decoded-arglist determining-args any-enrichment)
+ (compute-enriched-decoded-arglist operator arguments)
+ (etypecase decoded-arglist
+ ((member :not-available)
+ :not-available)
+ (arglist
+ (cond
+ (remove-args
+ ;; get rid of formal args already provided
+ (remove-actual-args decoded-arglist arguments))
+ (t
+ ;; replace some formal args by determining actual args
+ (remove-actual-args decoded-arglist determining-args)
+ (setf (arglist.provided-args decoded-arglist)
+ determining-args)))
+ (return-from arglist-dispatch
+ (values decoded-arglist any-enrichment))))))
+ :not-available)
+
+(defmethod arglist-dispatch ((operator-type (eql :function)) (operator (eql 'defmethod))
+ arguments &key (remove-args t))
+ (when (and (listp arguments)
+ (not (null arguments)) ;have generic function name
+ (notany #'listp (rest arguments))) ;don't have arglist yet
+ (let* ((gf-name (first arguments))
+ (gf (and (valid-function-name-p gf-name)
+ (fboundp gf-name)
+ (fdefinition gf-name))))
+ (when (typep gf 'generic-function)
+ (with-availability (arglist) (arglist gf)
+ (return-from arglist-dispatch
+ (values (make-arglist :provided-args (if remove-args
+ nil
+ (list gf-name))
+ :required-args (list arglist)
+ :rest "body" :body-p t)
+ t))))))
+ (call-next-method))
+
+(defmethod arglist-dispatch ((operator-type (eql :function)) (operator (eql 'eval-when))
+ arguments &key (remove-args t))
+ (let ((eval-when-args '(:compile-toplevel :load-toplevel :execute)))
+ (make-arglist :required-args (list (maybecall remove-args #'remove-actual-args
+ (make-arglist :any-args eval-when-args)
+ arguments))
+ :rest '#:body :body-p t)))
+
+(defmethod arglist-dispatch ((operator-type (eql :function)) (operator (eql 'declare))
+ arguments &key (remove-args t))
+ ;; Catching 'DECLARE before SWANK-BACKEND:ARGLIST can barf.
+ (declare (ignore remove-args))
+ (make-arglist :rest '#:decl-specifiers))
+
+(defmethod arglist-dispatch ((operator-type (eql :declaration))
+ decl-identifier decl-args &key (remove-args t))
+ (with-availability (arglist)
+ (declaration-arglist decl-identifier)
+ (maybecall remove-args #'remove-actual-args
+ (decode-arglist arglist) decl-args))
+ ;; We don't fall back to CALL-NEXT-METHOD because we're within a
+ ;; different namespace!
+ )
+
+(defmethod arglist-dispatch ((operator-type (eql :type-specifier))
+ type-specifier specifier-args &key (remove-args t))
+ (with-availability (arglist)
+ (type-specifier-arglist type-specifier)
+ (maybecall remove-args #'remove-actual-args
+ (decode-arglist arglist) specifier-args))
+ ;; No CALL-NEXT-METHOD, see above.
+ )
+
+
+(defun read-incomplete-form-from-string (form-string)
+ (with-buffer-syntax ()
+ (call-with-ignored-reader-errors
+ #'(lambda ()
+ (read-from-string form-string)))))
+
+(defun call-with-ignored-reader-errors (thunk)
+ (declare (type (function () (values &rest t)) thunk))
+ (declare (optimize (speed 3) (safety 1)))
+ (handler-case (funcall thunk)
+ (reader-error (c)
+ (declare (ignore c))
+ nil)
+ (stream-error (c)
+ (declare (ignore c))
+ nil)))
+
+(defslimefun complete-form (form-string)
+ "Read FORM-STRING in the current buffer package, then complete it
+by adding a template for the missing arguments."
+ (multiple-value-bind (form newly-interned-symbols)
+ (parse-form-spec form-string)
+ (unwind-protect
+ (when (consp form)
+ (let ((form-completion (arglist-from-form-spec form)))
+ (unless (eql form-completion :not-available)
+ (return-from complete-form
+ (decoded-arglist-to-template-string form-completion
+ *buffer-package*
+ :prefix "")))))
+ (mapc #'unintern-in-home-package newly-interned-symbols))
+ :not-available))
+
+
+(defun arglist-ref (decoded-arglist operator &rest indices)
+ (cond
+ ((null indices) decoded-arglist)
+ ((not (arglist-p decoded-arglist)) nil)
+ (t
+ (let ((index (first indices))
+ (args (append (and operator
+ (list operator))
+ (arglist.required-args decoded-arglist)
+ (arglist.optional-args decoded-arglist))))
+ (when (< index (length args))
+ (let ((arg (elt args index)))
+ (apply #'arglist-ref arg nil (rest indices))))))))
+
+(defslimefun completions-for-keyword (raw-specs keyword-string arg-index-specs)
+ (with-buffer-syntax ()
+ (multiple-value-bind (form-spec position newly-interned-symbols)
+ (parse-first-valid-form-spec raw-specs)
+ (unwind-protect
+ (when form-spec
+ (let ((arglist (arglist-from-form-spec form-spec :remove-args nil)))
+ (unless (eql arglist :not-available)
+ (let* ((operator (nth-value 1 (split-form-spec form-spec)))
+ (indices (reverse (rest (subseq arg-index-specs 0 (1+ position)))))
+ (arglist (apply #'arglist-ref arglist operator indices)))
+ (when (and arglist (arglist-p arglist))
+ ;; It would be possible to complete keywords only if we
+ ;; are in a keyword position, but it is not clear if we
+ ;; want that.
+ (let* ((keywords
+ (append (mapcar #'keyword-arg.keyword
+ (arglist.keyword-args arglist))
+ (remove-if-not #'keywordp (arglist.any-args arglist))))
+ (keyword-name
+ (tokenize-symbol keyword-string))
+ (matching-keywords
+ (find-matching-symbols-in-list keyword-name keywords
+ #'compound-prefix-match))
+ (converter (completion-output-symbol-converter keyword-string))
+ (strings
+ (mapcar converter
+ (mapcar #'symbol-name matching-keywords)))
+ (completion-set
+ (format-completion-set strings nil "")))
+ (list completion-set
+ (longest-compound-prefix completion-set))))))))
+ (mapc #'unintern-in-home-package newly-interned-symbols)))))
+
+
+(defun arglist-to-string (arglist package &key print-right-margin highlight)
+ (decoded-arglist-to-string (decode-arglist arglist)
+ :package package
+ :print-right-margin print-right-margin
+ :highlight highlight))
+
+(defun test-print-arglist ()
+ (flet ((test (list string)
+ (let* ((p (find-package :swank))
+ (actual (arglist-to-string list p)))
+ (unless (string= actual string)
+ (warn "Test failed: ~S => ~S~% Expected: ~S"
+ list actual string)))))
+ (test '(function cons) "(function cons)")
+ (test '(quote cons) "(quote cons)")
+ (test '(&key (function #'+)) "(&key (function #'+))")
+ (test '(&whole x y z) "(y z)")
+ (test '(x &aux y z) "(x)")
+ (test '(x &environment env y) "(x y)")
+ (test '(&key ((function f))) "(&key ((function f)))")
+ (test '(eval-when (&any :compile-toplevel :load-toplevel :execute) &body body)
+ "(eval-when (&any :compile-toplevel :load-toplevel :execute) &body body)")
+ (test '(declare (optimize &any (speed 1) (safety 1)))
+ "(declare (optimize &any (speed 1) (safety 1)))")
+ ))
+
+(test-print-arglist)
+
+(provide :swank-arglists)
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-asdf.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-asdf.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,63 @@
+;;; swank-asdf.el -- ASDF support
+;;
+;; Authors: Daniel Barlow <dan at telent.net>
+;; Marco Baringer <mb at bese.it>
+;; Edi Weitz <edi at agharta.de>
+;; and others
+;; License: Public Domain
+;;
+
+(in-package :swank)
+
+(defslimefun operate-on-system-for-emacs (system-name operation &rest keywords)
+ "Compile and load SYSTEM using ASDF.
+Record compiler notes signalled as `compiler-condition's."
+ (swank-compiler
+ (lambda ()
+ (apply #'operate-on-system system-name operation keywords))))
+
+(defun operate-on-system (system-name operation-name &rest keyword-args)
+ "Perform OPERATION-NAME on SYSTEM-NAME using ASDF.
+The KEYWORD-ARGS are passed on to the operation.
+Example:
+\(operate-on-system \"SWANK\" \"COMPILE-OP\" :force t)"
+ (with-compilation-hooks ()
+ (let ((operation (find-symbol operation-name :asdf)))
+ (when (null operation)
+ (error "Couldn't find ASDF operation ~S" operation-name))
+ (apply #'asdf:operate operation system-name keyword-args))))
+
+(defun asdf-central-registry ()
+ asdf:*central-registry*)
+
+(defslimefun list-all-systems-in-central-registry ()
+ "Returns a list of all systems in ASDF's central registry."
+ (mapcar #'pathname-name
+ (delete-duplicates
+ (loop for dir in (asdf-central-registry)
+ for defaults = (eval dir)
+ when defaults
+ nconc (mapcar #'file-namestring
+ (directory
+ (make-pathname :defaults defaults
+ :version :newest
+ :type "asd"
+ :name :wild
+ :case :local))))
+ :test #'string=)))
+
+(defslimefun list-all-systems-known-to-asdf ()
+ "Returns a list of all systems ASDF knows already."
+ ;; ugh, yeah, it's unexported - but do we really expect this to
+ ;; change anytime soon?
+ (loop for name being the hash-keys of asdf::*defined-systems*
+ collect name))
+
+(defslimefun list-asdf-systems ()
+ "Returns the systems in ASDF's central registry and those which ASDF
+already knows."
+ (nunion (list-all-systems-known-to-asdf)
+ (list-all-systems-in-central-registry)
+ :test #'string=))
+
+(provide :swank-asdf)
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-c-p-c.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-c-p-c.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,279 @@
+;;; swank-c-p-c.lisp -- ILISP style Compound Prefix Completion
+;;
+;; Author: Luke Gorrie <luke at synap.se>
+;; Edi Weitz <edi at agharta.de>
+;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: Public Domain
+;;
+
+
+(in-package :swank)
+
+(defslimefun completions (string default-package-name)
+ "Return a list of completions for a symbol designator STRING.
+
+The result is the list (COMPLETION-SET COMPLETED-PREFIX), where
+COMPLETION-SET is the list of all matching completions, and
+COMPLETED-PREFIX is the best (partial) completion of the input
+string.
+
+Simple compound matching is supported on a per-hyphen basis:
+
+ (completions \"m-v-\" \"COMMON-LISP\")
+ ==> ((\"multiple-value-bind\" \"multiple-value-call\"
+ \"multiple-value-list\" \"multiple-value-prog1\"
+ \"multiple-value-setq\" \"multiple-values-limit\")
+ \"multiple-value\")
+
+\(For more advanced compound matching, see FUZZY-COMPLETIONS.)
+
+If STRING is package qualified the result list will also be
+qualified. If string is non-qualified the result strings are
+also not qualified and are considered relative to
+DEFAULT-PACKAGE-NAME.
+
+The way symbols are matched depends on the symbol designator's
+format. The cases are as follows:
+ FOO - Symbols with matching prefix and accessible in the buffer package.
+ PKG:FOO - Symbols with matching prefix and external in package PKG.
+ PKG::FOO - Symbols with matching prefix and accessible in package PKG.
+"
+ (let ((completion-set (completion-set string default-package-name
+ #'compound-prefix-match)))
+ (when completion-set
+ (list completion-set (longest-compound-prefix completion-set)))))
+
+;;;;; Find completion set
+
+(defun completion-set (string default-package-name matchp)
+ "Return the set of completion-candidates as strings."
+ (multiple-value-bind (name package-name package internal-p)
+ (parse-completion-arguments string default-package-name)
+ (let* ((symbols (mapcar (completion-output-symbol-converter name)
+ (and package
+ (mapcar #'symbol-name
+ (find-matching-symbols name
+ package
+ (and (not internal-p)
+ package-name)
+ matchp)))))
+ (packs (mapcar (completion-output-package-converter name)
+ (and (not package-name)
+ (find-matching-packages name matchp)))))
+ (format-completion-set (nconc symbols packs) internal-p package-name))))
+
+(defun find-matching-symbols (string package external test)
+ "Return a list of symbols in PACKAGE matching STRING.
+TEST is called with two strings. If EXTERNAL is true, only external
+symbols are returned."
+ (let ((completions '())
+ (converter (completion-output-symbol-converter string)))
+ (flet ((symbol-matches-p (symbol)
+ (and (or (not external)
+ (symbol-external-p symbol package))
+ (funcall test string
+ (funcall converter (symbol-name symbol))))))
+ (do-symbols* (symbol package)
+ (when (symbol-matches-p symbol)
+ (push symbol completions))))
+ completions))
+
+(defun find-matching-symbols-in-list (string list test)
+ "Return a list of symbols in LIST matching STRING.
+TEST is called with two strings."
+ (let ((completions '())
+ (converter (completion-output-symbol-converter string)))
+ (flet ((symbol-matches-p (symbol)
+ (funcall test string
+ (funcall converter (symbol-name symbol)))))
+ (dolist (symbol list)
+ (when (symbol-matches-p symbol)
+ (push symbol completions))))
+ (remove-duplicates completions)))
+
+(defun find-matching-packages (name matcher)
+ "Return a list of package names matching NAME with MATCHER.
+MATCHER is a two-argument predicate."
+ (let ((to-match (string-upcase name)))
+ (remove-if-not (lambda (x) (funcall matcher to-match x))
+ (mapcar (lambda (pkgname)
+ (concatenate 'string pkgname ":"))
+ (loop for package in (list-all-packages)
+ collect (package-name package)
+ append (package-nicknames package))))))
+
+
+;; PARSE-COMPLETION-ARGUMENTS return table:
+;;
+;; user behaviour | NAME | PACKAGE-NAME | PACKAGE
+;; ----------------+--------+--------------+-----------------------------------
+;; asdf [tab] | "asdf" | NIL | #<PACKAGE "DEFAULT-PACKAGE-NAME">
+;; | | | or *BUFFER-PACKAGE*
+;; asdf: [tab] | "" | "asdf" | #<PACKAGE "ASDF">
+;; | | |
+;; asdf:foo [tab] | "foo" | "asdf" | #<PACKAGE "ASDF">
+;; | | |
+;; as:fo [tab] | "fo" | "as" | NIL
+;; | | |
+;; : [tab] | "" | "" | #<PACKAGE "KEYWORD">
+;; | | |
+;; :foo [tab] | "foo" | "" | #<PACKAGE "KEYWORD">
+;;
+(defun parse-completion-arguments (string default-package-name)
+ "Parse STRING as a symbol designator.
+Return these values:
+ SYMBOL-NAME
+ PACKAGE-NAME, or nil if the designator does not include an explicit package.
+ PACKAGE, generally the package to complete in. (However, if PACKAGE-NAME is
+ NIL, return the respective package of DEFAULT-PACKAGE-NAME instead;
+ if PACKAGE is non-NIL but a package cannot be found under that name,
+ return NIL.)
+ INTERNAL-P, if the symbol is qualified with `::'."
+ (multiple-value-bind (name package-name internal-p)
+ (tokenize-symbol string)
+ (if package-name
+ (let ((package (guess-package (if (equal package-name "")
+ "KEYWORD"
+ package-name))))
+ (values name package-name package internal-p))
+ (let ((package (guess-package default-package-name)))
+ (values name package-name (or package *buffer-package*) internal-p))
+ )))
+
+
+
+(defun completion-output-case-converter (input &optional with-escaping-p)
+ "Return a function to convert strings for the completion output.
+INPUT is used to guess the preferred case."
+ (ecase (readtable-case *readtable*)
+ (:upcase (cond ((or with-escaping-p
+ (not (some #'lower-case-p input)))
+ #'identity)
+ (t #'string-downcase)))
+ (:invert (lambda (output)
+ (multiple-value-bind (lower upper) (determine-case output)
+ (cond ((and lower upper) output)
+ (lower (string-upcase output))
+ (upper (string-downcase output))
+ (t output)))))
+ (:downcase (cond ((or with-escaping-p
+ (not (some #'upper-case-p input)))
+ #'identity)
+ (t #'string-upcase)))
+ (:preserve #'identity)))
+
+(defun completion-output-package-converter (input)
+ "Return a function to convert strings for the completion output.
+INPUT is used to guess the preferred case."
+ (completion-output-case-converter input))
+
+(defun completion-output-symbol-converter (input)
+ "Return a function to convert strings for the completion output.
+INPUT is used to guess the preferred case. Escape symbols when needed."
+ (let ((case-converter (completion-output-case-converter input))
+ (case-converter-with-escaping (completion-output-case-converter input t)))
+ (lambda (str)
+ (if (or (multiple-value-bind (lowercase uppercase)
+ (determine-case str)
+ ;; In these readtable cases, symbols with letters from
+ ;; the wrong case need escaping
+ (case (readtable-case *readtable*)
+ (:upcase lowercase)
+ (:downcase uppercase)
+ (t nil)))
+ (some (lambda (el)
+ (or (member el '(#\: #\Space #\Newline #\Tab))
+ (multiple-value-bind (macrofun nonterminating)
+ (get-macro-character el)
+ (and macrofun
+ (not nonterminating)))))
+ str))
+ (concatenate 'string "|" (funcall case-converter-with-escaping str) "|")
+ (funcall case-converter str)))))
+
+
+(defun determine-case (string)
+ "Return two booleans LOWER and UPPER indicating whether STRING
+contains lower or upper case characters."
+ (values (some #'lower-case-p string)
+ (some #'upper-case-p string)))
+
+
+;;;;; Compound-prefix matching
+
+(defun make-compound-prefix-matcher (delimeter &key (test #'char=))
+ "Returns a matching function that takes a `prefix' and a
+`target' string and which returns T if `prefix' is a
+compound-prefix of `target', and otherwise NIL.
+
+Viewing each of `prefix' and `target' as a series of substrings
+delimited by DELIMETER, if each substring of `prefix' is a prefix
+of the corresponding substring in `target' then we call `prefix'
+a compound-prefix of `target'."
+ (lambda (prefix target)
+ (declare (type simple-string prefix target))
+ (loop for ch across prefix
+ with tpos = 0
+ always (and (< tpos (length target))
+ (if (char= ch delimeter)
+ (setf tpos (position #\- target :start tpos))
+ (funcall test ch (aref target tpos))))
+ do (incf tpos))))
+
+(defun compound-prefix-match (prefix target)
+ "Examples:
+\(compound-prefix-match \"foo\" \"foobar\") => t
+\(compound-prefix-match \"m--b\" \"multiple-value-bind\") => t
+\(compound-prefix-match \"m-v-c\" \"multiple-value-bind\") => NIL
+"
+ (funcall (make-compound-prefix-matcher #\-) prefix target))
+
+
+;;;;; Extending the input string by completion
+
+(defun longest-compound-prefix (completions &optional (delimeter #\-))
+ "Return the longest compound _prefix_ for all COMPLETIONS."
+ (flet ((tokenizer (string) (tokenize-completion string delimeter)))
+ (untokenize-completion
+ (loop for token-list in (transpose-lists (mapcar #'tokenizer completions))
+ if (notevery #'string= token-list (rest token-list))
+ collect (longest-common-prefix token-list) ; Note that we possibly collect
+ and do (loop-finish) ; the "" here as well, so that
+ else collect (first token-list))))) ; UNTOKENIZE-COMPLETION will
+ ; append a hyphen for us.
+(defun tokenize-completion (string delimeter)
+ "Return all substrings of STRING delimited by DELIMETER."
+ (loop with end
+ for start = 0 then (1+ end)
+ until (> start (length string))
+ do (setq end (or (position delimeter string :start start) (length string)))
+ collect (subseq string start end)))
+
+(defun untokenize-completion (tokens)
+ (format nil "~{~A~^-~}" tokens))
+
+(defun transpose-lists (lists)
+ "Turn a list-of-lists on its side.
+If the rows are of unequal length, truncate uniformly to the shortest.
+
+For example:
+\(transpose-lists '((ONE TWO THREE) (1 2)))
+ => ((ONE 1) (TWO 2))"
+ (cond ((null lists) '())
+ ((some #'null lists) '())
+ (t (cons (mapcar #'car lists)
+ (transpose-lists (mapcar #'cdr lists))))))
+
+
+;;;; Completion for character names
+
+(defslimefun completions-for-character (prefix)
+ (let* ((matcher (make-compound-prefix-matcher #\_ :test #'char-equal))
+ (completion-set (character-completion-set prefix matcher))
+ (completions (sort completion-set #'string<)))
+ (list completions (longest-compound-prefix completions #\_))))
+
+(provide :swank-c-p-c)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-fancy-inspector.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-fancy-inspector.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,737 @@
+;;; swank-fancy-inspector.lisp --- Fancy inspector for CLOS objects
+;;
+;; Author: Marco Baringer <mb at bese.it> and others
+;; License: Public Domain
+;;
+
+(in-package :swank)
+
+;; Subclass `backend-inspector' so that backend specific methods are
+;; also considered.
+(defclass fancy-inspector (backend-inspector) ())
+
+(defmethod inspect-for-emacs ((symbol symbol) (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (let ((package (symbol-package symbol)))
+ (multiple-value-bind (_symbol status)
+ (and package (find-symbol (string symbol) package))
+ (declare (ignore _symbol))
+ (values
+ "A symbol."
+ (append
+ (label-value-line "Its name is" (symbol-name symbol))
+ ;;
+ ;; Value
+ (cond ((boundp symbol)
+ (label-value-line (if (constantp symbol)
+ "It is a constant of value"
+ "It is a global variable bound to")
+ (symbol-value symbol)))
+ (t '("It is unbound." (:newline))))
+ (docstring-ispec "Documentation" symbol 'variable)
+ (multiple-value-bind (expansion definedp) (macroexpand symbol)
+ (if definedp
+ (label-value-line "It is a symbol macro with expansion"
+ expansion)))
+ ;;
+ ;; Function
+ (if (fboundp symbol)
+ (append (if (macro-function symbol)
+ `("It a macro with macro-function: "
+ (:value ,(macro-function symbol)))
+ `("It is a function: "
+ (:value ,(symbol-function symbol))))
+ `(" " (:action "[make funbound]"
+ ,(lambda () (fmakunbound symbol))))
+ `((:newline)))
+ `("It has no function value." (:newline)))
+ (docstring-ispec "Function Documentation" symbol 'function)
+ (if (compiler-macro-function symbol)
+ (label-value-line "It also names the compiler macro"
+ (compiler-macro-function symbol)))
+ (docstring-ispec "Compiler Macro Documentation"
+ symbol 'compiler-macro)
+ ;;
+ ;; Package
+ (if package
+ `("It is " ,(string-downcase (string status))
+ " to the package: "
+ (:value ,package ,(package-name package))
+ ,@(if (eq :internal status)
+ `(" "
+ (:action "[export it]"
+ ,(lambda () (export symbol package)))))
+ " "
+ (:action "[unintern it]"
+ ,(lambda () (unintern symbol package)))
+ (:newline))
+ '("It is a non-interned symbol." (:newline)))
+ ;;
+ ;; Plist
+ (label-value-line "Property list" (symbol-plist symbol))
+ ;;
+ ;; Class
+ (if (find-class symbol nil)
+ `("It names the class "
+ (:value ,(find-class symbol) ,(string symbol))
+ " "
+ (:action "[remove]"
+ ,(lambda () (setf (find-class symbol) nil)))
+ (:newline)))
+ ;;
+ ;; More package
+ (if (find-package symbol)
+ (label-value-line "It names the package" (find-package symbol)))
+ )))))
+
+(defun docstring-ispec (label object kind)
+ "Return a inspector spec if OBJECT has a docstring of of kind KIND."
+ (let ((docstring (documentation object kind)))
+ (cond ((not docstring) nil)
+ ((< (+ (length label) (length docstring))
+ 75)
+ (list label ": " docstring '(:newline)))
+ (t
+ (list label ": " '(:newline) " " docstring '(:newline))))))
+
+(defmethod inspect-for-emacs ((f function) inspector)
+ (declare (ignore inspector))
+ (values "A function."
+ (append
+ (label-value-line "Name" (function-name f))
+ `("Its argument list is: "
+ ,(inspector-princ (arglist f)) (:newline))
+ (docstring-ispec "Documentation" f t)
+ (if (function-lambda-expression f)
+ (label-value-line "Lambda Expression"
+ (function-lambda-expression f))))))
+
+(defun method-specializers-for-inspect (method)
+ "Return a \"pretty\" list of the method's specializers. Normal
+ specializers are replaced by the name of the class, eql
+ specializers are replaced by `(eql ,object)."
+ (mapcar (lambda (spec)
+ (typecase spec
+ (swank-mop:eql-specializer
+ `(eql ,(swank-mop:eql-specializer-object spec)))
+ (t (swank-mop:class-name spec))))
+ (swank-mop:method-specializers method)))
+
+(defun method-for-inspect-value (method)
+ "Returns a \"pretty\" list describing METHOD. The first element
+ of the list is the name of generic-function method is
+ specialiazed on, the second element is the method qualifiers,
+ the rest of the list is the method's specialiazers (as per
+ method-specializers-for-inspect)."
+ (append (list (swank-mop:generic-function-name
+ (swank-mop:method-generic-function method)))
+ (swank-mop:method-qualifiers method)
+ (method-specializers-for-inspect method)))
+
+(defmethod inspect-for-emacs ((object standard-object)
+ (inspector fancy-inspector))
+ (let ((class (class-of object)))
+ (values "An object."
+ `("Class: " (:value ,class) (:newline)
+ ,@(all-slots-for-inspector object inspector)))))
+
+(defvar *gf-method-getter* 'methods-by-applicability
+ "This function is called to get the methods of a generic function.
+The default returns the method sorted by applicability.
+See `methods-by-applicability'.")
+
+(defun specializer< (specializer1 specializer2)
+ "Return true if SPECIALIZER1 is more specific than SPECIALIZER2."
+ (let ((s1 specializer1) (s2 specializer2) )
+ (cond ((typep s1 'swank-mop:eql-specializer)
+ (not (typep s2 'swank-mop:eql-specializer)))
+ (t
+ (flet ((cpl (class)
+ (and (swank-mop:class-finalized-p class)
+ (swank-mop:class-precedence-list class))))
+ (member s2 (cpl s1)))))))
+
+(defun methods-by-applicability (gf)
+ "Return methods ordered by most specific argument types.
+
+`method-specializer<' is used for sorting."
+ ;; FIXME: argument-precedence-order and qualifiers are ignored.
+ (labels ((method< (meth1 meth2)
+ (loop for s1 in (swank-mop:method-specializers meth1)
+ for s2 in (swank-mop:method-specializers meth2)
+ do (cond ((specializer< s2 s1) (return nil))
+ ((specializer< s1 s2) (return t))))))
+ (stable-sort (copy-seq (swank-mop:generic-function-methods gf)) #'method<)))
+
+(defun abbrev-doc (doc &optional (maxlen 80))
+ "Return the first sentence of DOC, but not more than MAXLAN characters."
+ (subseq doc 0 (min (1+ (or (position #\. doc) (1- maxlen)))
+ maxlen
+ (length doc))))
+
+(defgeneric inspect-slot-for-emacs (class object slot)
+ (:method (class object slot)
+ (let ((slot-name (swank-mop:slot-definition-name slot))
+ (boundp (swank-mop:slot-boundp-using-class class object slot)))
+ `(,@(if boundp
+ `((:value ,(swank-mop:slot-value-using-class class object slot)))
+ `("#<unbound>"))
+ " "
+ (:action "[set value]"
+ ,(lambda () (with-simple-restart
+ (abort "Abort setting slot ~S" slot-name)
+ (let ((value-string (eval-in-emacs
+ `(condition-case c
+ (slime-read-object
+ ,(format nil "Set slot ~S to (evaluated) : " slot-name))
+ (quit nil)))))
+ (when (and value-string
+ (not (string= value-string "")))
+ (setf (swank-mop:slot-value-using-class class object slot)
+ (eval (read-from-string value-string))))))))
+ ,@(when boundp
+ `(" " (:action "[make unbound]"
+ ,(lambda () (swank-mop:slot-makunbound-using-class class object slot)))))))))
+
+(defgeneric all-slots-for-inspector (object inspector)
+ (:method ((object standard-object) inspector)
+ (declare (ignore inspector))
+ (append '("--------------------" (:newline)
+ "All Slots:" (:newline))
+ (let* ((class (class-of object))
+ (direct-slots (swank-mop:class-direct-slots class))
+ (effective-slots (sort (copy-seq (swank-mop:class-slots class))
+ #'string< :key #'swank-mop:slot-definition-name))
+ (slot-presentations (loop for effective-slot :in effective-slots
+ collect (inspect-slot-for-emacs
+ class object effective-slot)))
+ (longest-slot-name-length
+ (loop for slot :in effective-slots
+ maximize (length (symbol-name
+ (swank-mop:slot-definition-name slot))))))
+ (loop
+ for effective-slot :in effective-slots
+ for slot-presentation :in slot-presentations
+ for direct-slot = (find (swank-mop:slot-definition-name effective-slot)
+ direct-slots :key #'swank-mop:slot-definition-name)
+ for slot-name = (inspector-princ
+ (swank-mop:slot-definition-name effective-slot))
+ for padding-length = (- longest-slot-name-length
+ (length (symbol-name
+ (swank-mop:slot-definition-name
+ effective-slot))))
+ collect `(:value ,(if direct-slot
+ (list direct-slot effective-slot)
+ effective-slot)
+ ,slot-name)
+ collect (make-array padding-length
+ :element-type 'character
+ :initial-element #\Space)
+ collect " = "
+ append slot-presentation
+ collect '(:newline))))))
+
+(defmethod inspect-for-emacs ((gf standard-generic-function)
+ (inspector fancy-inspector))
+ (flet ((lv (label value) (label-value-line label value)))
+ (values
+ "A generic function."
+ (append
+ (lv "Name" (swank-mop:generic-function-name gf))
+ (lv "Arguments" (swank-mop:generic-function-lambda-list gf))
+ (docstring-ispec "Documentation" gf t)
+ (lv "Method class" (swank-mop:generic-function-method-class gf))
+ (lv "Method combination"
+ (swank-mop:generic-function-method-combination gf))
+ `("Methods: " (:newline))
+ (loop for method in (funcall *gf-method-getter* gf) append
+ `((:value ,method ,(inspector-princ
+ ;; drop the name of the GF
+ (cdr (method-for-inspect-value method))))
+ " "
+ (:action "[remove method]"
+ ,(let ((m method)) ; LOOP reassigns method
+ (lambda ()
+ (remove-method gf m))))
+ (:newline)))
+ `((:newline))
+ (all-slots-for-inspector gf inspector)))))
+
+(defmethod inspect-for-emacs ((method standard-method)
+ (inspector fancy-inspector))
+ (values "A method."
+ `("Method defined on the generic function "
+ (:value ,(swank-mop:method-generic-function method)
+ ,(inspector-princ
+ (swank-mop:generic-function-name
+ (swank-mop:method-generic-function method))))
+ (:newline)
+ ,@(docstring-ispec "Documentation" method t)
+ "Lambda List: " (:value ,(swank-mop:method-lambda-list method))
+ (:newline)
+ "Specializers: " (:value ,(swank-mop:method-specializers method)
+ ,(inspector-princ (method-specializers-for-inspect method)))
+ (:newline)
+ "Qualifiers: " (:value ,(swank-mop:method-qualifiers method))
+ (:newline)
+ "Method function: " (:value ,(swank-mop:method-function method))
+ (:newline)
+ ,@(all-slots-for-inspector method inspector))))
+
+(defmethod inspect-for-emacs ((class standard-class)
+ (inspector fancy-inspector))
+ (values "A class."
+ `("Name: " (:value ,(class-name class))
+ (:newline)
+ "Super classes: "
+ ,@(common-seperated-spec (swank-mop:class-direct-superclasses class))
+ (:newline)
+ "Direct Slots: "
+ ,@(common-seperated-spec
+ (swank-mop:class-direct-slots class)
+ (lambda (slot)
+ `(:value ,slot ,(inspector-princ (swank-mop:slot-definition-name slot)))))
+ (:newline)
+ "Effective Slots: "
+ ,@(if (swank-mop:class-finalized-p class)
+ (common-seperated-spec
+ (swank-mop:class-slots class)
+ (lambda (slot)
+ `(:value ,slot ,(inspector-princ
+ (swank-mop:slot-definition-name slot)))))
+ '("#<N/A (class not finalized)>"))
+ (:newline)
+ ,@(let ((doc (documentation class t)))
+ (when doc
+ `("Documentation:" (:newline) ,(inspector-princ doc) (:newline))))
+ "Sub classes: "
+ ,@(common-seperated-spec (swank-mop:class-direct-subclasses class)
+ (lambda (sub)
+ `(:value ,sub ,(inspector-princ (class-name sub)))))
+ (:newline)
+ "Precedence List: "
+ ,@(if (swank-mop:class-finalized-p class)
+ (common-seperated-spec (swank-mop:class-precedence-list class)
+ (lambda (class)
+ `(:value ,class ,(inspector-princ (class-name class)))))
+ '("#<N/A (class not finalized)>"))
+ (:newline)
+ ,@(when (swank-mop:specializer-direct-methods class)
+ `("It is used as a direct specializer in the following methods:" (:newline)
+ ,@(loop
+ for method in (sort (copy-seq (swank-mop:specializer-direct-methods class))
+ #'string< :key (lambda (x)
+ (symbol-name
+ (let ((name (swank-mop::generic-function-name
+ (swank-mop::method-generic-function x))))
+ (if (symbolp name) name (second name))))))
+ collect " "
+ collect `(:value ,method ,(inspector-princ (method-for-inspect-value method)))
+ collect '(:newline)
+ if (documentation method t)
+ collect " Documentation: " and
+ collect (abbrev-doc (documentation method t)) and
+ collect '(:newline))))
+ "Prototype: " ,(if (swank-mop:class-finalized-p class)
+ `(:value ,(swank-mop:class-prototype class))
+ '"#<N/A (class not finalized)>")
+ (:newline)
+ ,@(all-slots-for-inspector class inspector))))
+
+(defmethod inspect-for-emacs ((slot swank-mop:standard-slot-definition)
+ (inspector fancy-inspector))
+ (values "A slot."
+ `("Name: " (:value ,(swank-mop:slot-definition-name slot))
+ (:newline)
+ ,@(when (swank-mop:slot-definition-documentation slot)
+ `("Documentation:" (:newline)
+ (:value ,(swank-mop:slot-definition-documentation slot))
+ (:newline)))
+ "Init args: " (:value ,(swank-mop:slot-definition-initargs slot)) (:newline)
+ "Init form: " ,(if (swank-mop:slot-definition-initfunction slot)
+ `(:value ,(swank-mop:slot-definition-initform slot))
+ "#<unspecified>") (:newline)
+ "Init function: " (:value ,(swank-mop:slot-definition-initfunction slot))
+ (:newline)
+ ,@(all-slots-for-inspector slot inspector))))
+
+
+;; Wrapper structure over the list of symbols of a package that should
+;; be displayed with their respective classification flags. This is
+;; because we need a unique type to dispatch on in INSPECT-FOR-EMACS.
+;; Used by the Inspector for packages.
+(defstruct (%package-symbols-container (:conc-name %container.)
+ (:constructor %%make-package-symbols-container))
+ title ;; A string; the title of the inspector page in Emacs.
+ description ;; A list of renderable objects; used as description.
+ symbols ;; A list of symbols. Supposed to be sorted alphabetically.
+ grouping-kind ;; Either :SYMBOL or :CLASSIFICATION. Cf. MAKE-SYMBOLS-LISTING.
+ )
+
+(defun %make-package-symbols-container (&key title description symbols)
+ (%%make-package-symbols-container :title title :description description
+ :symbols symbols :grouping-kind :symbol))
+
+(defgeneric make-symbols-listing (grouping-kind symbols))
+
+(defmethod make-symbols-listing ((grouping-kind (eql :symbol)) symbols)
+ "Returns an object renderable by Emacs' inspector side that
+alphabetically lists all the symbols in SYMBOLS together with a
+concise string representation of what each symbol
+represents (cf. CLASSIFY-SYMBOL & Fuzzy Completion.)"
+ (let ((max-length (loop for s in symbols maximizing (length (symbol-name s))))
+ (distance 10)) ; empty distance between name and classification
+ (flet ((string-representations (symbol)
+ (let* ((name (symbol-name symbol))
+ (length (length name))
+ (padding (- max-length length))
+ (classification (classify-symbol symbol)))
+ (values
+ (concatenate 'string
+ name
+ (make-string (+ padding distance) :initial-element #\Space))
+ (symbol-classification->string classification)))))
+ `("" ; 8 is (length "Symbols:")
+ "Symbols:" ,(make-string (+ -8 max-length distance) :initial-element #\Space) "Flags:"
+ (:newline)
+ ,(concatenate 'string ; underlining dashes
+ (make-string (+ max-length distance -1) :initial-element #\-)
+ " "
+ (let* ((dummy (classify-symbol (gensym)))
+ (dummy (symbol-classification->string dummy))
+ (classification-length (length dummy)))
+ (make-string classification-length :initial-element #\-)))
+ (:newline)
+ ,@(loop for symbol in symbols appending
+ (multiple-value-bind (symbol-string classification-string)
+ (string-representations symbol)
+ `((:value ,symbol ,symbol-string) ,classification-string
+ (:newline)
+ )))))))
+
+(defmethod make-symbols-listing ((grouping-kind (eql :classification)) symbols)
+ "For each possible classification (cf. CLASSIFY-SYMBOL), group
+all the symbols in SYMBOLS to all of their respective
+classifications. (If a symbol is, for instance, boundp and a
+generic-function, it'll appear both below the BOUNDP group and
+the GENERIC-FUNCTION group.) As macros and special-operators are
+specified to be FBOUNDP, there is no general FBOUNDP group,
+instead there are the three explicit FUNCTION, MACRO and
+SPECIAL-OPERATOR groups."
+ (let ((table (make-hash-table :test #'eq)))
+ (flet ((maybe-convert-fboundps (classifications)
+ ;; Convert an :FBOUNDP in CLASSIFICATIONS to :FUNCTION if possible.
+ (if (and (member :fboundp classifications)
+ (not (member :macro classifications))
+ (not (member :special-operator classifications)))
+ (substitute :function :fboundp classifications)
+ (remove :fboundp classifications))))
+ (loop for symbol in symbols do
+ (loop for classification in (maybe-convert-fboundps (classify-symbol symbol))
+ ;; SYMBOLS are supposed to be sorted alphabetically;
+ ;; this property is preserved here except for reversing.
+ do (push symbol (gethash classification table)))))
+ (let* ((classifications (loop for k being each hash-key in table collect k))
+ (classifications (sort classifications #'string<)))
+ (loop for classification in classifications
+ for symbols = (gethash classification table)
+ appending`(,(symbol-name classification)
+ (:newline)
+ ,(make-string 64 :initial-element #\-)
+ (:newline)
+ ,@(mapcan #'(lambda (symbol)
+ (list `(:value ,symbol ,(symbol-name symbol)) '(:newline)))
+ (nreverse symbols)) ; restore alphabetic orderness.
+ (:newline)
+ )))))
+
+(defmethod inspect-for-emacs ((%container %package-symbols-container)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (with-struct (%container. title description symbols grouping-kind) %container
+ (values title
+ `(, at description
+ (:newline)
+ " " ,(ecase grouping-kind
+ (:symbol
+ `(:action "[Group by classification]"
+ ,(lambda () (setf grouping-kind :classification))
+ :refreshp t))
+ (:classification
+ `(:action "[Group by symbol]"
+ ,(lambda () (setf grouping-kind :symbol))
+ :refreshp t)))
+ (:newline) (:newline)
+ ,@(make-symbols-listing grouping-kind symbols)))))
+
+
+(defmethod inspect-for-emacs ((package package)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (let ((package-name (package-name package))
+ (package-nicknames (package-nicknames package))
+ (package-use-list (package-use-list package))
+ (package-used-by-list (package-used-by-list package))
+ (shadowed-symbols (package-shadowing-symbols package))
+ (present-symbols '()) (present-symbols-length 0)
+ (internal-symbols '()) (internal-symbols-length 0)
+ (external-symbols '()) (external-symbols-length 0))
+
+ (do-symbols* (sym package)
+ (let ((status (symbol-status sym package)))
+ (when (not (eq status :inherited))
+ (push sym present-symbols) (incf present-symbols-length)
+ (if (eq status :internal)
+ (progn (push sym internal-symbols) (incf internal-symbols-length))
+ (progn (push sym external-symbols) (incf external-symbols-length))))))
+
+ (setf package-nicknames (sort (copy-list package-nicknames) #'string<)
+ package-use-list (sort (copy-list package-use-list) #'string< :key #'package-name)
+ package-used-by-list (sort (copy-list package-used-by-list) #'string< :key #'package-name)
+ shadowed-symbols (sort (copy-list shadowed-symbols) #'string<))
+
+ (setf present-symbols (sort present-symbols #'string<) ; SORT + STRING-LESSP
+ internal-symbols (sort internal-symbols #'string<) ; conses on at least
+ external-symbols (sort external-symbols #'string<)) ; SBCL 0.9.18.
+
+
+ (values
+ "A package."
+ `("" ; dummy to preserve indentation.
+ "Name: " (:value ,package-name) (:newline)
+
+ "Nick names: " ,@(common-seperated-spec package-nicknames) (:newline)
+
+ ,@(when (documentation package t)
+ `("Documentation:" (:newline) ,(documentation package t) (:newline)))
+
+ "Use list: " ,@(common-seperated-spec
+ package-use-list
+ (lambda (package)
+ `(:value ,package ,(package-name package))))
+ (:newline)
+
+ "Used by list: " ,@(common-seperated-spec
+ package-used-by-list
+ (lambda (package)
+ `(:value ,package ,(package-name package))))
+ (:newline)
+
+ ,@ ; ,@(flet ((...)) ...) would break indentation in Emacs.
+ (flet ((display-link (type symbols length &key title description)
+ (if (null symbols)
+ (format nil "0 ~A symbols." type)
+ `(:value ,(%make-package-symbols-container :title title
+ :description description
+ :symbols symbols)
+ ,(format nil "~D ~A symbol~P." length type length)))))
+
+ `(,(display-link "present" present-symbols present-symbols-length
+ :title (format nil "All present symbols of package \"~A\"" package-name)
+ :description
+ '("A symbol is considered present in a package if it's" (:newline)
+ "\"accessible in that package directly, rather than" (:newline)
+ "being inherited from another package.\"" (:newline)
+ "(CLHS glossary entry for `present')" (:newline)))
+
+ (:newline)
+ ,(display-link "external" external-symbols external-symbols-length
+ :title (format nil "All external symbols of package \"~A\"" package-name)
+ :description
+ '("A symbol is considered external of a package if it's" (:newline)
+ "\"part of the `external interface' to the package and" (:newline)
+ "[is] inherited by any other package that uses the" (:newline)
+ "package.\" (CLHS glossary entry of `external')" (:newline)))
+ (:newline)
+ ,(display-link "internal" internal-symbols internal-symbols-length
+ :title (format nil "All internal symbols of package \"~A\"" package-name)
+ :description
+ '("A symbol is considered internal of a package if it's" (:newline)
+ "present and not external---that is if the package is" (:newline)
+ "the home package of the symbol, or if the symbol has" (:newline)
+ "been explicitly imported into the package." (:newline)
+ (:newline)
+ "Notice that inherited symbols will thus not be listed," (:newline)
+ "which deliberately deviates from the CLHS glossary" (:newline)
+ "entry of `internal' because it's assumed to be more" (:newline)
+ "useful this way." (:newline)))
+ (:newline)
+ ,(display-link "shadowed" shadowed-symbols (length shadowed-symbols)
+ :title (format nil "All shadowed symbols of package \"~A\"" package-name)
+ :description nil)))))))
+
+
+(defmethod inspect-for-emacs ((pathname pathname)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values (if (wild-pathname-p pathname)
+ "A wild pathname."
+ "A pathname.")
+ (append (label-value-line*
+ ("Namestring" (namestring pathname))
+ ("Host" (pathname-host pathname))
+ ("Device" (pathname-device pathname))
+ ("Directory" (pathname-directory pathname))
+ ("Name" (pathname-name pathname))
+ ("Type" (pathname-type pathname))
+ ("Version" (pathname-version pathname)))
+ (unless (or (wild-pathname-p pathname)
+ (not (probe-file pathname)))
+ (label-value-line "Truename" (truename pathname))))))
+
+(defmethod inspect-for-emacs ((pathname logical-pathname)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values "A logical pathname."
+ (append
+ (label-value-line*
+ ("Namestring" (namestring pathname))
+ ("Physical pathname: " (translate-logical-pathname pathname)))
+ `("Host: "
+ ,(pathname-host pathname)
+ " (" (:value ,(logical-pathname-translations
+ (pathname-host pathname)))
+ "other translations)"
+ (:newline))
+ (label-value-line*
+ ("Directory" (pathname-directory pathname))
+ ("Name" (pathname-name pathname))
+ ("Type" (pathname-type pathname))
+ ("Version" (pathname-version pathname))
+ ("Truename" (if (not (wild-pathname-p pathname))
+ (probe-file pathname)))))))
+
+(defmethod inspect-for-emacs ((n number)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values "A number." `("Value: " ,(princ-to-string n))))
+
+(defun format-iso8601-time (time-value &optional include-timezone-p)
+ "Formats a universal time TIME-VALUE in ISO 8601 format, with
+ the time zone included if INCLUDE-TIMEZONE-P is non-NIL"
+ ;; Taken from http://www.pvv.ntnu.no/~nsaa/ISO8601.html
+ ;; Thanks, Nikolai Sandved and Thomas Russ!
+ (flet ((format-iso8601-timezone (zone)
+ (if (zerop zone)
+ "Z"
+ (multiple-value-bind (h m) (truncate (abs zone) 1.0)
+ ;; Tricky. Sign of time zone is reversed in ISO 8601
+ ;; relative to Common Lisp convention!
+ (format nil "~:[+~;-~]~2,'0D:~2,'0D"
+ (> zone 0) h (round (* 60 m)))))))
+ (multiple-value-bind (second minute hour day month year dow dst zone)
+ (decode-universal-time time-value)
+ (declare (ignore dow dst))
+ (format nil "~4,'0D-~2,'0D-~2,'0DT~2,'0D:~2,'0D:~2,'0D~:[~*~;~A~]"
+ year month day hour minute second
+ include-timezone-p (format-iso8601-timezone zone)))))
+
+(defmethod inspect-for-emacs ((i integer)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values "A number."
+ (append
+ `(,(format nil "Value: ~D = #x~8,'0X = #o~O = #b~,,' ,8:B~@[ = ~E~]"
+ i i i i (ignore-errors (coerce i 'float)))
+ (:newline))
+ (when (< -1 i char-code-limit)
+ (label-value-line "Code-char" (code-char i)))
+ (label-value-line "Integer-length" (integer-length i))
+ (ignore-errors
+ (label-value-line "Universal-time" (format-iso8601-time i t))))))
+
+(defmethod inspect-for-emacs ((c complex)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values "A complex number."
+ (label-value-line*
+ ("Real part" (realpart c))
+ ("Imaginary part" (imagpart c)))))
+
+(defmethod inspect-for-emacs ((r ratio)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values "A non-integer ratio."
+ (label-value-line*
+ ("Numerator" (numerator r))
+ ("Denominator" (denominator r))
+ ("As float" (float r)))))
+
+(defmethod inspect-for-emacs ((f float)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (values "A floating point number."
+ (cond
+ ((> f most-positive-long-float)
+ (list "Positive infinity."))
+ ((< f most-negative-long-float)
+ (list "Negative infinity."))
+ ((not (= f f))
+ (list "Not a Number."))
+ (t
+ (multiple-value-bind (significand exponent sign) (decode-float f)
+ (append
+ `("Scientific: " ,(format nil "~E" f) (:newline)
+ "Decoded: "
+ (:value ,sign) " * "
+ (:value ,significand) " * "
+ (:value ,(float-radix f)) "^" (:value ,exponent) (:newline))
+ (label-value-line "Digits" (float-digits f))
+ (label-value-line "Precision" (float-precision f))))))))
+
+(defmethod inspect-for-emacs ((stream file-stream)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (multiple-value-bind (title content)
+ (call-next-method)
+ (declare (ignore title))
+ (values "A file stream."
+ (append
+ `("Pathname: "
+ (:value ,(pathname stream))
+ (:newline) " "
+ (:action "[visit file and show current position]"
+ ,(let ((pathname (pathname stream))
+ (position (file-position stream)))
+ (lambda ()
+ (ed-in-emacs `(,pathname :charpos ,position))))
+ :refreshp nil)
+ (:newline))
+ content))))
+
+(defmethod inspect-for-emacs ((condition stream-error)
+ (inspector fancy-inspector))
+ (declare (ignore inspector))
+ (multiple-value-bind (title content)
+ (call-next-method)
+ (let ((stream (stream-error-stream condition)))
+ (if (typep stream 'file-stream)
+ (values "A stream error."
+ (append
+ `("Pathname: "
+ (:value ,(pathname stream))
+ (:newline) " "
+ (:action "[visit file and show current position]"
+ ,(let ((pathname (pathname stream))
+ (position (file-position stream)))
+ (lambda ()
+ (ed-in-emacs `(,pathname :charpos ,position))))
+ :refreshp nil)
+ (:newline))
+ content))
+ (values title content)))))
+
+(defvar *fancy-inpector-undo-list* nil)
+
+(defslimefun fancy-inspector-init ()
+ (let ((i *default-inspector*))
+ (push (lambda () (setq *default-inspector* i))
+ *fancy-inpector-undo-list*))
+ (setq *default-inspector* (make-instance 'fancy-inspector))
+ t)
+
+(defslimefun fancy-inspector-unload ()
+ (loop while *fancy-inpector-undo-list* do
+ (funcall (pop *fancy-inpector-undo-list*))))
+
+(provide :swank-fancy-inspector)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-fuzzy.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-fuzzy.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,625 @@
+;;; swank-fuzzy.lisp --- fuzzy symbol completion
+;;
+;; Authors: Brian Downing <bdowning at lavos.net>
+;; Tobias C. Rittweiler <tcr at freebits.de>
+;; and others
+;;
+;; License: Public Domain
+;;
+
+
+(in-package :swank)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (swank-require :swank-c-p-c))
+
+;;; For nomenclature of the fuzzy completion section, please read
+;;; through the following docstring.
+
+(defslimefun fuzzy-completions (string default-package-name &key limit time-limit-in-msec)
+"Returns a list of two values:
+
+ An (optionally limited to LIMIT best results) list of fuzzy
+ completions for a symbol designator STRING. The list will be
+ sorted by score, most likely match first.
+
+ A flag that indicates whether or not TIME-LIMIT-IN-MSEC has
+ been exhausted during computation. If that parameter's value is
+ NIL or 0, no time limit is assumed.
+
+The main result is a list of completion objects, where a completion
+object is:
+
+ (COMPLETED-STRING SCORE (&rest CHUNKS) FLAGS)
+
+where a CHUNK is a description of a matched substring:
+
+ (OFFSET SUBSTRING)
+
+and FLAGS is a list of keywords describing properties of the
+symbol (see CLASSIFY-SYMBOL).
+
+E.g., completing \"mvb\" in a package that uses COMMON-LISP would
+return something like:
+
+ ((\"multiple-value-bind\" 26.588236 ((0 \"m\") (9 \"v\") (15 \"b\"))
+ (:FBOUNDP :MACRO))
+ ...)
+
+If STRING is package qualified the result list will also be
+qualified. If string is non-qualified the result strings are
+also not qualified and are considered relative to
+DEFAULT-PACKAGE-NAME.
+
+Which symbols are candidates for matching depends on the symbol
+designator's format. The cases are as follows:
+ FOO - Symbols accessible in the buffer package.
+ PKG:FOO - Symbols external in package PKG.
+ PKG::FOO - Symbols accessible in package PKG."
+ ;; For Emacs we allow both NIL and 0 as value of TIME-LIMIT-IN-MSEC
+ ;; to denote an infinite time limit. Internally, we only use NIL for
+ ;; that purpose, to be able to distinguish between "no time limit
+ ;; alltogether" and "current time limit already exhausted." So we've
+ ;; got to canonicalize its value at first:
+ (let* ((no-time-limit-p (or (not time-limit-in-msec) (zerop time-limit-in-msec)))
+ (time-limit (if no-time-limit-p nil time-limit-in-msec)))
+ (multiple-value-bind (completion-set interrupted-p)
+ (fuzzy-completion-set string default-package-name :limit limit
+ :time-limit-in-msec time-limit)
+ ;; We may send this as elisp [] arrays to spare a coerce here,
+ ;; but then the network serialization were slower by handling arrays.
+ ;; Instead we limit the number of completions that is transferred
+ ;; (the limit is set from Emacs.)
+ (list (coerce completion-set 'list) interrupted-p))))
+
+
+;;; A Fuzzy Matching -- Not to be confused with a fuzzy completion
+;;; object that will be sent back to Emacs, as described above.
+
+(defstruct (fuzzy-matching (:conc-name fuzzy-matching.)
+ (:predicate fuzzy-matching-p)
+ (:constructor %make-fuzzy-matching))
+ symbol ; The symbol that has been found to match.
+ package-name ; The name of the package where SYMBOL was found in.
+ ; (This is not necessarily the same as the home-package
+ ; of SYMBOL, because the SYMBOL can be internal to
+ ; lots of packages; also think of package nicknames.)
+ score ; The higher the better SYMBOL is a match.
+ package-chunks ; Chunks pertaining to the package identifier of SYMBOL.
+ symbol-chunks) ; Chunks pertaining to SYMBOL's name.
+
+(defun make-fuzzy-matching (symbol package-name score package-chunks symbol-chunks)
+ (declare (inline %make-fuzzy-matching))
+ (%make-fuzzy-matching :symbol symbol :package-name package-name :score score
+ :package-chunks package-chunks
+ :symbol-chunks symbol-chunks))
+
+(defun %fuzzy-extract-matching-info (fuzzy-matching user-input-string)
+ (multiple-value-bind (_ user-package-name __ input-internal-p)
+ (parse-completion-arguments user-input-string nil)
+ (declare (ignore _ __))
+ (with-struct (fuzzy-matching. score symbol package-name package-chunks symbol-chunks)
+ fuzzy-matching
+ (let (symbol-name real-package-name internal-p)
+ (cond (symbol ; symbol fuzzy matching?
+ (setf symbol-name (symbol-name symbol))
+ (setf internal-p input-internal-p)
+ (setf real-package-name (cond ((keywordp symbol) "")
+ ((not user-package-name) nil)
+ (t package-name))))
+ (t ; package fuzzy matching?
+ (setf symbol-name "")
+ (setf real-package-name package-name)
+ ;; If no explicit package name was given by the user
+ ;; (e.g. input was "asdf"), we want to append only
+ ;; one colon ":" to the package names.
+ (setf internal-p (if user-package-name input-internal-p nil))))
+ (values symbol-name
+ real-package-name
+ (if user-package-name internal-p nil)
+ (completion-output-symbol-converter user-input-string)
+ (completion-output-package-converter user-input-string))))))
+
+(defun fuzzy-format-matching (fuzzy-matching user-input-string)
+ "Returns the completion (\"foo:bar\") that's represented by FUZZY-MATCHING."
+ (multiple-value-bind (symbol-name package-name internal-p symbol-converter package-converter)
+ (%fuzzy-extract-matching-info fuzzy-matching user-input-string)
+ (setq symbol-name (and symbol-name (funcall symbol-converter symbol-name)))
+ (setq package-name (and package-name (funcall package-converter package-name)))
+ (let ((result (untokenize-symbol package-name internal-p symbol-name)))
+ ;; We return the length of the possibly added prefix as second value.
+ (values result (search symbol-name result)))))
+
+(defun fuzzy-convert-matching-for-emacs (fuzzy-matching user-input-string)
+ "Converts a result from the fuzzy completion core into
+something that emacs is expecting. Converts symbols to strings,
+fixes case issues, and adds information describing if the symbol
+is :bound, :fbound, a :class, a :macro, a :generic-function,
+a :special-operator, or a :package."
+ (with-struct (fuzzy-matching. symbol score package-chunks symbol-chunks) fuzzy-matching
+ (multiple-value-bind (name added-length)
+ (fuzzy-format-matching fuzzy-matching user-input-string)
+ (list name
+ score
+ (append package-chunks
+ (mapcar #'(lambda (chunk)
+ ;; Fix up chunk positions to account for possible
+ ;; added package identifier.
+ (let ((offset (first chunk)) (string (second chunk)))
+ (list (+ added-length offset) string)))
+ symbol-chunks))
+ (classify-symbol symbol)))))
+
+(defun fuzzy-completion-set (string default-package-name &key limit time-limit-in-msec)
+ "Returns two values: an array of completion objects, sorted by
+their score, that is how well they are a match for STRING
+according to the fuzzy completion algorithm. If LIMIT is set,
+only the top LIMIT results will be returned. Additionally, a flag
+is returned that indicates whether or not TIME-LIMIT-IN-MSEC was
+exhausted."
+ (check-type limit (or null (integer 0 #.(1- most-positive-fixnum))))
+ (check-type time-limit-in-msec (or null (integer 0 #.(1- most-positive-fixnum))))
+ (multiple-value-bind (matchings interrupted-p)
+ (fuzzy-generate-matchings string default-package-name time-limit-in-msec)
+ (when (and limit
+ (> limit 0)
+ (< limit (length matchings)))
+ (if (array-has-fill-pointer-p matchings)
+ (setf (fill-pointer matchings) limit)
+ (setf matchings (make-array limit :displaced-to matchings))))
+ (map-into matchings #'(lambda (m)
+ (fuzzy-convert-matching-for-emacs m string))
+ matchings)
+ (values matchings interrupted-p)))
+
+
+(defun fuzzy-generate-matchings (string default-package-name time-limit-in-msec)
+ "Does all the hard work for FUZZY-COMPLETION-SET. If
+TIME-LIMIT-IN-MSEC is NIL, an infinite time limit is assumed."
+ (multiple-value-bind (parsed-symbol-name parsed-package-name package internal-p)
+ (parse-completion-arguments string default-package-name)
+ (flet ((fix-up (matchings parent-package-matching)
+ ;; The components of each matching in MATCHINGS have been computed
+ ;; relatively to PARENT-PACKAGE-MATCHING. Make them absolute.
+ (let* ((p parent-package-matching)
+ (p.name (fuzzy-matching.package-name p))
+ (p.score (fuzzy-matching.score p))
+ (p.chunks (fuzzy-matching.package-chunks p)))
+ (map-into matchings
+ #'(lambda (m)
+ (let ((m.score (fuzzy-matching.score m)))
+ (setf (fuzzy-matching.package-name m) p.name)
+ (setf (fuzzy-matching.package-chunks m) p.chunks)
+ (setf (fuzzy-matching.score m)
+ (if (equal parsed-symbol-name "")
+ ;; (Make package matchings be sorted before all the
+ ;; relative symbol matchings while preserving over
+ ;; all orderness.)
+ (/ p.score 100)
+ (+ p.score m.score)))
+ m))
+ matchings)))
+ (find-symbols (designator package time-limit &optional filter)
+ (fuzzy-find-matching-symbols designator package
+ :time-limit-in-msec time-limit
+ :external-only (not internal-p)
+ :filter (or filter #'identity)))
+ (find-packages (designator time-limit)
+ (fuzzy-find-matching-packages designator :time-limit-in-msec time-limit)))
+ (let ((time-limit time-limit-in-msec) (symbols) (packages) (results))
+ (cond ((not parsed-package-name) ; E.g. STRING = "asd"
+ ;; We don't know if user is searching for a package or a symbol
+ ;; within his current package. So we try to find either.
+ (setf (values packages time-limit) (find-packages parsed-symbol-name time-limit))
+ (setf (values symbols time-limit) (find-symbols parsed-symbol-name package time-limit)))
+ ((string= parsed-package-name "") ; E.g. STRING = ":" or ":foo"
+ (setf (values symbols time-limit) (find-symbols parsed-symbol-name package time-limit)))
+ (t ; E.g. STRING = "asd:" or "asd:foo"
+ ;; Find fuzzy matchings of the denoted package identifier part.
+ ;; After that, find matchings for the denoted symbol identifier
+ ;; relative to all the packages found.
+ (multiple-value-bind (found-packages rest-time-limit)
+ (find-packages parsed-package-name time-limit-in-msec)
+ ;; We want to traverse the found packages in the order of their score,
+ ;; since those with higher score presumably represent better choices.
+ ;; (This is important because some packages may never be looked at if
+ ;; time limit exhausts during traversal.)
+ (setf found-packages (sort found-packages #'fuzzy-matching-greaterp))
+ (loop
+ for package-matching across found-packages
+ for package = (find-package (fuzzy-matching.package-name package-matching))
+ while (or (not time-limit) (> rest-time-limit 0)) do
+ (multiple-value-bind (matchings remaining-time)
+ ;; The duplication filter removes all those symbols which are
+ ;; present in more than one package match. Specifically if such a
+ ;; package match represents the home package of the symbol, it's
+ ;; the one kept because this one is deemed to be the best match.
+ (find-symbols parsed-symbol-name package rest-time-limit
+ (%make-duplicate-symbols-filter
+ (remove package-matching found-packages)))
+ (setf matchings (fix-up matchings package-matching))
+ (setf symbols (concatenate 'vector symbols matchings))
+ (setf rest-time-limit remaining-time)
+ (let ((guessed-sort-duration (%guess-sort-duration (length symbols))))
+ (when (<= rest-time-limit guessed-sort-duration)
+ (decf rest-time-limit guessed-sort-duration)
+ (loop-finish))))
+ finally
+ (setf time-limit rest-time-limit)
+ (when (equal parsed-symbol-name "") ; E.g. STRING = "asd:"
+ (setf packages found-packages))))))
+ ;; Sort by score; thing with equal score, sort alphabetically.
+ ;; (Especially useful when PARSED-SYMBOL-NAME is empty, and all possible
+ ;; completions are to be returned.)
+ (setf results (concatenate 'vector symbols packages))
+ (setf results (sort results #'fuzzy-matching-greaterp))
+ (values results (and time-limit (<= time-limit 0)))))))
+
+(defun %guess-sort-duration (length)
+ ;; These numbers are pretty much arbitrary, except that they're
+ ;; vaguely correct on my machine with SBCL. Yes, this is an ugly
+ ;; kludge, but it's better than before (where this didn't exist at
+ ;; all, which essentially meant, that this was taken to be 0.)
+ (if (zerop length)
+ 0
+ (let ((comparasions (* 3.8 (* length (log length 2)))))
+ (* 1000 (* comparasions (expt 10 -7)))))) ; msecs
+
+(defun %make-duplicate-symbols-filter (fuzzy-package-matchings)
+ ;; Returns a filter function that takes a symbol, and which returns T
+ ;; if and only if /no/ matching in FUZZY-PACKAGE-MATCHINGS represents
+ ;; the home-package of the symbol passed.
+ (let ((packages (mapcar #'(lambda (m)
+ (find-package (fuzzy-matching.package-name m)))
+ (coerce fuzzy-package-matchings 'list))))
+ #'(lambda (symbol)
+ (not (member (symbol-package symbol) packages)))))
+
+(defun fuzzy-matching-greaterp (m1 m2)
+ "Returns T if fuzzy-matching M1 should be sorted before M2.
+Basically just the scores of the two matchings are compared, and
+the match with higher score wins. For the case that the score is
+equal, the one which comes alphabetically first wins."
+ (declare (type fuzzy-matching m1 m2))
+ (let ((score1 (fuzzy-matching.score m1))
+ (score2 (fuzzy-matching.score m2)))
+ (cond ((> score1 score2) t)
+ ((< score1 score2) nil) ; total order
+ (t
+ (let ((name1 (symbol-name (fuzzy-matching.symbol m1)))
+ (name2 (symbol-name (fuzzy-matching.symbol m2))))
+ (string< name1 name2))))))
+
+(declaim (ftype (function () (integer 0)) get-real-time-msecs))
+(defun get-real-time-in-msecs ()
+ (let ((units-per-msec (max 1 (floor internal-time-units-per-second 1000))))
+ (values (floor (get-internal-real-time) units-per-msec)))) ; return just one value!
+
+(defun fuzzy-find-matching-symbols
+ (string package &key (filter #'identity) external-only time-limit-in-msec)
+ "Returns two values: a vector of fuzzy matchings for matching
+symbols in PACKAGE, using the fuzzy completion algorithm, and the
+remaining time limit.
+
+Only those symbols are considered of which FILTER does return T.
+
+If EXTERNAL-ONLY is true, only external symbols are considered. A
+TIME-LIMIT-IN-MSEC of NIL is considered no limit; if it's zero or
+negative, perform a NOP."
+ (let ((time-limit-p (and time-limit-in-msec t))
+ (time-limit (or time-limit-in-msec 0))
+ (rtime-at-start (get-real-time-in-msecs))
+ (package-name (package-name package))
+ (count 0))
+ (declare (type boolean time-limit-p))
+ (declare (type integer time-limit rtime-at-start))
+ (declare (type (integer 0 #.(1- most-positive-fixnum)) count))
+
+ (flet ((recompute-remaining-time (old-remaining-time)
+ (cond ((not time-limit-p)
+ (values nil nil)) ; propagate NIL back as infinite time limit.
+ ((> count 0) ; ease up on getting internal time like crazy.
+ (setf count (mod (1+ count) 128))
+ (values nil old-remaining-time))
+ (t (let* ((elapsed-time (- (get-real-time-in-msecs) rtime-at-start))
+ (remaining (- time-limit elapsed-time)))
+ (values (<= remaining 0) remaining)))))
+ (perform-fuzzy-match (string symbol-name)
+ (let* ((converter (completion-output-symbol-converter string))
+ (converted-symbol-name (funcall converter symbol-name)))
+ (compute-highest-scoring-completion string converted-symbol-name))))
+ (let ((completions (make-array 256 :adjustable t :fill-pointer 0))
+ (rest-time-limit time-limit))
+ (block loop
+ (do-symbols* (symbol package)
+ (multiple-value-bind (exhausted? remaining-time)
+ (recompute-remaining-time rest-time-limit)
+ (setf rest-time-limit remaining-time)
+ (cond (exhausted? (return-from loop))
+ ((or (not external-only) (symbol-external-p symbol package))
+ (when (funcall filter symbol)
+ (if (string= "" string) ; "" matches always
+ (vector-push-extend (make-fuzzy-matching symbol package-name
+ 0.0 '() '())
+ completions)
+ (multiple-value-bind (match-result score)
+ (perform-fuzzy-match string (symbol-name symbol))
+ (when match-result
+ (vector-push-extend
+ (make-fuzzy-matching symbol package-name score
+ '() match-result)
+ completions))))))))))
+ (values completions rest-time-limit)))))
+
+
+(defun fuzzy-find-matching-packages (name &key time-limit-in-msec)
+ "Returns a vector of fuzzy matchings for each package that is
+similiar to NAME, and the remaining time limit.
+Cf. FUZZY-FIND-MATCHING-SYMBOLS."
+ (let ((time-limit-p (and time-limit-in-msec t))
+ (time-limit (or time-limit-in-msec 0))
+ (rtime-at-start (get-real-time-in-msecs))
+ (converter (completion-output-package-converter name))
+ (completions (make-array 32 :adjustable t :fill-pointer 0)))
+ (declare (type boolean time-limit-p))
+ (declare (type integer time-limit rtime-at-start))
+ (declare (type function converter))
+ (if (and time-limit-p (<= time-limit 0))
+ (values #() time-limit)
+ (loop for package in (list-all-packages) do
+ ;; Find best-matching package-nickname:
+ (loop with max-pkg-name = ""
+ with max-result = nil
+ with max-score = 0
+ for package-name in (package-names package)
+ for converted-name = (funcall converter package-name)
+ do
+ (multiple-value-bind (result score)
+ (compute-highest-scoring-completion name converted-name)
+ (when (and result (> score max-score))
+ (setf max-pkg-name package-name)
+ (setf max-result result)
+ (setf max-score score)))
+ finally
+ (when max-result
+ (vector-push-extend (make-fuzzy-matching nil max-pkg-name
+ max-score max-result '())
+ completions)))
+ finally
+ (return
+ (values completions
+ (and time-limit-p
+ (let ((elapsed-time (- (get-real-time-in-msecs) rtime-at-start)))
+ (- time-limit elapsed-time)))))))))
+
+
+(defslimefun fuzzy-completion-selected (original-string completion)
+ "This function is called by Slime when a fuzzy completion is
+selected by the user. It is for future expansion to make
+testing, say, a machine learning algorithm for completion scoring
+easier.
+
+ORIGINAL-STRING is the string the user completed from, and
+COMPLETION is the completion object (see docstring for
+SWANK:FUZZY-COMPLETIONS) corresponding to the completion that the
+user selected."
+ (declare (ignore original-string completion))
+ nil)
+
+
+;;;;; Fuzzy completion core
+
+(defparameter *fuzzy-recursion-soft-limit* 30
+ "This is a soft limit for recursion in
+RECURSIVELY-COMPUTE-MOST-COMPLETIONS. Without this limit,
+completing a string such as \"ZZZZZZ\" with a symbol named
+\"ZZZZZZZZZZZZZZZZZZZZZZZ\" will result in explosive recursion to
+find all the ways it can match.
+
+Most natural language searches and symbols do not have this
+problem -- this is only here as a safeguard.")
+(declaim (fixnum *fuzzy-recursion-soft-limit*))
+
+(defun compute-highest-scoring-completion (short full)
+ "Finds the highest scoring way to complete the abbreviation
+SHORT onto the string FULL, using CHAR= as a equality function for
+letters. Returns two values: The first being the completion
+chunks of the highest scorer, and the second being the score."
+ (let* ((scored-results
+ (mapcar #'(lambda (result)
+ (cons (score-completion result short full) result))
+ (compute-most-completions short full)))
+ (winner (first (sort scored-results #'> :key #'first))))
+ (values (rest winner) (first winner))))
+
+(defun compute-most-completions (short full)
+ "Finds most possible ways to complete FULL with the letters in SHORT.
+Calls RECURSIVELY-COMPUTE-MOST-COMPLETIONS recursively. Returns
+a list of (&rest CHUNKS), where each CHUNKS is a description of
+how a completion matches."
+ (let ((*all-chunks* nil))
+ (declare (special *all-chunks*))
+ (recursively-compute-most-completions short full 0 0 nil nil nil t)
+ *all-chunks*))
+
+(defun recursively-compute-most-completions
+ (short full
+ short-index initial-full-index
+ chunks current-chunk current-chunk-pos
+ recurse-p)
+ "Recursively (if RECURSE-P is true) find /most/ possible ways
+to fuzzily map the letters in SHORT onto FULL, using CHAR= to
+determine if two letters match.
+
+A chunk is a list of elements that have matched consecutively.
+When consecutive matches stop, it is coerced into a string,
+paired with the starting position of the chunk, and pushed onto
+CHUNKS.
+
+Whenever a letter matches, if RECURSE-P is true,
+RECURSIVELY-COMPUTE-MOST-COMPLETIONS calls itself with a position
+one index ahead, to find other possibly higher scoring
+possibilities. If there are less than
+*FUZZY-RECURSION-SOFT-LIMIT* results in *ALL-CHUNKS* currently,
+this call will also recurse.
+
+Once a word has been completely matched, the chunks are pushed
+onto the special variable *ALL-CHUNKS* and the function returns."
+ (declare ;(optimize speed)
+ (fixnum short-index initial-full-index)
+ (simple-string short full)
+ (special *all-chunks*))
+ (flet ((short-cur ()
+ "Returns the next letter from the abbreviation, or NIL
+ if all have been used."
+ (if (= short-index (length short))
+ nil
+ (aref short short-index)))
+ (add-to-chunk (char pos)
+ "Adds the CHAR at POS in FULL to the current chunk,
+ marking the start position if it is empty."
+ (unless current-chunk
+ (setf current-chunk-pos pos))
+ (push char current-chunk))
+ (collect-chunk ()
+ "Collects the current chunk to CHUNKS and prepares for
+ a new chunk."
+ (when current-chunk
+ (push (list current-chunk-pos
+ (coerce (reverse current-chunk) 'string)) chunks)
+ (setf current-chunk nil
+ current-chunk-pos nil))))
+ ;; If there's an outstanding chunk coming in collect it. Since
+ ;; we're recursively called on skipping an input character, the
+ ;; chunk can't possibly continue on.
+ (when current-chunk (collect-chunk))
+ (do ((pos initial-full-index (1+ pos)))
+ ((= pos (length full)))
+ (let ((cur-char (aref full pos)))
+ (if (and (short-cur)
+ (char= cur-char (short-cur)))
+ (progn
+ (when recurse-p
+ ;; Try other possibilities, limiting insanely deep
+ ;; recursion somewhat.
+ (recursively-compute-most-completions
+ short full short-index (1+ pos)
+ chunks current-chunk current-chunk-pos
+ (not (> (length *all-chunks*)
+ *fuzzy-recursion-soft-limit*))))
+ (incf short-index)
+ (add-to-chunk cur-char pos))
+ (collect-chunk))))
+ (collect-chunk)
+ ;; If we've exhausted the short characters we have a match.
+ (if (short-cur)
+ nil
+ (let ((rev-chunks (reverse chunks)))
+ (push rev-chunks *all-chunks*)
+ rev-chunks))))
+
+
+;;;;; Fuzzy completion scoring
+
+(defparameter *fuzzy-completion-symbol-prefixes* "*+-%&?<"
+ "Letters that are likely to be at the beginning of a symbol.
+Letters found after one of these prefixes will be scored as if
+they were at the beginning of ths symbol.")
+(defparameter *fuzzy-completion-symbol-suffixes* "*+->"
+ "Letters that are likely to be at the end of a symbol.
+Letters found before one of these suffixes will be scored as if
+they were at the end of the symbol.")
+(defparameter *fuzzy-completion-word-separators* "-/."
+ "Letters that separate different words in symbols. Letters
+after one of these symbols will be scores more highly than other
+letters.")
+
+(defun score-completion (completion short full)
+ "Scores the completion chunks COMPLETION as a completion from
+the abbreviation SHORT to the full string FULL. COMPLETION is a
+list like:
+ ((0 \"mul\") (9 \"v\") (15 \"b\"))
+Which, if SHORT were \"mulvb\" and full were \"multiple-value-bind\",
+would indicate that it completed as such (completed letters
+capitalized):
+ MULtiple-Value-Bind
+
+Letters are given scores based on their position in the string.
+Letters at the beginning of a string or after a prefix letter at
+the beginning of a string are scored highest. Letters after a
+word separator such as #\- are scored next highest. Letters at
+the end of a string or before a suffix letter at the end of a
+string are scored medium, and letters anywhere else are scored
+low.
+
+If a letter is directly after another matched letter, and its
+intrinsic value in that position is less than a percentage of the
+previous letter's value, it will use that percentage instead.
+
+Finally, a small scaling factor is applied to favor shorter
+matches, all other things being equal."
+ (labels ((at-beginning-p (pos)
+ (= pos 0))
+ (after-prefix-p (pos)
+ (and (= pos 1)
+ (find (aref full 0) *fuzzy-completion-symbol-prefixes*)))
+ (word-separator-p (pos)
+ (find (aref full pos) *fuzzy-completion-word-separators*))
+ (after-word-separator-p (pos)
+ (find (aref full (1- pos)) *fuzzy-completion-word-separators*))
+ (at-end-p (pos)
+ (= pos (1- (length full))))
+ (before-suffix-p (pos)
+ (and (= pos (- (length full) 2))
+ (find (aref full (1- (length full)))
+ *fuzzy-completion-symbol-suffixes*)))
+ (score-or-percentage-of-previous (base-score pos chunk-pos)
+ (if (zerop chunk-pos)
+ base-score
+ (max base-score
+ (+ (* (score-char (1- pos) (1- chunk-pos)) 0.85)
+ (expt 1.2 chunk-pos)))))
+ (score-char (pos chunk-pos)
+ (score-or-percentage-of-previous
+ (cond ((at-beginning-p pos) 10)
+ ((after-prefix-p pos) 10)
+ ((word-separator-p pos) 1)
+ ((after-word-separator-p pos) 8)
+ ((at-end-p pos) 6)
+ ((before-suffix-p pos) 6)
+ (t 1))
+ pos chunk-pos))
+ (score-chunk (chunk)
+ (loop for chunk-pos below (length (second chunk))
+ for pos from (first chunk)
+ summing (score-char pos chunk-pos))))
+ (let* ((chunk-scores (mapcar #'score-chunk completion))
+ (length-score (/ 10.0 (1+ (- (length full) (length short))))))
+ (values
+ (+ (reduce #'+ chunk-scores) length-score)
+ (list (mapcar #'list chunk-scores completion) length-score)))))
+
+(defun highlight-completion (completion full)
+ "Given a chunk definition COMPLETION and the string FULL,
+HIGHLIGHT-COMPLETION will create a string that demonstrates where
+the completion matched in the string. Matches will be
+capitalized, while the rest of the string will be lower-case."
+ (let ((highlit (nstring-downcase (copy-seq full))))
+ (dolist (chunk completion)
+ (setf highlit (nstring-upcase highlit
+ :start (first chunk)
+ :end (+ (first chunk)
+ (length (second chunk))))))
+ highlit))
+
+(defun format-fuzzy-completion-set (winners)
+ "Given a list of completion objects such as on returned by
+FUZZY-COMPLETION-SET, format the list into user-readable output
+for interactive debugging purpose."
+ (let ((max-len
+ (loop for winner in winners maximizing (length (first winner)))))
+ (loop for (sym score result) in winners do
+ (format t "~&~VA score ~8,2F ~A"
+ max-len (highlight-completion result sym) score result))))
+
+(provide :swank-fuzzy)
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-listener-hooks.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-listener-hooks.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,82 @@
+;;; swank-listener-hooks.lisp --- listener with special hooks
+;;
+;; Author: Alan Ruttenberg <alanr-l at mumble.net>
+
+;; I guess that only Alan Ruttenberg knows how to use this code. It
+;; was in swank.lisp for a long time, so here it is. -- Helmut Eller
+
+(defvar *slime-repl-advance-history* nil
+ "In the dynamic scope of a single form typed at the repl, is set to nil to
+ prevent the repl from advancing the history - * ** *** etc.")
+
+(defvar *slime-repl-suppress-output* nil
+ "In the dynamic scope of a single form typed at the repl, is set to nil to
+ prevent the repl from printing the result of the evalation.")
+
+(defvar *slime-repl-eval-hook-pass* (gensym "PASS")
+ "Token to indicate that a repl hook declines to evaluate the form")
+
+(defvar *slime-repl-eval-hooks* nil
+ "A list of functions. When the repl is about to eval a form, first try running each of
+ these hooks. The first hook which returns a value which is not *slime-repl-eval-hook-pass*
+ is considered a replacement for calling eval. If there are no hooks, or all
+ pass, then eval is used.")
+
+(defslimefun repl-eval-hook-pass ()
+ "call when repl hook declines to evaluate the form"
+ (throw *slime-repl-eval-hook-pass* *slime-repl-eval-hook-pass*))
+
+(defslimefun repl-suppress-output ()
+ "In the dynamic scope of a single form typed at the repl, call to
+ prevent the repl from printing the result of the evalation."
+ (setq *slime-repl-suppress-output* t))
+
+(defslimefun repl-suppress-advance-history ()
+ "In the dynamic scope of a single form typed at the repl, call to
+ prevent the repl from advancing the history - * ** *** etc."
+ (setq *slime-repl-advance-history* nil))
+
+(defun %eval-region (string)
+ (with-input-from-string (stream string)
+ (let (- values)
+ (loop
+ (let ((form (read stream nil stream)))
+ (when (eq form stream)
+ (fresh-line)
+ (finish-output)
+ (return (values values -)))
+ (setq - form)
+ (if *slime-repl-eval-hooks*
+ (setq values (run-repl-eval-hooks form))
+ (setq values (multiple-value-list (eval form))))
+ (finish-output))))))
+
+(defun run-repl-eval-hooks (form)
+ (loop for hook in *slime-repl-eval-hooks*
+ for res = (catch *slime-repl-eval-hook-pass*
+ (multiple-value-list (funcall hook form)))
+ until (not (eq res *slime-repl-eval-hook-pass*))
+ finally (return
+ (if (eq res *slime-repl-eval-hook-pass*)
+ (multiple-value-list (eval form))
+ res))))
+
+(defun %listener-eval (string)
+ (clear-user-input)
+ (with-buffer-syntax ()
+ (track-package
+ (lambda ()
+ (let ((*slime-repl-suppress-output* :unset)
+ (*slime-repl-advance-history* :unset))
+ (multiple-value-bind (values last-form) (%eval-region string)
+ (unless (or (and (eq values nil) (eq last-form nil))
+ (eq *slime-repl-advance-history* nil))
+ (setq *** ** ** * * (car values)
+ /// // // / / values))
+ (setq +++ ++ ++ + + last-form)
+ (unless (eq *slime-repl-suppress-output* t)
+ (funcall *send-repl-results-function* values))))))))
+
+(setq *listener-eval-function* '%listener-eval)
+
+(provide :swank-listener-hooks)
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-presentation-streams.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-presentation-streams.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,319 @@
+;;; swank-presentation-streams.lisp --- Streams that allow attaching object identities
+;;; to portions of output
+;;;
+;;; Authors: Alan Ruttenberg <alanr-l at mumble.net>
+;;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;;; Helmut Eller <heller at common-lisp.net>
+;;;
+;;; License: This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+
+(in-package :swank)
+
+(swank-require :swank-presentations)
+
+;; This file contains a mechanism for printing to the slime repl so
+;; that the printed result remembers what object it is associated
+;; with. This extends the recording of REPL results.
+;;
+;; There are two methods:
+;;
+;; 1. Depends on the ilisp bridge code being installed and ready to
+;; intercept messages in the printed stream. We encode the
+;; information with a message saying that we are starting to print
+;; an object corresponding to a given id and another when we are
+;; done. The process filter notices these and adds the necessary
+;; text properties to the output.
+;;
+;; 2. Use separate protocol messages :presentation-start and
+;; :presentation-end for sending presentations.
+;;
+;; We only do this if we know we are printing to a slime stream,
+;; checked with the method slime-stream-p. Initially this checks for
+;; the knows slime streams looking at *connections*. In cmucl, sbcl, and
+;; openmcl it also checks if it is a pretty-printing stream which
+;; ultimately prints to a slime stream.
+;;
+;; Method 1 seems to be faster, but the printed escape sequences can
+;; disturb the column counting, and thus the layout in pretty-printing.
+;; We use method 1 when a dedicated output stream is used.
+;;
+;; Method 2 is cleaner and works with pretty printing if the pretty
+;; printers support "annotations". We use method 2 when no dedicated
+;; output stream is used.
+
+;; Control
+(defvar *enable-presenting-readable-objects* t
+ "set this to enable automatically printing presentations for some
+subset of readable objects, such as pathnames." )
+
+;; doing it
+
+(defmacro presenting-object (object stream &body body)
+ "What you use in your code. Wrap this around some printing and that text will
+be sensitive and remember what object it is in the repl"
+ `(presenting-object-1 ,object ,stream #'(lambda () , at body)))
+
+(defmacro presenting-object-if (predicate object stream &body body)
+ "What you use in your code. Wrap this around some printing and that text will
+be sensitive and remember what object it is in the repl if predicate is true"
+ (let ((continue (gensym)))
+ `(let ((,continue #'(lambda () , at body)))
+ (if ,predicate
+ (presenting-object-1 ,object ,stream ,continue)
+ (funcall ,continue)))))
+
+;;; Get pretty printer patches for SBCL at load (not compile) time.
+#+sbcl
+(eval-when (:load-toplevel)
+ (handler-bind ((simple-error
+ (lambda (c)
+ (declare (ignore c))
+ (let ((clobber-it (find-restart 'sb-kernel::clobber-it)))
+ (when clobber-it (invoke-restart clobber-it))))))
+ (sb-ext:without-package-locks
+ (swank-backend::with-debootstrapping
+ (load (make-pathname
+ :name "sbcl-pprint-patch"
+ :type "lisp"
+ :directory (pathname-directory swank-loader:*source-directory*)))))))
+
+(let ((last-stream nil)
+ (last-answer nil))
+ (defun slime-stream-p (stream)
+ "Check if stream is one of the slime streams, since if it isn't we
+don't want to present anything.
+Two special return values:
+:DEDICATED -- Output ends up on a dedicated output stream
+:REPL-RESULT -- Output ends up on the :repl-results target.
+"
+ (if (eq last-stream stream)
+ last-answer
+ (progn
+ (setq last-stream stream)
+ (if (eq stream t)
+ (setq stream *standard-output*))
+ (setq last-answer
+ (or #+openmcl
+ (and (typep stream 'ccl::xp-stream)
+ ;(slime-stream-p (ccl::xp-base-stream (slot-value stream 'ccl::xp-structure)))
+ (slime-stream-p (ccl::%svref (slot-value stream 'ccl::xp-structure) 1)))
+ #+cmu
+ (or (and (typep stream 'lisp::indenting-stream)
+ (slime-stream-p (lisp::indenting-stream-stream stream)))
+ (and (typep stream 'pretty-print::pretty-stream)
+ (fboundp 'pretty-print::enqueue-annotation)
+ (let ((slime-stream-p
+ (slime-stream-p (pretty-print::pretty-stream-target stream))))
+ (and ;; Printing through CMUCL pretty
+ ;; streams is only cleanly
+ ;; possible if we are using the
+ ;; bridge-less protocol with
+ ;; annotations, because the bridge
+ ;; escape sequences disturb the
+ ;; pretty printer layout.
+ (not (eql slime-stream-p :dedicated-output))
+ ;; If OK, return the return value
+ ;; we got from slime-stream-p on
+ ;; the target stream (could be
+ ;; :repl-result):
+ slime-stream-p))))
+ #+sbcl
+ (let ()
+ (declare (notinline sb-pretty::pretty-stream-target))
+ (or (and (typep stream 'sb-impl::indenting-stream)
+ (slime-stream-p (sb-impl::indenting-stream-stream stream)))
+ (and (typep stream (find-symbol "PRETTY-STREAM" 'sb-pretty))
+ (find-symbol "ENQUEUE-ANNOTATION" 'sb-pretty)
+ (not *use-dedicated-output-stream*)
+ (slime-stream-p (sb-pretty::pretty-stream-target stream)))))
+ #+allegro
+ (and (typep stream 'excl:xp-simple-stream)
+ (slime-stream-p (excl::stream-output-handle stream)))
+ (loop for connection in *connections*
+ thereis (or (and (eq stream (connection.dedicated-output connection))
+ :dedicated)
+ (eq stream (connection.socket-io connection))
+ (eq stream (connection.user-output connection))
+ (eq stream (connection.user-io connection))
+ (and (eq stream (connection.repl-results connection))
+ :repl-result)))))))))
+
+(defun can-present-readable-objects (&optional stream)
+ (declare (ignore stream))
+ *enable-presenting-readable-objects*)
+
+;; If we are printing to an XP (pretty printing) stream, printing the
+;; escape sequences directly would mess up the layout because column
+;; counting is disturbed. Use "annotations" instead.
+#+allegro
+(defun write-annotation (stream function arg)
+ (if (typep stream 'excl:xp-simple-stream)
+ (excl::schedule-annotation stream function arg)
+ (funcall function arg stream nil)))
+#+cmu
+(defun write-annotation (stream function arg)
+ (if (and (typep stream 'pp:pretty-stream)
+ (fboundp 'pp::enqueue-annotation))
+ (pp::enqueue-annotation stream function arg)
+ (funcall function arg stream nil)))
+#+sbcl
+(defun write-annotation (stream function arg)
+ (let ((enqueue-annotation
+ (find-symbol "ENQUEUE-ANNOTATION" 'sb-pretty)))
+ (if (and enqueue-annotation
+ (typep stream (find-symbol "PRETTY-STREAM" 'sb-pretty)))
+ (funcall enqueue-annotation stream function arg)
+ (funcall function arg stream nil))))
+#-(or allegro cmu sbcl)
+(defun write-annotation (stream function arg)
+ (funcall function arg stream nil))
+
+(defstruct presentation-record
+ (id)
+ (printed-p)
+ (target))
+
+(defun presentation-start (record stream truncatep)
+ (unless truncatep
+ ;; Don't start new presentations when nothing is going to be
+ ;; printed due to *print-lines*.
+ (let ((pid (presentation-record-id record))
+ (target (presentation-record-target record)))
+ (case target
+ (:dedicated
+ ;; Use bridge protocol
+ (write-string "<" stream)
+ (prin1 pid stream)
+ (write-string "" stream))
+ (t
+ (finish-output stream)
+ (send-to-emacs `(:presentation-start ,pid ,target)))))
+ (setf (presentation-record-printed-p record) t)))
+
+(defun presentation-end (record stream truncatep)
+ (declare (ignore truncatep))
+ ;; Always end old presentations that were started.
+ (when (presentation-record-printed-p record)
+ (let ((pid (presentation-record-id record))
+ (target (presentation-record-target record)))
+ (case target
+ (:dedicated
+ ;; Use bridge protocol
+ (write-string ">" stream)
+ (prin1 pid stream)
+ (write-string "" stream))
+ (t
+ (finish-output stream)
+ (send-to-emacs `(:presentation-end ,pid ,target)))))))
+
+(defun presenting-object-1 (object stream continue)
+ "Uses the bridge mechanism with two messages >id and <id. The first one
+says that I am starting to print an object with this id. The second says I am finished"
+ (let ((slime-stream-p
+ (and *record-repl-results* (slime-stream-p stream))))
+ (if slime-stream-p
+ (let* ((pid (swank::save-presented-object object))
+ (record (make-presentation-record :id pid :printed-p nil
+ :target (if (eq slime-stream-p :repl-result)
+ :repl-result
+ nil))))
+ (write-annotation stream #'presentation-start record)
+ (multiple-value-prog1
+ (funcall continue)
+ (write-annotation stream #'presentation-end record)))
+ (funcall continue))))
+
+(defun present-repl-results-via-presentation-streams (values)
+ ;; Override a function in swank.lisp, so that
+ ;; nested presentations work in the REPL result.
+ (let ((repl-results (connection.repl-results *emacs-connection*)))
+ (flet ((send (value)
+ (presenting-object value repl-results
+ (prin1 value repl-results))
+ (terpri repl-results)))
+ (if (null values)
+ (progn
+ (princ "; No value" repl-results)
+ (terpri repl-results))
+ (mapc #'send values)))
+ (finish-output repl-results)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Example: Tell openmcl and cmucl to always present unreadable objects. try (describe 'class)
+#+openmcl
+(in-package :ccl)
+#+openmcl
+(let ((*warn-if-redefine-kernel* nil)
+ (*warn-if-redefine* nil))
+ (defun %print-unreadable-object (object stream type id thunk)
+ (cond ((null stream) (setq stream *standard-output*))
+ ((eq stream t) (setq stream *terminal-io*)))
+ (swank::presenting-object object stream
+ (write-unreadable-start object stream)
+ (when type
+ (princ (type-of object) stream)
+ (stream-write-char stream #\space))
+ (when thunk
+ (funcall thunk))
+ (if id
+ (%write-address object stream #\>)
+ (pp-end-block stream ">"))
+ nil))
+ (defmethod print-object :around ((pathname pathname) stream)
+ (swank::presenting-object-if
+ (swank::can-present-readable-objects stream)
+ pathname stream (call-next-method))))
+
+#+openmcl
+(ccl::def-load-pointers clear-presentations ()
+ (swank::clear-presentation-tables))
+
+(in-package :swank)
+
+#+cmu
+(progn
+ (fwrappers:define-fwrapper presenting-unreadable-wrapper (object stream type identity body)
+ (presenting-object object stream
+ (fwrappers:call-next-function)))
+
+ (fwrappers:define-fwrapper presenting-pathname-wrapper (pathname stream depth)
+ (presenting-object-if (can-present-readable-objects stream) pathname stream
+ (fwrappers:call-next-function)))
+
+ (fwrappers::fwrap 'lisp::%print-pathname #'presenting-pathname-wrapper)
+ (fwrappers::fwrap 'lisp::%print-unreadable-object #'presenting-unreadable-wrapper)
+ )
+
+#+sbcl
+(progn
+ (defvar *saved-%print-unreadable-object*
+ (fdefinition 'sb-impl::%print-unreadable-object))
+ (sb-ext:without-package-locks
+ (setf (fdefinition 'sb-impl::%print-unreadable-object)
+ (lambda (object stream type identity body)
+ (presenting-object object stream
+ (funcall *saved-%print-unreadable-object*
+ object stream type identity body))))
+ (defmethod print-object :around ((object pathname) stream)
+ (presenting-object object stream
+ (call-next-method)))))
+
+#+allegro
+(progn
+ (excl:def-fwrapper presenting-unreadable-wrapper (object stream type identity continuation)
+ (swank::presenting-object object stream (excl:call-next-fwrapper)))
+ (excl:def-fwrapper presenting-pathname-wrapper (pathname stream depth)
+ (presenting-object-if (can-present-readable-objects stream) pathname stream
+ (excl:call-next-fwrapper)))
+ (excl:fwrap 'excl::print-unreadable-object-1
+ 'print-unreadable-present 'presenting-unreadable-wrapper)
+ (excl:fwrap 'excl::pathname-printer
+ 'print-pathname-present 'presenting-pathname-wrapper))
+
+;; Hook into SWANK.
+
+(setq *send-repl-results-function* 'present-repl-results-via-presentation-streams)
+
+(provide :swank-presentation-streams)
Added: branches/bos/thirdparty/emacs/slime/contrib/swank-presentations.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/contrib/swank-presentations.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,235 @@
+;;; swank-presentations.lisp --- imitate LispM's presentations
+;;
+;; Authors: Alan Ruttenberg <alanr-l at mumble.net>
+;; Luke Gorrie <luke at synap.se>
+;; Helmut Eller <heller at common-lisp.net>
+;; Matthias Koeppe <mkoeppe at mail.math.uni-magdeburg.de>
+;;
+;; License: This code has been placed in the Public Domain. All warranties
+;; are disclaimed.
+;;
+
+(in-package :swank)
+
+;;;; Recording and accessing results of computations
+
+(defvar *record-repl-results* t
+ "Non-nil means that REPL results are saved for later lookup.")
+
+(defvar *object-to-presentation-id*
+ (make-weak-key-hash-table :test 'eq)
+ "Store the mapping of objects to numeric identifiers")
+
+(defvar *presentation-id-to-object*
+ (make-weak-value-hash-table :test 'eql)
+ "Store the mapping of numeric identifiers to objects")
+
+(defun clear-presentation-tables ()
+ (clrhash *object-to-presentation-id*)
+ (clrhash *presentation-id-to-object*))
+
+(defvar *presentation-counter* 0 "identifier counter")
+
+(defvar *nil-surrogate* (make-symbol "nil-surrogate"))
+
+;; XXX thread safety? [2006-09-13] mb: not in the slightest (fwiw the
+;; rest of slime isn't thread safe either), do we really care?
+(defun save-presented-object (object)
+ "Save OBJECT and return the assigned id.
+If OBJECT was saved previously return the old id."
+ (let ((object (if (null object) *nil-surrogate* object)))
+ ;; We store *nil-surrogate* instead of nil, to distinguish it from
+ ;; an object that was garbage collected.
+ (or (gethash object *object-to-presentation-id*)
+ (let ((id (incf *presentation-counter*)))
+ (setf (gethash id *presentation-id-to-object*) object)
+ (setf (gethash object *object-to-presentation-id*) id)
+ id))))
+
+(defun lookup-presented-object (id)
+ "Retrieve the object corresponding to ID.
+The secondary value indicates the absence of an entry."
+ (etypecase id
+ (integer
+ ;;
+ (multiple-value-bind (object foundp)
+ (gethash id *presentation-id-to-object*)
+ (cond
+ ((eql object *nil-surrogate*)
+ ;; A stored nil object
+ (values nil t))
+ ((null object)
+ ;; Object that was replaced by nil in the weak hash table
+ ;; when the object was garbage collected.
+ (values nil nil))
+ (t
+ (values object foundp)))))
+ (cons
+ (destructure-case id
+ ((:frame-var thread-id frame index)
+ (declare (ignore thread-id)) ; later
+ (handler-case
+ (frame-var-value frame index)
+ (t (condition)
+ (declare (ignore condition))
+ (values nil nil))
+ (:no-error (value)
+ (values value t))))
+ ((:inspected-part part-index)
+ (declare (special *inspectee-parts*))
+ (if (< part-index (length *inspectee-parts*))
+ (values (inspector-nth-part part-index) t)
+ (values nil nil)))))))
+
+(defslimefun get-repl-result (id)
+ "Get the result of the previous REPL evaluation with ID."
+ (multiple-value-bind (object foundp) (lookup-presented-object id)
+ (cond (foundp object)
+ (t (error "Attempt to access unrecorded object (id ~D)." id)))))
+
+(defslimefun clear-repl-results ()
+ "Forget the results of all previous REPL evaluations."
+ (clear-presentation-tables)
+ t)
+
+(defun present-repl-results (values)
+ ;; Override a function in swank.lisp, so that
+ ;; presentations are associated with every REPL result.
+ (flet ((send (value)
+ (let ((id (and *record-repl-results*
+ (save-presented-object value))))
+ (send-to-emacs `(:presentation-start ,id :repl-result))
+ (send-to-emacs `(:write-string ,(prin1-to-string value)
+ :repl-result))
+ (send-to-emacs `(:presentation-end ,id :repl-result))
+ (send-to-emacs `(:write-string ,(string #\Newline)
+ :repl-result)))))
+ (if (null values)
+ (send-to-emacs `(:write-string "; No value" :repl-result))
+ (mapc #'send values))))
+
+
+;;;; Presentation menu protocol
+;;
+;; To define a menu for a type of object, define a method
+;; menu-choices-for-presentation on that object type. This function
+;; should return a list of two element lists where the first element is
+;; the name of the menu action and the second is a function that will be
+;; called if the menu is chosen. The function will be called with 3
+;; arguments:
+;;
+;; choice: The string naming the action from above
+;;
+;; object: The object
+;;
+;; id: The presentation id of the object
+;;
+;; You might want append (when (next-method-p) (call-next-method)) to
+;; pick up the Menu actions of superclasses.
+;;
+
+(defvar *presentation-active-menu* nil)
+
+(defun menu-choices-for-presentation-id (id)
+ (multiple-value-bind (ob presentp) (lookup-presented-object id)
+ (cond ((not presentp) 'not-present)
+ (t
+ (let ((menu-and-actions (menu-choices-for-presentation ob)))
+ (setq *presentation-active-menu* (cons id menu-and-actions))
+ (mapcar 'car menu-and-actions))))))
+
+(defun swank-ioify (thing)
+ (cond ((keywordp thing) thing)
+ ((and (symbolp thing)(not (find #\: (symbol-name thing))))
+ (intern (symbol-name thing) 'swank-io-package))
+ ((consp thing) (cons (swank-ioify (car thing)) (swank-ioify (cdr thing))))
+ (t thing)))
+
+(defun execute-menu-choice-for-presentation-id (id count item)
+ (let ((ob (lookup-presented-object id)))
+ (assert (equal id (car *presentation-active-menu*)) ()
+ "Bug: Execute menu call for id ~a but menu has id ~a"
+ id (car *presentation-active-menu*))
+ (let ((action (second (nth (1- count) (cdr *presentation-active-menu*)))))
+ (swank-ioify (funcall action item ob id)))))
+
+
+(defgeneric menu-choices-for-presentation (object)
+ (:method (ob) (declare (ignore ob)) nil)) ; default method
+
+;; Pathname
+(defmethod menu-choices-for-presentation ((ob pathname))
+ (let* ((file-exists (ignore-errors (probe-file ob)))
+ (lisp-type (make-pathname :type "lisp"))
+ (source-file (and (not (member (pathname-type ob) '("lisp" "cl") :test 'equal))
+ (let ((source (merge-pathnames lisp-type ob)))
+ (and (ignore-errors (probe-file source))
+ source))))
+ (fasl-file (and file-exists
+ (equal (ignore-errors
+ (namestring
+ (truename
+ (compile-file-pathname
+ (merge-pathnames lisp-type ob)))))
+ (namestring (truename ob))))))
+ (remove nil
+ (list*
+ (and (and file-exists (not fasl-file))
+ (list "Edit this file"
+ (lambda(choice object id)
+ (declare (ignore choice id))
+ (ed-in-emacs (namestring (truename object)))
+ nil)))
+ (and file-exists
+ (list "Dired containing directory"
+ (lambda (choice object id)
+ (declare (ignore choice id))
+ (ed-in-emacs (namestring
+ (truename
+ (merge-pathnames
+ (make-pathname :name "" :type "") object))))
+ nil)))
+ (and fasl-file
+ (list "Load this fasl file"
+ (lambda (choice object id)
+ (declare (ignore choice id object))
+ (load ob)
+ nil)))
+ (and fasl-file
+ (list "Delete this fasl file"
+ (lambda (choice object id)
+ (declare (ignore choice id object))
+ (let ((nt (namestring (truename ob))))
+ (when (y-or-n-p-in-emacs "Delete ~a? " nt)
+ (delete-file nt)))
+ nil)))
+ (and source-file
+ (list "Edit lisp source file"
+ (lambda (choice object id)
+ (declare (ignore choice id object))
+ (ed-in-emacs (namestring (truename source-file)))
+ nil)))
+ (and source-file
+ (list "Load lisp source file"
+ (lambda(choice object id)
+ (declare (ignore choice id object))
+ (load source-file)
+ nil)))
+ (and (next-method-p) (call-next-method))))))
+
+(defmethod menu-choices-for-presentation ((ob function))
+ (list (list "Disassemble"
+ (lambda (choice object id)
+ (declare (ignore choice id))
+ (disassemble object)))))
+
+(defslimefun inspect-presentation (id reset-p)
+ (let ((what (lookup-presented-object id)))
+ (when reset-p
+ (reset-inspector))
+ (inspect-object what)))
+
+
+(setq *send-repl-results-function* 'present-repl-results)
+
+(provide :swank-presentations)
Added: branches/bos/thirdparty/emacs/slime/doc/.cvsignore
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/.cvsignore Fri Jan 18 06:05:59 2008
@@ -0,0 +1,15 @@
+contributors.texi
+slime.aux
+slime.cp
+slime.dvi
+slime.fn
+slime.info
+slime.ky
+slime.log
+slime.pdf
+slime.pg
+slime.ps
+slime.tmp
+slime.toc
+slime.tp
+slime.vr
Added: branches/bos/thirdparty/emacs/slime/doc/CVS/Entries
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/CVS/Entries Fri Jan 18 06:05:59 2008
@@ -0,0 +1,9 @@
+/.cvsignore/1.1/Mon Jul 24 14:13:23 2006//
+/Makefile/1.12/Mon Sep 17 14:04:27 2007//
+/slime-refcard.pdf/1.1/Thu Aug 9 09:18:50 2007//
+/slime-refcard.tex/1.1/Thu Aug 9 09:18:50 2007//
+/slime-small.eps/1.1/Wed Nov 22 06:27:38 2006//
+/slime-small.pdf/1.1/Wed Nov 22 06:27:38 2006//
+/slime.texi/1.61/Tue Nov 27 13:16:52 2007//
+/texinfo-tabulate.awk/1.2/Mon Aug 29 20:02:57 2005//
+D
Added: branches/bos/thirdparty/emacs/slime/doc/CVS/Repository
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/CVS/Repository Fri Jan 18 06:05:59 2008
@@ -0,0 +1 @@
+slime/doc
Added: branches/bos/thirdparty/emacs/slime/doc/CVS/Root
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/CVS/Root Fri Jan 18 06:05:59 2008
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous at common-lisp.net:/project/slime/cvsroot
Added: branches/bos/thirdparty/emacs/slime/doc/CVS/Template
==============================================================================
Added: branches/bos/thirdparty/emacs/slime/doc/Makefile
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/Makefile Fri Jan 18 06:05:59 2008
@@ -0,0 +1,97 @@
+# This file has been placed in the public domain.
+#
+# Where to put the info file(s). NB: the GNU Coding Standards (GCS)
+# and the Filesystem Hierarchy Standard (FHS) differ on where info
+# files belong. The GCS says /usr/local/info; the FHS says
+# /usr/local/share/info. Many distros obey the FHS, but people who
+# installed their emacs from source probably have a GCS-ish file
+# hierarchy.
+infodir=/usr/local/info
+
+# What command to use to install info file(s)
+INSTALL_CMD=install -m 644
+
+# Info files generated here.
+infofiles=slime.info
+
+TEXI = slime.texi contributors.texi
+
+all: slime.info slime.pdf html/index.html
+
+slime.dvi: $(TEXI)
+ texi2dvi slime.texi
+
+slime.ps: slime.dvi
+ dvips -o $@ $<
+
+slime.info: $(TEXI)
+ makeinfo $<
+
+slime.html: $(TEXI)
+ texi2html $<
+
+html/index.html: $(TEXI)
+ makeinfo -o html --html $<
+
+slime.pdf: $(TEXI)
+ texi2pdf $<
+
+install: install-info
+
+uninstall: uninstall-info
+
+# Create contributors.texi, a texinfo table listing all known
+# contributors of code.
+#
+# Explicitly includes Eric Marsden (pre-ChangeLog hacker)
+#
+# The gist of this horror show is that the contributor list is piped
+# into texinfo-tabulate.awk with one name per line, sorted
+# alphabetically.
+#
+# Some special-case TeX-escaping of international characters.
+contributors.texi: ../ChangeLog Makefile texinfo-tabulate.awk
+ cat ../ChangeLog | \
+ sed -ne '/^[0-9]/{s/^[^ ]* *//; s/ *<.*//; p;}' | \
+ sort | \
+ uniq -c | \
+ sort -nr| \
+ sed -e 's/^[^A-Z]*//' | \
+ awk -f texinfo-tabulate.awk | \
+ sed -e "s/\o341/@'a/g" | \
+ sed -e "s/\o355/@'{@dotless{i}}/g" | \
+ sed -e "s/\o351/@'e/g" | \
+ sed -e "s/\o361/@~n/g" | \
+ sed -e 's/\o370/@o{}/g' \
+ > $@
+
+#.INTERMEDIATE: contributors.texi
+
+# Debian's install-info wants a --section argument.
+section := $(shell grep INFO-DIR-SECTION $(infofiles) | sed 's/INFO-DIR-SECTION //')
+install-info: slime.info
+ mkdir -p $(infodir)
+ $(INSTALL_CMD) $(infofiles) $(infodir)/$(infofiles)
+ @if (install-info --version && \
+ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
+ echo "install-info --info-dir=$(infodir) $(infodir)/$(infofiles)";\
+ install-info --info-dir="$(infodir)" "$(infodir)/$(infofiles)" || :;\
+ else \
+ echo "install-info --infodir=$(infodir) --section $(section) $(section) $(infodir)/$(infofiles)" && \
+ install-info --infodir="$(infodir)" --section $(section) ${section} "$(infodir)/$(infofiles)" || :; fi
+
+uninstall-info:
+ @if (install-info --version && \
+ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
+ echo "install-info --info-dir=$(infodir) --remove $(infodir)/$(infofiles)";\
+ install-info --info-dir="$(infodir)" --remove "$(infodir)/$(infofiles)" || :;\
+ else \
+ echo "install-info --infodir=$(infodir) --remove $(infodir)/$(infofiles)";\
+ install-info --infodir="$(infodir)" --remove "$(infodir)/$(infofiles)" || :; fi
+ rm -f $(infodir)/$(infofiles)
+
+clean:
+ rm -f contributors.texi
+ rm -f slime.{aux,cp,cps,fn,fns,ky,kys,log,pg,tmp,toc,tp,vr,vrs}
+ rm -f slime.{info,pdf,dvi,ps,html}
+ rm -rf html
Added: branches/bos/thirdparty/emacs/slime/doc/slime-refcard.pdf
==============================================================================
Binary file. No diff available.
Added: branches/bos/thirdparty/emacs/slime/doc/slime-refcard.tex
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/slime-refcard.tex Fri Jan 18 06:05:59 2008
@@ -0,0 +1,123 @@
+\documentclass[a4paper,10pt]{article}
+
+\usepackage{textcomp}
+\usepackage{fullpage}
+\pagestyle{empty}
+
+
+\newcommand{\group}[1]{\bigskip\par\noindent\textbf{\large#1}\medskip}
+\newcommand{\subgroup}[1]{\medskip\par\noindent\textbf{#1}\smallskip}
+\newcommand{\key}[2]{\par\noindent\textbf{#1}\hfill{#2}}
+\newcommand{\meta}[1]{\textlangle{#1}\textrangle}
+
+\begin{document}
+
+\twocolumn[\LARGE\centering{SLIME Quick Reference Card}\vskip1cm]
+
+\group{Getting help in Emacs}
+
+\key{C-h \meta{key}}{describe function bound to \meta{key}}
+\key{C-h b}{list the current key-bindings for the focus buffer}
+\key{C-h m}{describe mode}
+\key{C-h l}{shows the keys you have pressed}
+\key{\meta{key} l}{what starts with \meta{key}}
+
+\group{Programming}
+
+\subgroup{Completion}
+
+\key{M-tab, C-c C-i, C-M-i}{complete symbol}
+\key{C-c C-s}{complete form}
+\key{C-c M-i}{fuzzy complete symbol}
+
+\subgroup{Closure}
+
+\key{C-c C-q}{close parens at point}
+\key{C-]}{cl}{close all sexp}
+
+\subgroup{Indentation}
+
+\key{C-c M-q}{reindent defun}
+\key{C-M-q}{indent sexp}
+
+\subgroup{Documentation}
+
+\key{spc}{insert a space, display argument list}
+\key{C-c C-d d}{describe symbol}
+\key{C-c C-f}{describe function}
+\key{C-c C-d a}{apropos search for regexp}
+\key{C-c C-d z}{apropos with internal symbols}
+\key{C-c C-d p}{apropos in package}
+\key{C-c C-d h}{hyperspec lookup}
+\key{C-c C-d ~}{format character hyperspec lookup}
+
+
+\subgroup{Cross reference}
+
+\key{C-c C-w c}{show function callers}
+\key{C-c C-w r}{show references to global variable}
+\key{C-c C-w b}{show bindings of a global variable}
+\key{C-c C-w s}{show assignments to a global variable}
+\key{C-c C-w m}{show expansions of a macro}
+\key{C-c \textless}{list callers of a function}
+\key{C-c \textgreater}{list callees of a function}
+
+\subgroup{Finding definitions}
+
+\key{M-.}{edit definition}
+\key{M-, or M-*}{pop definition stack}
+\key{C-x 4 .}{edit definition in other window}
+\key{C-x 5 .}{edit definition in other frame}
+
+\newpage
+
+\subgroup{Macro expansion commands}
+
+\key{C-c C-m or C-c RET}{macroexpand-1}
+\key{C-c C-m}{macroexpand-all}
+\key{C-c C-t}{toggle tracing of the function at point}
+
+\subgroup{Disassembly}
+
+\key{C-c M-d}{disassemble function definition}
+
+\group{Compilation}
+
+\key{C-c C-c}{compile defun}
+\key{C-c C-y}{call defun}
+\key{C-c C-k}{compile and load file}
+\key{C-c M-k}{compile file}
+\key{C-c C-l}{load file}
+\key{C-c C-z}{switch to output buffer}
+\key{M-n}{next note}
+\key{M-p}{previous note}
+\key{C-c M-c}{remove notes}
+
+\group{Evaluation}
+
+\key{C-M-x}{eval defun}
+\key{C-x C-e}{eval last expression}
+\key{C-c C-p}{eval \& pretty print last expression}
+\key{C-c C-r}{eval region}
+\key{C-x M-e}{eval last expression, display output}
+\key{C-c :}{interactive eval}
+\key{C-c E}{edit value}
+\key{C-c C-u}{undefine function}
+
+\group{Abort/Recovery}
+
+\key{C-c C-b}{interrupt (send SIGINT)}
+\key{C-c \~}{sync the current package and working directory}
+\key{C-c M-p}{set package in REPL}
+
+\group{Inspector}
+
+\key{C-c I}{inspect (from minibuffer)}
+\key{ret}{operate on point}
+\key{d}{describe}
+\key{l}{pop}
+\key{n}{next}
+\key{q}{quit}
+\key{M-ret}{copy down}
+
+\end{document}
Added: branches/bos/thirdparty/emacs/slime/doc/slime-small.eps
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/slime-small.eps Fri Jan 18 06:05:59 2008
@@ -0,0 +1,995 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner
+%%Title: slime-small.eps
+%%CreationDate: Tue Nov 14 18:44:25 2006
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 0 0 252 104
+%%EndComments
+%%BeginProlog
+% Use own dictionary to avoid conflicts
+10 dict begin
+%%EndProlog
+%%Page: 1 1
+% Translate for offset
+0 0 translate
+% Translate to begin of first scanline
+0 103.29540259080517 translate
+251.14960629921259 -103.29540259080517 scale
+% Image geometry
+248 102 8
+% Transformation matrix
+[ 248 0 0 102 0 0 ]
+% Strings to hold RGB-samples per scanline
+/rstr 248 string def
+/gstr 248 string def
+/bstr 248 string def
+{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
+true 3
+%%BeginData: 57552 ASCII Bytes
+colorimage
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcDnQp&=1TJ,~>
+JcDnQp&=1TJ,~>
+JcDnQp&=1TJ,~>
+JcE=]rVd0(rr2loqtg-`p\+IV#PRoeq>:*grpKf:~>
+JcE=]rVd0(rr2loqtg-`p\+IV#PRoeq>:*grpKf:~>
+JcE=]rVd0(rr2loqtg-`p\+IV#PRoeq>:*grpKf:~>
+^&S*2K`;\ar;-0]p at n@Wp at RnBl/gp^gtM_[%,0ImiT04hnFZMQrVl?eJ,~>
+^&S*2K`;\ar;-0]p at n@Wp at RnBl/gp^gtM_[%,0ImiT04hnFZMQrVl?eJ,~>
+^&S*2K`;\ar;-0]p at n@Wp at RnBl/gp^gtM_[%,0ImiT04hnFZMQrVl?eJ,~>
+_#FK8r;$?d!r;cn\,QX2rVZTlrpKdkrquWgqYU6joD]L&q=<e0hVR5Pj58P;ahkZtYGnAsUCF&u
+Xg>RRajSr)m.C/Qo)F4~>
+_#FK8r;$?d!r;cn\,QX2rVZTlrpKdkrquWgqYU6joD]L&q=<e0hVR5Pj58P;ahkZtYGnAsUCF&u
+Xg>RRajSr)m.C/Qo)F4~>
+_#FK8r;$?d!r;cn\,QX2rVZTlrpKdkrquWgqYU6joD]L&q=<e0hVR5Pj58P;ahkZtYGnAsUCF&u
+Xg>RRajSr)m.C/Qo)F4~>
+_>al?q!dM,hr<khq#'=Ts8E&tr;?HlqY^3lr;HTmrp0RjrquQ`naQ,CqYg!b$NBttna#E'me-GU
+p&>['q!?_R[B6U<\@8]>TW+a/a2[rL%+WD>YGn1p]$&prp\j^`J,~>
+_>al?q!dM,hr<khq#'=Ts8E&tr;?HlqY^3lr;HTmrp0RjrquQ`naQ,CqYg!b$NBttna#E'me-GU
+p&>['q!?_R[B6U<\@8]>SYMdk^:j at 0%*ZE"VkT`^]$&prp\j^`J,~>
+_>al?q!dM,hr<khq#'=Ts8E&tr;?HlqY^3lr;HTmrp0RjrquQ`naQ,CqYg!b$NBttna#E'me-GU
+p&>['q!?_R[B6U<\@8]>V6mGObffhD%+WSI]!S?7]$&prp\j^`J,~>
+h>[WWrVZQgrV-NkqY^<ko`#?tp?:)F[BI!Uf')i*lMh(eqtTjUnF$;Brp0RM%di]RoCV_Lp\=R\
+qu$Elo)B*rq=<_'da6P&m.UALrs\o'o&\EB_8O^YmeHbTrs\o'mFAPViU?6RSZ0Nnmg%djUU8G5
+p\jaaJ,~>
+h>[WWrVZQgrV-NkqY^<ko`#?tp?:)F[BI!Uf')i*lMh(eqtTjUnF$;Brp0RM%di]RoCV_Lp\=R\
+qu$Elo)B*rq=<_'da6P&m.UALrs\o'o&\EB_8O^YmeHbTrs\o'mFAPNg$@t9Q_M(XlNc+VT=!#1
+p\jaaJ,~>
+h>[WWrVZQgrV-NkqY^<ko`#?tp?:)F[BI!Uf')i*lMh(eqtTjUnF$;Brp0RM%di]RoCV_Lp\=R\
+qu$Elo)B*rq=<_'da6P&m.UALrs\o'o&\EB_8O^YmeHbTrrrDumFAP[rlbJ^Vm=2*bQc%f[*e.4
+rUg,?~>
+i;XMjrVH<]nEfB#j5]4`lgOH>q>C3jq>Us'pZTo*]]&><]WTQDp\jIY$N0Yek2"S6bK.`Erl4rX
+&]r8De_&U3i8`tbmIBiCqYgEerser%mFoFYYH=n8d,t$!pAYX%qXE=XWP-?nW4LRHq>U0h%/ohS
+[aX<je^`UCkMY^W#he/'d]LsbqYp0fJ,~>
+i;XMjrVH<]nEfB#j5]4`lgOH>q>C3jq>Us'pZTo'Ze=ZtZ`DC8p\jIY$N0Yek2"S6bK.`Erl4rX
+&]r8De_&U3i8`tbmIBiCqYgEerser%mFoFYWMcZ'd,t$!pAYX%qXE=XVR4(PUUo%Cq>U0h%/ohS
+[`n%#kND*rlfmd!#jCO?bH'(YqYp0fJ,~>
+i;XMjrVH<]nEfB#j5]4`lgOH>q>C3jq>UWspZTo0_>_X^_6_GNp\jIY$N0Yek2"S6bK.`Erl4rX
+&]r8De_&U3i8`tbmIBiCqYgEerser%mFoFY\[SrTd,t$!pAYX%qXE=XXhr)uZ+ANQq>U0h%/ohS
+[`cFp[C*Zc_S#6C#e.Ieb-TO`qYp0fJ,~>
+ir9kpr:omMj4hu'_7R1c\\?)/fAPl]p%eObqu70'nC=YujOr):jPR)inGDVQ#lOAYeA&,YUT+6j
+rMKRl&ZM at nU8Fur\%T]%dFmOFo_SR^rt#,*mFJYMn*93*d]1LSp\jjd&,YqR];b5Zi8F"CZIeRB
+rqZR'qsDY1lH-<4XLlTm]<(D##dM"dh:&pnpAO[aJ,~>
+ir9kpr:omMj4hu'_7R1c\\?)/fAPl]p%eObqu70'nC=SolKIEplJ&AinGDVQ#lOAYeA&,YT;)+R
+&tu(iSt`*_Z+%Eab0eo%lh(&Qq#:m(qX)k at WpB$<mE;ENkkG&Mrt#"th7KHKlKRR#^9ZAZqu6Ek%
+/]G:VsNL&hr!DRj5K@^#iO\'l-$WrpAO[aJ,~>
+ir9kpr:omMj4hu'_7R1c\\?)/fAPl]p%eObqu70'nC=kd^ULV[^W<b3nGDVQ$iK\\eA&,YXL#19
+Yl1d*YS+4IURn3WX0K.I_ogB[ip675rqQL(rqc$5[(=K"`5g$'bNS^!p\td$o%gpab.kU%a2YF:
+n,*+[rsekmc*tWnTq at sSXfJ=km at FTWVQdYS\`*8\p&BO~>
+jSp5!r:odDfu^e(TW#$4`5KX*VPBrn_U.-&nbE%]rr3Q/q<,T+jM8%%Z,#G4_<:Xnn,E[lpZKc$
+a7&Kap$)PFrpL<S_o0']WM$/ubMVgcrqZR)r:8UMa62!paj&Z!WmpM7q#:p(p>j&hlI!DZ]?TEJ
+]]&S_qYq$(q<,Q6i4G)-M3+3lOR.f0N0'^WmB"n/r:U)?~>
+jSoYfr:odDfu^e(SYE!prk&ZETV&$d_U.-&nbE%]rr3Q/q<,T#lJgaZi8X%._<:Xnn,E[lpZKc"
+^?b+Po^)SC%GA>*Yb%S[Vmjk,nG<.[rt#%ugU4c]kN(^cl.W)cn,)n[&H2=`_5$AZio/kXlE\(]
+pAOjf%K?1d^qT'lg=Os1gtUQLf*L$_h<"%&f(&\2s*t~>
+jSoYfr:odDfu^e(V6RMKrko5ZYH4P+_U.-&nbE%]rr3Q/q<,T1^SmiuTr>`A_<:Xnn,E[lpZKc*
+`luZIou$jQrQG\e`4`=ZUo1]FhsgLAq>V!'o%URl_R6MJYe%o[eF3;0rt,/&jMA1 at ZDaXtYeRud
+iV*6Hrso&(kJ5*MVO*gCQ^<u(SF)jQS!TSJa0jLgr:U)?~>
+jo5bfq=3Rs^o=!Gi9omnrSSgZlL"&YYFr&9f&uZ$rr<#tp><.DeZ=^dN2tLtZ/>9Sn,E[jn'nDq
+i76B&ouR3]rm_J2i8E\]lL+,hXhEQ]r;-F*rqPZpWTqU,S"$+djLMq`p\t!g&GtqFVs_s0PE:m'
+dI*aUmeck\%0$%_\AdC<OF21uK7NrKs+:9-!/p]8re^Z,$@I,DJssdGY0lb:p&BO~>
+jo5bfq=3Rs^o<g:g$J(krTPHim-X,NVk(!.f&uZ$rr<#tp><. at kMOqDf\blXZ/>9Sn,E[jn'n>j
+l0%6kp#H,8roXCIl07L4liue!VnLpWr;-F*rqPZpU?psugt^`FlE\(_p\t!g#5dl<V!R7#rn7S5
+k3Sbfmeck\%0$%_\@h(bg="<qeC4EFs4%)#!8./%rn%2"$I[>KeD0-OVpY#3p&BO~>
+jo5bfq=3Rs^o=9Obf[l at rOa8f`5g*>\>6:Ff&uZ$rr<#tp><.![@`qYS"@%3Z/>9Sn,E[jn'nV`
+]X>/OorS5"rj<3E]Y)"t`6-<H\%UVgr;-F*rqPZpZc&u<Q^=/>^V at GAp\t!g&GtqFXNIi=QC!r.
+ZH9&lmeck\%0$%_\AZ%WQ`IKoUS[sjs.fUb!1WhPrgj(a$EL>7UR/+$\'a^Cp&BO~>
+kPl%kr:]F/_5=EomGQ[Fai+.i+Mc+De_oWYdBTXhhspRBs8DWFVsi0;M04ZUeaKEjp&4C[$3'b_
+^rPBFXK8,gRfK>bX:DMI]>2P1dFI(<^;T1/rql^-r:8L?i7YAoK7f#]eaK<anbi7`')q^i^q/UB
+PC at n.P/$(f]]Akequ7B0pYrX"i4G(uBk_L(Jr,SXR]EKoqRZ[,s-a:VNerU]aQg"Znbi([J,~>
+kPl%kr:]F/_5=0amHNisjQ$3t+QDJDkNV=!af25XhspRBs8DWFVsEO'f?`(+kNf&#p&4C[$3'b_
+^q]-mhr!8_g]641h[\T'iSrqZk3)!q[`%>'rql^-r:8L?g$%AHeC<+-kNeqonbi7`')q^i^p<7b
+g=+Kug>_D&]]Akequ7B0pYrWol/C at Eb0%rPeCWF0gu%#IqVhG2s4dt8g"4j2jQrnrnbi([J,~>
+kPl%kr:]F/_5=`da1SmeXfMDt+K2EH[CjB!agn at hhspRBs8DWFVp)Q at S@"iY[EPQ'p&4C[$3'b_
+^rO*bT:_SFQN3QTT+7QlVPpW!ZF.9^_o1^4rql^-r:8L?bdX:8USFBO[EPGsnbi7`')q^i^qd^`
+QDgj_QDhR4]]Akequ7B0pYrX!]V_$raiV93URdd=Q_'eBqPO7`s-F([R at Tn8Xi.d"nbi([J,~>
+kl21mqXW[jYG^=Ag!..6VONkLO<BaVTrblEdG=!DXM<]cr;Z`ffq\#dXGM(VX4?[6g%>74rsA]!
+iNr"'XGMdfon*7"reV,DOH>ZqS#39qeaKToo_n^f'E7jn`i87FRtGWtJssdGVoS*!rql^.rUo!M
+dG;6kH>.S]Z.\'7g%51>rtPJ-j0lna]9%DS>]54_X1HBne^`@Li;V:,a9oMeX/ii!jIG&urUp2@~>
+kl21mqXW[jYFsS7kiLd]hV?l`g)o,+hr3VXl0I$"^Ynb^s8DTCU[.+#f?`(+kNenro_n:Z$3'\X
+Zg6f3f at SRGe,\)!f)XJ&gAfq6hV[;Tl`Ak5rVZ[/rqbp"U?psreBH.dguRgqa6NO#qu7<-p"cgo
+l/C=Cb0\f!kh2rgoDSRd'`Rmf[_1k`g="-?bgbG*iT0(_kNMd,roa=Bs5F"8#3"t'QJM33p&BO~>
+kl21mqXW[jYHc<g\$2a'S<oN>QQVT\R\-IXZF[os[D1Ylr;Z`ffqZd!T:E9ZT!ce;g%>74rsA]!
+iNpb9T:DFFoqMMYrgXIfQ^=#)Q^j\C[EP`,o_n^f'E7jn`j3ObQ_V:/UR/+$YfH&*rql^.rUo!M
+ah"78Y0!r<Tsr7Fg%51>rtPJ-j0ln=VO+@*`4r(6Su/Wl[C*L?]`,>=XU:r#St;h"fsBN,rUp2@~>
+l2M=oqXE=XUVuHN`3H"tN/*%9rHo`:K8#/DQ);".g$5``lh^VZo[oo,eZ=UMM6#1qU=f,:nG`am
+pY`=FeZ=W(K)0BuF*2bUG^OmfK7er9R`Octe+*A6rtGA)i3^G\]9%DSBRGoQi5E+ap\t'i')_:K
+TC:=3M03<JKqQ]XUWr6(qu7W7puK!)i4G(uBlATlaOT56lL43!_SEt)_na(en,MY[i8)r6i9cK,
+lM:GPs*t~>
+l2M=oqXE=XTtKaUj5AbIf[eR$rR)h;eCE1)gYUoLkj57klh^VZo[oo(kMOn;fAGcWU=f,:nG`am
+pY`=BkMOnfeG at B%cHjndd*g at keC<($guRh$e+*A6rtGA)i3^/]iS)`&ajSo%l+FLbp\t'i')_:K
+TBk[tf?_"Pe_T?ST?Zg$qu7W7puJuul/C at Eb08AjjQGdom-Euj]!f)[]=,0Ili6;Yl0.<nl0Wu"
+lM:GPs*t~>
+l2M=oqXE=XWPl`aX.buKS"?COrMq'>US43EQ(4VM\&>c!lh^VZo[on^[@`trSY!75U=f,:nG`am
+pY`=#[@`ucU\_\;\$W<=Z)aq(USFENQ`\3:e+*A6rtGA)i3^G8VO+@*b,^o,]Yh5<p\t'i')_:K
+T?O^8S@$>KTpi4+XNg21qu79-puK!(]V_$rahOU;XgPg[`;[sb_8jX6_T0^rbl>Tg]XkMY]Z7S&
+lM:GPs*t~>
+lMhLrq<ltJU#+_LZ'C9%I!BpeJqs>^+GGDrH$k-tNg6m"n%.TTrr)KAU at 6X6M04ZUeaK6bo_n:Z
+#QFM[][>QDT_b)XJoCQl!b$#!r/(B(#,]f9YL;q<r;RH.n^X?%eZ=UM at q9eAZ.\'6g%>7?rtG7p
+aJ\=FRtGWaCk.ehkH;Ybq>U<l.fT8,^8^;6Q%3e)R`Od-_ip@!CNQauDmZliDJX'$Q(l+An*e,M
+I_bURo`'F~>
+lMhLrq<ltJSD*5gi7lo7da6CjeCOWN+P"uidF-Lpg"YHJlal0Prr)KAU?h""f?`(+kNekpo_n:Z
+#QFM[]ZKEsh>5n-eBIif!jg,#r7Cns#2\M/WRC;6r;RH.n^X?!kMOn;\\?GCi98jmg%>7?rtG7p
+aJ%t]gsjQFbL>5+l__M^q>U<l.fT8,^7X`OgXFBrguRh/]7l#@=_+^A?F7(F>Zt61LRbiolg)'+
+DS#K<o`'F~>
+lMhLrq<ltJWQ2ZRTp;+ at X0Jh)US%OV+JGR/Y,eCjR?aJRbdum1rr)KAU<L$;S@"iY[EPAto_n:Z
+#QFM[]Zds^Rei?OUV?ZF!li!Mr13e]#+W!@]$g*Gr;RH.n^X>W[@`tra2kNTTsr7Eg%>7?rtG7p
+aK`[cQ_V:6_PWU!_RIAFq>U<l(]O6n^:M1^Q)26jQ`\3B_RmL`Yd(C=[JmNDZa$a:]rT5tbfn2@
+]@Z]Qo`'F~>
+li.Xtq<lnDVsVmDRuDlBF+/n$Q("TLX!"((P)bBSJqBZ,i:488p\t-`fV7ibXGM(VX4?[5f_#.2
+rs&>ecA:l at c2,KfRt>Q`91rN.JsuV<rL*qfdI*[[oDSUe'Dh%9W9VKoK5Y"&F,-X?m[qkpr;?R/
+rqPQc\E(GhIVW)"I#tqt_mSLurqudGrqblrS*J+bK7]Q5lAK2SF*;eSL>RB+iSf03H[9p[_/X at p
+DfU)Zc27M4s*t~>
+li.Xtq<lnDT^Cn#gt:*&cI1:qgYCZbh]Ub1g=b*/eC<=5l0>_:p\t-`fV7]phq-3+hrj="f_#.2
+rs&>ec?\g at jne$EgsjQEBP=6deD0uZrS.V6k3SPhoDSUe'Dh%9U?psreBFepcIUk7m$uGkr;?R/
+rqPQcYNk-$e'"0$db<[E]X?bnrqudGrqblrOmM/aeC<:7m!_j6@:Wt`G2I%MiSeNdBkV*h_-^HL
+?!q8ia8>l.s*t~>
+li.Xtq<lnDYfF&HQ^ahV\>Z$jQ'\$?SfjJgQC4;9USF9T][XCLp\t-`fV6TtT:E9ZT!ce:f_#.2
+rs&>ecF_-+YkkI.Q_V:5]tMA!UR1nMrKd_YZH9E)oDSUe'Dh%9Z,Ec2UV=^e\=]:saeR5Or;?R/
+rqPQc]t^M3W5ZZsX-fcs_mSLurqudGrqblr[)B)5USF0X`3cMF\@]Gh_r&;IiShVh^q[Rp_7$_Q
+[(!`gjSSrKs*t~>
+m/Ie!qXE4IV<Z=&OFqdrIYWcWX2N*,rm`.9aM50aVOEsH]'dSQk5##To[oo,eZ=UMM6#1qU=f,:
+n,EUjp#:(\iU-L,$-AZgDd6OcJssdYec!PndFH75jS/ZPrtYP.jh&%`^ls4_=^5lsR`Ocj`9R3u
+rVmT1p"Z[sh6r>iB2rJdMm:snWnd:Gqu7Q1lG]=Zad[p7R`OcVDUX#aJV&sWK7ipmKDpH1JUls4
+I,97"J<87ZoDa=~>
+m/Ie!qXE4ITBt[rg=4Kndam%,hrEe[roYEcjPo.UhV?oBiU".jk5##To[oo(kMOn;fAGcWU=f,:
+n,EUjp#9G<g?nb'$09mkbbh5\eD0-_kPaHGk3'LOjS/ZPrtYP.jh%_]inDl)RAJ-WguRgo`9R3u
+rVmT1p"Z[ll/C=C`JhOXf\kuHWnd:Gqu8)@lG\tRjP887guRgS>gmJ+DfC7$EH1aIEH,r:Df4cS
+C>N]ADLg"2oDa=~>
+m/Ie!qXE4IYJdZ8Q_Uh#W1TWNSu]!!rj<lQXf/"dS<oS2VTI6#k5##To[on^[@`trSY!75U=f,:
+n,EUjp#<NtbfBRu$*BPh^;Rt)UR/+\[Jd33ZF.Q_jS/ZPrtYP.jh&4 at W0XC$_o0<bQ`\3/`9R3u
+rVmT1p"Z[k\tb[rahc''S"[=8Wnd:Gqu8)@lG^0LXd>fXQ`\3:ZdZe1`lH?uaN4,MaN2EB`l7/Y
+_;<#G`Qd]IoDa=~>
+m/IdtoA at 0XlH,`THuEqGM5I?$e`Z5crpLuslK$dOdE'DRea at b2med"^o[oo,eZ=UMM6#1qU=f,:
+n,F7(qso,XGH%U-Pbt7>Q)D`nK5Y[[R`NR_rU9^M"n&Y&\FBCnrtYM*hQG8^[Z5ZH<E<d\OLjAg
+\`EPbrVmT0n^F)ueZ=UM at o6]XM6#1qT[iW3qu73'lc,L\ad[p7R`OcYF6%rPKE[S=Kn]O*re:?)
+#l91+p4J!NP1K4(J,~>
+m/IdtoA at 0Qm,[!Rd`fq]fA>EIkNhL$rp(]om-<ftk2bUbkNlp1med"^o[oo(kMOn;fAGcWU=f,:
+n,F7(qsnN5B;D;XL7b&iO.YLgeBH.dguQG\rTjCJ"K/W4nGE.`(&dg^Y0-"fg!RctOic&*iT\"c
+jS8`QrtPD$e"5mghq-2bI^m_Uhrj<ueai\9rttUu`focMgsjj/jQqS/jD]-[F+aI5F8l1;F8p7d
+qJgNKEH-#Od.73e~>
+m/IdtoA at 0a`3#K"X1l?USXc:W[DKl(rlcM*`4rmkZE:75[E5l)med"^o[on^[@`trSY!75U=f,:
+n,F7(qsqV9['?sN]W\HKT!b\eUV=L<Q`\!;rQP5Y"j+Tfd.$r1rtYM*hQFu3URA:,_8=?qR&7O7
+\`EPbrVmT0n^F)R[@`tra1o[%SY!75T[iW3qu7N0lc-BOXd>fXQ`\3<\E(]Pai`!0b0'__rQ>/^
+#l;W`p;k=sd-^E(J,~>
+mJf3GpufYlmEM>YF(oQ8M6#%Sma%ntS"+2]Kp9'nn*]K+mGF7PjS&QPrUea:n("LrFc!0Ln"SJ,
+rU0\3rqh:sLXXIiFiM79Q&Y(NRtH<]aQe[mBPM7MQBd`$HZRi\q>U<l(&d^SU at 6X6M03<*<+^E9
+[b]?6hY-sIrtP=qa/A4ERtGWa9jVgnTZukucL:Z-rt"tl`guD:RtH<]aQf"3l at f.j"dAt?L&_2M
+K`h@/L&V(*!L)+*s*t~>
+mJe4+pufYhmH*0ScH=AWfAG`Rm)YrVR at I?IG(m-?li-5fmFmD,jS&QPrUea:lf[0Wce%(;l_<&(
+rU0\3rqgYOGLOcGA&c>kQ%//]gsjj/jQq=l<`iImLkgbBC15c3q>U<l(&d^SU?h""f?_!VMT!oq
+iTSCdhY-sIrtP=qa.Ve[gsjQFDQD%4h<"$qcL:Z-rt"tl`focMgsjj/jQqV2l>llF"bZhrF8u:;
+Es)G`F8l/[!JAbis*t~>
+mJf3GpufYta0;#+\&lClSY!-paiCa#Tq&9S\@]DsbfRfAa3)0.jS&QPrUea:bdF(5[%3erbbEb^
+rU0\3rqjaS`7)rA]#MRoQ*nQ4Q_U=BXi.TFXfnps^:h4p\%()Kq>U<l(&d^SU<L$;S@$>O_9&jJ
+UUnOLhY-sIrtP=qa0ERbQ_V:6]u at UWR]si4cL:Z-rt"tl`jWgfQ_U=BXi.l`lH0%J"jm:lb5_M=
+aoh[db5VC_!RU6)s*t~>
+mJf3DnC=Jqfs-K\AT)sQX4?XAG&4^3cI7'eG'(<5CNukFWNp\qoDARfrUea:n("LrFc!0Ln"SJ,
+rU'V0re,obna:pXlK*8mYiNT`IY+$0lB,q,H$Rh^G'8(UIdkeaqu7E.m`hKnc(Ti2?VO at +Fc!0L
+n"\M+rVlg3rqGKa\E(GhIVW(Z>]54_aQfYBlh^MY&,PV3Sa+=dK7]Q5lBHGWK`6Z/PQ->js8VtM
+"94(/s8I]QPLf=)J,~>
+mJf3DnC=Jjkht+?^Wb-Xhrj@&AQlWScI6FSAR`5U=_FOdV6XWIoDARfrUea:lf[0Wce%(;l_<&(
+rU'V0rc<(0na::4lK)Z\V<['oe(!16m"8PRB4oY(A7T7bD",[Iqu7E.m`h?jjk\J3XDiQsce%(;
+l_E)'rVlg3rqGKaYNk-$e'".kV9IHEjQrPZlh^MY&,PV3PO.AceC<:7m"T$9ErL+`KE$"6s8Vt;
+"93F`s8I'?K@'2hJ,~>
+mJf3DnC=J]\"T:raM4dHT!c\TZ*LpOcI9MU]XbV[YdCdOZ*M!YoDARfrUea:bdF(5[%3erbbEb^
+rU'V0rlW=,na=B8lK,a^`4r7:W2#]]`4<4d^:r%.]=Y_j_slphqu7E.m`hfQYaV8s`P0+-[%3er
+bbNe]rVlg3rqGKa]t^M3W5ZZe`4r(6Xi.E_lh^MY&,PV3[`#;7USF0X`4W\Iao9Edd/V82s8Vu=
+"96Nds8L.Ad-^E(J,~>
+mf,?IpZ9/nkJWX9D/Xf`X4=@sDfpBeJ+)r[nUQ,NI!U%_GLYK!K)>QIs8DTBU at 6X6M04ZUeaK6b
+o_n.Vs+M8Pr;2/#q=B!@_;MqeI"e6<m?D^@JV!@iJ-1CUqpkTD(B40p_klY?RtGWa928l9LSiJe
+S^6d&rr3c4o\-=lh6r>iB2qN,Ck.ehkH)G]q>U<l&,PV3Sa+=dK7]Q5lBHGWK`6Z/PQ->js8VtM
+"94(/s8I]QPLf=)J,~>
+mf,?IpZ9/glf6aKbfnMhhrgeI?"@X0D=@%7nSW4*C1q5)A^oRRE;TY7s8DTBU?h""f?`(+kNekp
+o_n.Vs)T97r;1MTq=A at .\*;l*dad18m=o(cDf>/aDJjB3EVn)ZrtbV1l,0+ZjP88/VJ(+WcIUk7
+m$c8hr;Q^3rUegDam%d;dD_&OT$,U;j6NPVkP>,Trt"tl`focMgsjj/jQqV2lZ2uG"bZhrF8u:;
+Es)G`F8u5\!JAbis*t~>
+mf,?IpZ90"_Q/ru_S<.=T!c;<[(F*6`:*9;n\rH._8!\/][YfVa8>l9s8DTBU<L$;S@"iY[EPAt
+o_n.Vs2lG1r;4UXq=DG0aLnC:X.buda1]%#`l at Pg`Poj;aSYB%rtbV1l,0[BXd>fs`P'"*\=]:s
+aeI,Mr;Q^3rUegDah"78Y0"Mm_nr:9X2;9ZkP>,Trt"tl`jWgfQ_U=BXi.l`lcK.K"jm:lb5_M=
+aoh[db5_I`!RU6)s*t~>
+mf+X3o%0etfs-K\Dg[YXeW=TiH[gYBK`(e%r.KauJqARBJFW;bK`:uN&H27RU at 6X6M04ZUeaK6b
+o_n.Vs+M8Qs8Re,rqCiK_;MqeI"e6<m=oh8KS9:$KE?l-f),I_rqPQb`Se at iHtcYO93cCeR`Ock
+`p<L#rtbM#c_'XQVMB5$:IS;tI#tqt`4+e%rqud,qWc%jlH,NJJssdGP]c;Fre1N>s+Q1,s8.KP
+s+Q1,re1B:f(/ik~>
+mf+X3o%0emkht+?bgP5(kCZrJBl.haEr>lWr,QiQEH#jbDt3L?F8l1=&H27RU?h""f?`(+kNekp
+o_n.Vs)T!/s8R.]rqC39\*;l*dad18m<<,ZEcV*VErU1]s3UZC(B4*i\\.1cg="-,;J)cLeD0-O
+T>p3nrr3c2n'@Njk2+\7ZZf6.ajSo%l+FLcq#:3k&,PS1PO.AceC<:7m"T$9ErL+`KE$"6s8Vt;
+"93F`s8I'?K@'2hJ,~>
+mf+X3o%0e`\"T:r^T3a![C*<O^r4:gao)+[r5m(UaN)<h`pr`Cb5VD?&H27RU<L$;S@"iY[EPAt
+o_n.Vs2l/)s8U6arqF:;aLnC:X.buda18k%aiXJZaoBKas6]^`(B4*i\\u.XQ`J6F]"GtrUR/+$
+YK#o)rr3c2n'@fPZCIMq`kK%$b,^o,]Yh5=q#:3k&,PS1[D]26USF0X`4W\Iao9Edd/V82s8Vu=
+"96Nds8L.Ad-^E(J,~>
+mf+U0lc?'jad[p$I#tqtNbs#iJqSgVL&_1,s+Q1,KnP-WK`(h'L&M#_rUea:n("LrFc!0Ln"SJ,
+rTsRaKbosQs+Q1+pO'9_i4G(uM6#1qBR#)]L&_%(!WUaJs"OHGhQOiT]9%DS=%5\^C4;>\jLDnc
+q>UEnq<,SskJWX9D-KS#<bQlB]&:H/htI'Jrt,2+l,0%Vad[p7R`OcYFmF_[Ka!\?Kn]R,qh5.P
+Kn]R+K`RCgo)F4~>
+mf+U0lc>gejP88/db<[EJQl`&E,p%!F8u8]s)W8]F)uC"Er>oXF8c+MrUea:lf[0Wce%(;l_<&(
+rTsRaEu0K/s)W8\pM7(Cl/C at EfAGcW<bH>kF8u,Y!WUODs"OHGhQONTiS)`&P#>DLbL5,(lEIta
+q>UEnq<,Sllf6aKbb&<?Oic&*iT[qWhtI'Jrt,2+l,/\NjP887guRgVA*\17Es73rF*%B]qf;l>
+F*%B\Ergp?o)F4~>
+mf+U0lc?BMXd>fsX-fcsZa.9^a2uL'b5_Las2rLab0%j(ao).\b5M>OrUea:bdF(5[%3erbbEb^
+rTsRaaqrG)s2rL`pVO5W]V_$rSY!75Y.hotb5_@]!WVQas"OHGhQOf/VO+@*_Rd at s`i,3%^V.>C
+q>UEnq<,T'_Q/ru_Sj*u_TJpHVS'aKhtI'Jrt,2+l,0pIXd>fXQ`\3=]'IK;ap$/lb0'baqoT$@
+b0'b`aoTlVo)F4~>
+n,FF-puK!)i4G(uI#tqtcXh3IJqSf2s+ULQL&Zj\s8I]Us+ULQKn]L*&H27RU$pO5M04ZUeaK6b
+o_n.Vs+M8Qs8Re,rq:`C^u2hdI#4oSmqI'!KSBI'K`V5)qu8AKo at Tl-eZ=UM at o5Z`<bQlB]&:K4
+i:m6NrUo'Q_r/.gHtcYO78RH9M6#1qVqUeArVmH.q<,M^lH,NJJssdGP]c;Fre1N>re6()rV_EL
+K*_7)KDU=UKp1*Ys*t~>
+n,FF-puJuul/C at Edb<[E`Dg;_E,p#@s)\5?F8p<&s8I'Cs)\5?F*%<[&H27RU$Ln!f?`(+kNekp
+o_n.Vs)T!/s8R.]rq:*1[cuc)db!C>lW at e=F*%BYErl<fqu8AKo at Tl)kMOn;\UHe?Oic&*iT[t\
+i:m6NrUo'Q]BS;.d`R_N:jfe!fAGcWVqUeArVmH.q<,MSm,ZsOeD0-OL1BOirc86qrc</ZrV^d:
+E<GuUEVo`V!JAbis*t~>
+n,FF-puK!(]V_$rX-fcsbH&1ka2uKHs2tBAb5]W,s8L.Es2tBAb0'\_&H27RU!0p:S@"iY[EPAt
+o_n.Vs2l/)s8U6arq=13aLnC:X.>iibceb$b0'b]aoVP0qu8AKo at Tk_[@`tra1o*p_TJpHVS'dP
+i:m6NrUo'Q_n;k5X3&5i]"c:mSY!75VqUeArVmH.q<,N!`3#B$UR/+$]XmFNrlPDkrlWC^rVak<
+a924YaSYtZ!RU6)s*t~>
+n,FF-p>2t1fs-K\I#tqt^1MM:JqJ`0qh4nGK`6[Zs8I]Us+ULQKn]L*&H24OTC:=3M04ZUeaK9d
+o_n.Vs+M8Qs8Re,rq1W<i7YAoG_rKOmqR0#KSBI'K`V5)qu8AJn'@TndAD\?@8BKa;Ik!0Z.\'6
+g at Y@Dr:/7.n("LrF^n9A78RH9M6#1qT%*?/rVn;FpuT-,i4G(uJssdGP]Z)?K7nl=pO\"ho7;FB
+Isuk,I=CR8K7oH>o)F4~>
+n,FF-p>2t*kht+?db<[EZrCOOE,fo=qf;W5F8g6%s8I'Cs)\5?F*%<[&H24OTBk[tf?`(+kNenr
+o_n.Vs)T!/s8R.]rq1!*f]_8Gd+ at 1<lW at h>F*%BYErl<fqu8AJn'@Kik2+\7ZZeT0K>,^bi98jm
+g at Y@Dr:/7.lf[0WcaeL::jfe!fAGcWT%*?/rVn;FpuT-$l/C at EeD0-OL19=cEH6&MpMk0Eo5AMa
+D/=%KCM`BWEH?cZo)F4~>
+n,FF-p>2sr\"T:rX-fcs`N6Yga2lBEqoSd7b5TQ+s8L.Es2tBAb0'\_&H24OT?O^8S@"iY[EPE!
+o_n.Vs2l/)s8U6arq4(,bdX:8Z(7Jobcee%b0'b]aoVP0qu8AJn'@cOZCIMq`kJmm^rWdMTsr7E
+g at Y@Dr:/7.bdF(5[)]qo]"c:mSY!75T%*?/rVn;FpuT-,]V_$rUR/+$]Xd4HaN;NKpW1DIo>\bg
+`5BLQ_Sbc]aNDlso)F4~>
+n,FF,p"QG6eZ=UMF,-X?h/I4SH[^Hom""TrK(X_Jq>Q$Nre:CPKn]L*&H)(IS+"n/M04`]g$klm
+p&47Ws+M8Qs8Re,rUkK6n("LrFc!0LmqR0#KSBI'K`V5)qu8AHlc,jfad[p$>Y at sb:h"R(X4?[/
+ddd87qWc%tlH,NJDd5q3787*.KqQ]XU!<$&rVn;FpuAj%i4G(uJssdGPB#B,It)p(iSJq6eTc7[
+FE2B2EHB?NItIULo)F4~>
+n,Fa5p"QG2kMOn;cIUk7fO.rqBl%X'lu)=`E:n3jq/ULsrcA,>F*%<[&H)(IS*T7pf?`+-kj,,"
+p&47Ws)T!/s8R.]rUjm%lf[0Wce%(;lW at h>F*%BYErl<fqu8AHlc,UajP88/VJ&%nI(7MShrj<q
+ddd87qWc%mm,ZsObbf'$:i<>Ye_T?SS^$U"rVmE-puAirl/C at EeD0-OKj`^8D&$l4iSJ;$eRi?%
+ at UWWR?X_/mD/oL#o)F4~>
+n,Fa5p"QFh[@`tr\=]:s`iQMZ^r++/m)AJba7[Npq8pb$rlY9 at b0'\_&H)(IS'8:4S@"cZ\'Lr*
+p&47Ws2l/)s8U6arUmt'bdF(5[%3erbcnk&b0'b]aoVP0qu8AHlc-0IXd>fs`P&[k^W3^PT!ce4
+ddd87qWc&(`3#B$^;[e#]"Q(pTpi4+Wm0u/rVmE-puAj%]V_$rUR/+$]=6Sp`"g20iSMB&e\/T+
+\[])X[^aPs`5qlDo)F4~>
+n,Fa5p"QG6eZ=UMA93O'dG9 at fDK9iAaEGnYHJ*XmjaVi5q1S_HKn]L*&H)"BU[?="Km\uni8L]k
+p&=:W(kn1Rs+Q1*oQm;$eZ=UMM6#1qC3kJbL&_%(!WUaKs"XNJk.J4b^ls4_=[u+a93cCeR`Ocm
+amAm&p>NEti4G(uBiePK<_H\9JssdGUr;QprVn;FpYrU!i4G(uJssdGOD;JJFE;K4Z`\,>Sp-Kc
+Pc_pC_T/`rGCK;:o)F4~>
+n,Fa5p"QG2kMOn;^<Y<dk1O`U>[V#NaCNWGB\@*7j_\pTq/ZH6F*%<[&H)"BTC(are^E11l.N)l
+p&=:W(it?0s)W8[oOt#ckMOn;fAGcW=D2YpF8u,Y!WUOEs"XNJk.Iq`inDl)R9F2aAu3`$guRgr
+amAm&p>NEll/C at Eb*&U2O_1H6eD0-OT#BpjrVn;FpYrTml/C at EeD0-OJQTV)@prcTZ`[K,SnEk6
+L8DPq\%\_FASq1fo)F4~>
+n,Fa5p"QFh[@`traL at e3ZH';S[(!TWaLfdI^Y-E=ji#0Zq8rU8b0'\_&H)"BX2hH5TrXQX][3\6
+p&=:W(s:5*s2rL_oY70F[@`trSY!75YeS6$b5_@]!WVQbs"XNJk.JCBW0XC$_n3Rh]YqR[Q`\33
+amAm&p>NEt]V_$rahl!:_S!h%UR/+$Y/KW%rVn;FpYrTu]V_$rUR/+$\$3Qb]"#5ZZ`^U/T!Z5F
+]X>\rai:`q]YsR2o)F4~>
+n,Fa6p>2t at eZ=UM at pjA5VU=eg_3:+KVj4$IC8Gcc]6/@Fk(*1&Kn]L*&Gtk;WTqTpK7&cli5)VS
+pAXCX(kn1Rs+Q1*oQm8#eZ=UMM6#1qC3kJbL&_%(!WUaKs"aTIi3L8Y]9%DS=%c at _8Qoq\Q,Mje
+^ZYCho%'Vpfs-K\AR&nkBNA5MIZhJ,\%Lhtrr2p5rqGBY`8J7hI"Ig.lAAo;Vj*CN`5KOlmf;eT
+l2^#Gi!/K*H[+r+rq$/?~>
+n,Fa6p>2t<kMOn;\['N3hWF4X[Y0BiTST51=J]5-]45Gek&9tjF*%<[&Gtk;U?psreC*(0l*mkR
+pAXCX(it?0s)W8[oOsubkMOn;fAGcW=D2YpF8u,Y!WUOEs"aTIi3KuZiS)`&P%K)R?_5HigZ.Ur
+^ZYCho%'Vikht+?^ST&uacVt6db<^GYIrulrr2p5rqGBY]BS;.da[(5m!MKmTSA/t]XtcSli$/M
+li$&Pm+H,cmEGS$s*t~>
+n,Fa6p>2sr[@`tra2YT\S?g2ZaLf*uZ+d9/YGJP3]=P\kk/R,lb0'\_&Gtk;Zc&u4UT9cZ]Z%)3
+pAXCX(s:5*s2rL_oY7-E[@`trSY!75YeS6$b5_@]!WVQbs"aTIi3L85VO+@*_S!Xr]YhU`Q)hd0
+^ZYCho%'V[\"T:raMc6.b/2'9W0XBs]tEJ%rr2p5rqGBY_n;k5X.u#``3Q/5Z+[ch`5BIkbQ,fb
+_uR[Q]EZ=!\@q:orq$/?~>
+n,F"!puK'(i4G(uBjP1gLSi>Li;Dj?mJZJ]_8V[aD81>TmXp2lrr3Q+m)Z*iad[p1OLjAdZJbKV
+lMhZas8Re,rUbE1n("LrFc!0LmqR0#KSBI'K`V5)r;SPNo at Tqufs-K\AQW2H>YA+2I#tqt_mA:p
+q!6%omEM>YEF3C,M0ru;BRGoQi5;n[p\t0l&,u=]ZGYV4OF1tuS&ssamJcANjSn*:eH""raT09X
+]*?C5d;e*jrU^&>~>
+n,F"!puK&rl/C at Eb,_hnf&#NPl29lJmJZ>Y[_7E.>ean1mW!:Hrr3Q+m)YjdjP885g>V;+ZJbKV
+lMhZQs8R.]rUactlf[0Wce%(;lW at h>F*%BYErl<fr;SPNo at Tqnkht+?^R1k-V.Yq4db<[E]<gGh
+q!6%kmH*0Sc)f%8f@%d'ajSo%l+=:\p\t0l&,u=]ZFfA[g="3pguRhfmJcGPlMg&Ik5aZDj8e6=
+i<JB,aC!lIrU^&>~>
+n,F"!puK'/]V_$rai29/T:E-p]_o\Ja8O3iaMkj"ZbO35m`<NLrr3Q+m)ZHMXd>f`R&7O8ZJbKV
+lMh[Is8U6arUdk!bdF(5[%3erbcnk&b0'b]aoVP0r;SPNo at Tq`\"T:raMYs:`4Wt0X-fcs_R&1o
+q!6&#a0;#+]#DgmSZBoMb,^o,]Y_#6p\t0l&,u=]ZGX>PQ`IiqQ`\3Ma8X!W^](nF[/dN3XT5F#
+V?X06bdQHlrU^&>~>
+mf*jpm*(7Pc(Ti:EGB$*LS:ubr5er`rRLr+*U<(NY'IS+IY.Irs8Vr]`i&+DRtH*M]&:E3iV3?6
+rtC+bo[oo,eZ=UMM6#1qC3kJbL&_()s8N)Mr;SPLn'@TndAD\?@9dDeDd61NGDi`Zi25/to]!Ek
+jM6t.CN"T^X,q^BA9Ws:g#/jap&4mi&,u:[YJ];1OF1b\Jt'm4c2Pfb_#CtFX8o-sRfJ`PO9VB&
+m>BH;r:Br=~>
+mf*jpm*'_Ajk\J7c-*iHf%o9Cr8[k>rTF4Fs6L]XVJ3ThCiK:Ns8Vr]`h;\Zgsjd+iT[kZiV3?6
+rtBJPo[oo(kMOn;fAGcW=D2YpF8u/Zs8N)Gr;SPLn'@Kik2+\7Z_bUdbb]s+d+I:?fr!Emo]!Eb
+lJgOHbKSDghqHN$^<kNjkh2rip&4mi&,u:[YI`uWg="-feD0-Jjo4<@ir7p9hZ2O4g]6+-g'6Bp
+m<[=%r:Br=~>
+mf*jpm**&]YaV8g]>hq$Ssl at Mr2ft'rO)[<*Q6+E[^EZo_oMZRs8Vr]`j!C`Q_UUKVS'pUiV3?6
+rtEQRo[on^[@`trSY!75YeS6$b5_C^s8N)dr;SPLn'@cOZCIMq`l-!+^Vmq/Z(%GrbGNq_o]!Ep
+^SmHs`P8I at SsZS$aK_5.\'1i+p&4mi&,u:[YJRrLQ`J6BUR/*jYl:a)W;`[nT)bD\QN3<LQNin_
+a1Ts_r:Br=~>
+mf*jso\XW*i4kqFKmn5cF+oR7r0m\[rN-%2*Qc^^kO,mVFF<TSrr2c[`i&+DRtH*M]&:E3iV3?6
+rtL1co[oo,eZ=UMM6#1qC3kJbL&_2OL&_/Qf)>V)rqYfrV<Z0lK5Y",H&7,k>[VW.VU=h'cg:)O
+VVp.4N-K8gOLhF&OF1bbM6#1qT at EH0rr3N.p"ZS*fs-K\AR'/*S#i=_RfJZOOT((:L]2o+JGsp$
+JssdGQdEnQoDa=~>
+mf*jso\X#cl/LOPe^DghcILS$r7h;.rSRY6*TZAHlg1mP at qtN0rr2c[`h;\Zgsjd+iT[kZiV3?6
+rtKPQo[oo(kMOn;fAGcW=D2YpF8u:=F8u7?d/Eu#rqYfrT'YOneBFf.dFZmlV6S=shWF0ocg:)O
+VV11kf[.jjg>T*kg="-ifAGcWT at EH0rr3N.p"ZS#kht+?^ST0(gu$reh#5t+f)XD$e,[tsdKe:W
+jQq`M`;K6,J,~>
+mf*gro\[+"]Vq9eTr>6.\"T;gQN3KQTDtc/Xg5FQb.ja`_=7=#rqbs#Yf*Z1UT9cZ]Z.>;p\s=T
+'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8N)drVn\Qq<>f"`3#B$^;\3sSYNp;`jhY2ZH8iem-`K&
+bdX:8Z+m?,VQH__X3.f?T!ce7eFNP:rt#,%goAT-Tpr=.`4i"5T:5bG!1*VNrgWt[rhBIiri6:!
+Q`\3 at d,Foos*t~>
+mf*aqqX/WG_W8tMTTY4eK)U/qK)gW(M>rYXS#3I/dH'5?Eng'ZrVGj"Vs;BnK7&cli5)eZp\s=T
+'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Os8N)MrVn\Qp>NEti4G(uC2\BXUmcmR>]54_aQfS<jQ=OV
+mEM>YEI<kZi.J;HOF2&%TZuktbjPB-rt#)$g8=>hXGM(0;-\$lM1tq]!.Oops)n<g!.b'#reUiJ
+c0C\FbP^u3J,~>
+mf*aqqX/!#\*E)6h:gN3eGdnoe,\%tfDjPFgtpuLk3CWD@,(/HrVGj"T^:apeC*(0l+"+Zp\s=T
+'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)GrVn\Qp>NEll/C at EbKSAebhU^lV9IHEjQrJTjQ=OQ
+mH*0Sc-k>)l$'>ig="6rh<"$pbjPB-rt#)$g8=3!hq-2bI\k9<f at BlM!7Uqqs3L\m!7UqsrmqA0
+jm7iQ`Vf?-J,~>
+mf*aqqX2)'ahP'TR[0G:U].=lUB%"dSGnipS>!!h^Wa6tg[G";qWl/*`3#B$X-fcs`jF_!roX4p
+b5LtbU<L$;S@"iY[EPkia3)R)s8C+?rrDHbs"jZJiO-S9VO+@'^TNurQ_V:5^S at -t`3-u<k/aLA
+YaV8sX-fcsWO/OhX1P'oYfEcfmed"`&,l1TVTcH?S@$>O`4i":U&LeeW;`jt[/R*+VZ*@iSHbFb
+`4sd\r:Br=~>
+mJd^qpj[O*\aA4t^TjH#OH>CuM#`>1K)U-<K85DNVSLmPQ+GfBqYBHsVWu9mK7&cli5)e[p\s=T
+'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Os8N)MrVo=bo%0_rfs-K\Dg at AOR%p.&DeON[]&:N6g"NpF
+jM6t.I#tqtnQ!<]]9%DlR`Oci_Wgprs8W&ifq\#dXGM(0;-\$^H2`3jJcLN(M>iS:Q2[6OWs60&
+oPWI0rU^&>~>
+mJd^qphaVJZ0gc:io&YJg=k3Wf)XD$eGdl:eCN:,hW!bdLUu=4qYBHsT^:apeC*(0l+"+[p\s=T
+'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)GrVo=bo%0_kkht+?bgG,&R&f#lbfS;eiT\"^g"Np=
+lJgOHdb<[El9quCiS)`0guRgm_Wgprs8W&ifq[lrhq-2bI\k97dJhSne,\%ufDaJ(g]$"-hZi',
+lWi5drU^&>~>
+mJd^qpr'kP^;mghW1fZHR$aB at SH,;]U].;7URms?S>`p;]t3%jqYBHsYJdQ0UT9cZ]Z.><p\s=T
+'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8N)drVo=bo%0_]\"T:r^TO!"V5]fV^<3LDVS'gRg"NpK
+^SmHsX-fcse=4FiVO+?YQ`\3._Wgprs8W&ifqZd!T:E:/^VmmoY5YL$UB%"eSc4uVQ2[-LSd)(4
+gp>etrU^&>~>
+m/IRoK7A0UL=#>Kg!.UL]!;16!2faa+HVV=HujO_LQf!flD_V\p%[glVWu9mK7&cli5)e[p\s=T
+'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Os8N)MrVo=`mE;6kc(Ti2H&f>hKr2t]Jo>jkZ.\'2bfcd>
+fs-K\JssdG_-N&cad[p1OLjAg\E!A`s8W&ifV7ibXGM(0>]54NNrG.>RK0#[X8][1`;[jWeHXt!
+QZ_N>rq$/?~>
+m/IRoEG]?tGK9+9kiLmaiSaXk!8d_1+PPN"da$4gf%T'Dm%_DXp%[glT^:apeC*(0l+"+[p\s=T
+'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)GrVo=`mE;'fjk\J3dFmLBHCj3QeBH:li98jibfcd7
+kht+?eD0-O\4hD=jP885g>V;/\E!A`s8W&ifV7]phq-2bV9IH at g&B_)g]610hu;R7j8S-=k6C2<
+M.>bmrq$/?~>
+m/IRoaMbg%\]`%.\$3!3VP3pZ!1a%T+IJRhX1, at 1SsH(S`3R5?p%[glYJdQ0UT9cZ]Z.><p\s=T
+'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8N)drVo=`mE;NMYaV8sY*l&rV6m at kUV="&Tsr7Abfcd*
+\"T:rUR/+$_kXWXXd>f`R&7O6\E!A`s8W&ifV6TtT:E:/`4r(<RJrTQQN3KRT)PSeX8]7#[0F:a
+^UiXmrq$/?~>
+li.EIK7Mg$DMG[ZmHWWfg&0A#dJh30]!eJtHt[A<IZ1/OhPJTcp$'GllH,NJI#tqt_6r:sroX4p
+L&LYrU at 6X6M04ZUeaI7!JqSjXs8 at ZOrrCXLs$m"_jh7eZ`0GjuNjdd5>E%jhRtGd;VU=h"]==F!
+c(Ti2JssdGS7RiJad[p.NjdcjXPNRJs8W&ifV.caXGM(0Dh=FY[f3l;a8jKaec+J,kPjcGmfg[e
+F+!T/o)F4~>
+li.E8EGjWC>^*F*mHj*%kksTDk5OHAi?$k0d`TeZe(EO>g8!$]p$'Gfm,ZsOdb<[E\@(>jroX4p
+F8ba`U?h""f?`(+kNc5`E-$+#s8@$=rrCFFs$cq^jh7MVj4i&1g#;/[97H6ggsjX#hWF0k]==6q
+jk\J3eD0-OQ;`J'jP884g#;/:XPNRJs8W&ifV.Wohq-2bbgbG*rSdb:!9O4CrojFKrp9XM"hf1j
+C at faAs*t~>
+li.F:aMm#I[(3loa2GX'\,<W6ZMpsKVPBZKX3/;gW10<_`i at DPp$'H!`3#B$X-fcs`jOh#roX4p
+b5LtbU<L$;S@"iY[EPkia3)R)s8C+?rrDHcs$m"_jh8(=X-KNaRA7 at AR'af6Q_V'_S?g8/]==]X
+YaV8sUR/+$V5h,FXd>fcRA7 at 7XPNRJs8W&ifV-NsT:E:/^S at -eU]..iXT5U)[Jmf=_Z%LQbQYtt
+\\[n'o)F4~>
+li7!=$\\/%HZm!"Um/^2i;E$Dmf)Joi8)elOF1bNCOVG]jLD\VnE7]clH,NJI#tqt_RAM"roX4p
+L&LYrU at 6X6M04ZUeaI7!JqSjXs8 at ZOrrCXLs$ltZgo\u[[Z5ZaQ,Mk5ARFoVXGM(OR`OceV4b6W
+^ls4rP/$)KPAFh!eZ=UMM6#1qT[iW2s8W&heXl6[XGM(<Jssd2h>Z at 3l2^5Nmgm:N_4m0YQCDZ,
+]Q\dTqpk9;J,~>
+li7!+$ZblVBk=lTT8'h`g&117llbQVk2G%Bb-T:>g>_D%\)6]<_k-5Ugsjd+iT[k\j7rW9rtKPQ
+o[oo(kMOn;fAGcW=D2YpF8u:=F8u7?d/O&7rUemIb3 at m<dF6k1lc3"#lf[0Wcd^b2m$X]CXm4p"
+e'ct0lKXR:;sWW(f?`(+kNeeko)/OfrU\R2lf[0WccjnojQGb+l2L#LmJcD^]!o/6KnbAP=^8UN
+CN'*ro)F4~>
+li7"-$H_qY^q at 7XXh;`qqof&^rkoql]!A3#X3/H$W0XBs]slngkJOI at Xd>f`R&7O9[c@/^k5Q.<
+rUea:bdF(5[%3erbcnk&b0'barQ>0?!:Bdc7fDu7Xi\/LRBEEPX2<2WV9H?>S@#&XXi.38TY%t;
+QDgaJW5$rJZ)Z$UT:E9ZT!ce8eaiY<s8DQ>T$4U7S@$&+Q`[[,rk/6K!6>)_&&H?.^q7:oS$963
+]Y_\cmIL:-~>
+li6s<2#W&YJE5FsFE)5 at ChmdZBqD8fTu#(Ci4G(uBjc";VU=h+cfjE(U?]jiK7K6*kJXplq#9FU
+'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Os8N)Mrr6C(n'RfrdAD\?KqQ]XTl+Jgh6r>iI#tqt_23g5
+eZ=UMKqQ]X\#XO`i7YAoG_Mg8m at _Yiqu?]on^<lpeZ=UMJssdGn'Ake_3:+KUM4MBY&A<#FEMfU
+H at 4h)JqX-So)F4~>
+li6s*2#VE5DWKN]@UNJQ>$4t$=.>q=S%$E(l/C at Eb-B7ChWF0tcfjE(SF#=leC314laaReq#9FU
+'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)Grr6C(n'R]mk2+\7e_T?SP[7>0l/C=Cdb<[E\VYt)
+kMOn;e_T?SYH)&5g$%AHd+-t6m at 2;dqu?]on^<llkMOn;eD0-Olc-NF[tTQlSl]'nY$PID at Uiut
+BPQXHEH;'*o)F4~>
+li6t,2#YM9`T5ar\[SrOZ*:I+Y+i57WlW?)]V_$rai:i_S?g88cfjE(X2M-,USa<W_TKFMq#9FU
+'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8N)drr6C(n'RuSZCIMqTpi4+^oONY\tb[rX-fcs^km]f
+[@`trTpi4+^8n`HbI=17Z([Vja/I2Kqu?]on^<lM[@`trUR/+$bf[cCaLf*uX0/\*Y-k^J\[oH%
+^VT$NaN=GKo)F4~>
+li6s<2#i8_K_Y2kIsud#H[:"iH-j`V^2IeN^Yl_cHtd>EP/$(g^YmtZ`Se at iI"Ig.lD;5Xq>TOV
+'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Os8QW\s8W)ol,0 at _ad[p&KqQ]XKQ_1:jM6t.GDi`ZheJ;=
+ad[p&KqQ]XT"oMd_r/.gI"7L#kH2M^q>UEkm`hftad[p7R`OcP@;2l`EH?5FcZsikhL'a#It3(>
+JqEcNKSBHWo)F4~>
+li6s*2#hW<Eqo:UD/=!3BkV23B at +h3^0Xs)[HZZ(d`Tb]g>_D'^YmtZ^$4M0da[(5m$YTNq>TOV
+'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8QWVs8W)ol,0+ZjP880e_T?SFCn^QlJgOHd+I:?fP6?2
+jP880e_T?SR_WK>]BS;.daQt2l_VAZq>UEkm`hQojP887guRgM:fsl,?t!PUcY$qGhJ6nCD/O:^
+E,kYnF*%B.o)F4~>
+li6t,+TKU,anYMj`5BI1^q[Y9^<k'7^9t24a1S:9X3&A[QDjet&E)EU`Or(7X.u#``4itKq>TOV
+'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8QWss8W)ol,0^CXd>fpTpi4+[^36X^SmHsZ(%Grb%dEa
+Xd>fpTpi4+VnfsO_n;k5X/;/__R at 5Bq>UEkm`i,WXd>fXQ`\34Vm!82\%'#]cb at 0KhSR.I`5Tad
+a2n%tb0'bOo)F4~>
+li6s<!<<%P#6+S\KS+o=rdlKhJai)WkBqQiBY`Q<OF1bfNjdckYLhI8`8J7hI"Ig.lB]<OqYoXW
+'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Os8Q*Ms8W)li3UA[]9%DfOLjB?BmjudlH,NJEJ:(1m;TS[
+TnRK8P/$):VU9^0\E(GhIXI6gi5;kXpAP!fm)c3kad[p7R`OcUD0FZ^IXZcsn:?2apAT^DKEM.*
+L&V(*!WUaAs*t~>
+li6s*!<<%>#6+SXEcH)Lrbs4VDt*13kA"YE<jq8Og="-kg#;/:YLhI8]]nD/da[(5m"rUDqYoXW
+'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8Q*Gs8W)li3U&[iS)`.g>V;]=)D<!m,ZsOc.1Y3m;0/k
+h:9cug>_DNVU9'aYj16%e'ct/l+=7YpAP!fm)c!gjP887guRgR>@lQ)Ci+$,n8E:=pAT(2EWc5\
+F8l/[!WUO;s*t~>
+li6t,!<<&@#6+SkaiMQJrl6AX`piE7kJ=mIY/e2PQ`J62RA7 at 8YLhI8`4Vt6X.u#``4<bLqYoXW
+'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8Q*ds8W)li3U>6VO+?aR&7OGY.D'T`3#B$]:k[ta*G"q
+R\@<kQDhRHVU</e]t^M3W2l;_]Y^u3pAP!fm)cNNXd>fXQ`\39ZFnr/_o0L4nA`NApAW/4aTMI`
+b5VC_!WVQXs*t~>
+li6s<!<<%Ps8N)[re2ebKnY3YK`(_#q1=1VF(X=_Z&EpMM6#1qU!D2o`8J7hI"Ig.lBfKTqW7_k
+L&LYrU at 6X6M04ZUeaI7!JqSjXs8 at ZOs&IYMs8;H=U[Qa7M04?6`95!TJotereZ=UMEJ:(1T$<s_
+EH?o4dI+ERhL0LDlH,NJFc!0Ln"\J)r;QQYa/A4ERtH<]aQet0II`$cq>,dBKS9@(qh51QKn]P\
+rr2uLo)F4~>
+li6s*!<<%>s8N)Wrc8'lrc9CaF8YoUq/L?3 at T;"Di7QE&fAGcWU!D2o]BS;.da[(5m#&dIqW7_k
+F8ba`U?h""f?`(+kNc5`E-$+#s8@$=s&IGGs8;H=U[.+#f?_q#j6O-YEb&8;kMOn;c.1Y3RH<8T
+c-Fnsk3T+ZhJ6Snm,ZsOce%(;l_E&%r;QQYa.Ve[gsjj/jQqS/C[uK?q>,.0F*%?[qf;o?F*%A&
+rr2uFo)F4~>
+li6t,!<<&@s8N)jrlP5frlQPcb5D.Yq8gS7\Z<r`Tpr<oSY!75U!D2o_n;k5X.u#``4<kPqW7_k
+b5LtbU<L$;S@"iY[EPkia3)R)s8C+?s&JIds8;H=UWg-<S@#/YX2<&d^UpYm[@`tr]:k[tT<OcX
+]""B&ZH:.uhSQh-`3#B$[%3erbbNb[r;QQYa0<LaQ_U=BXi.i]_XbeCq>/52b0'__qoT'Ab0'b,
+rr2uco)F4~>
+n,ELhr;-6gKE2#NL&_/QjSji5PQ$7^s+ULQL&Zj[nTo&VjM6t.EJ:(1mA%_LYf,J3OF2YKaQf/4
+lh]`C'SZMXfV7ibXGM(VX4?ZRH at gg(s8W%Or;T at cm)ksfc(Ti2KqQ]XUN2*7D9q%HNd>>XKqZbb
+KlLLALSiJeHctZ'GFn6MVMB5HTZuktbjG<,qWl/!lH,NJJssdGPf8.JL&V)UL&Zj\s8VtM!rmt.
+r;QcJo)F4~>
+n,EXlr;-50Ec_6ZF8u7?i;RctKDop<s)\5?F8p<%nRu.&lJgOHc.1Y3m at VGHYe0/Yg="L+jQqfE
+lh]`C'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=r;T at cm)kgbjk\J3e_T?SQ=+lK>KH'fg!Rd`e_T?C
+e]kAEf&#QUD9M0\AXi&KhU^!&h<"$objG<,qWl.om,ZsOeD0-OL;e$*F8l1CF8p<&s8Vt;!rm=_
+r;QcDo)F4~>
+n,EXlr;-62aiaV^b5_JAoDZl4d/M06s2tBAb5]W+n\;BI^SmHs]:k[ta/m>/Yf",NQ`HmJXi.fj
+lh]`C'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?r;T at cm)l9IYaV8sTpi4+_RIFsZHKhSRBFZDTpi3S
+Tt87RT:E4/Z-2CM]VEWTS=[3`R]si3bjG<,qWl/*`3#B$UR/+$]Z%hbb5VDEb5]W,s8Vu=!rpEc
+r;Qcao)F4~>
+nc'.!r:faIk^J&6q1OHUs8V0ZK`I>9KdHbQs8RfQKn]8LEKTP.RtGX2R`Ocm_U#F'i4G(uJssdG
+R)nXjjo6$KrUea:n("LrFc!0LmqR0#KSBI+rIt4M9)eVI]Xd+=PC at M*TZukXG)CZeZK/fbIVW80
+KqX3??Yk7X`95Tkg at 9`?VXN':M04?6`948;kP>)Qlc,jfad[p7R`OcY`ddi=rr3.Us+Q1,s8.KO
+s+Q1)rrCX at s*t~>
+nc&ppr:faIk\Y3Vq>PI8rrD!VEr^jlF!^j-s8R0?F*%(k?\Ie,gsjQtguRgr_U#Etl/C at EeD0-O
+Mob8]jo6$9rUea:lf[0Wce%(;lW at h>F*%B]rH%r;9)eVI]Wg\\g=+<sh<"$IA9r$!VX!0pe'"i;
+e_Sd#XNT)Ij6Oiug at 9)pVX*F&f?_q#j6NPVkP>)Qlc,UajP887guRgV`bkQnrr3.Cs)W8]s8-j=
+s)W8ZrrCF:s*t~>
+nc&ppr:faIketH\q>SP:rrDZiaoKffasI)1s8U7Ab0'Iq[^sDZQ_V9iQ`\32_U#F']V_$rUR/+$
+]#a77jo6%;rUea:bdF(5[%3erbcnk&b0'barQ>*=9)eVI]Y;.ZQDhEhR]siB]>qdt`kSI<W5Z`f
+Tph[d`PSL;X2</eg@<1tVTcH?S@#/YX2;<[kP>)Qlc-0IXd>fXQ`\3=`l._rrr3/Es2rLas80q?
+s2rL^rrDHWs*t~>
+nc'-soB+WF^iO[Fl at O\Cs8V0ZK`I>9KdHbQs8RfQKnT/JE09G-RtGX2R`Ock^s/sui4G(uKqQ]X
+R*+gnjSonlo[oo,eZ=UMM6#1qU=b'NL&_2OL&M$DrUo!KdG;6kH at 1gci:1T.N.5u(mEM>YEF3$l
+KlLI-F,-X?m]V!!p at Wg>`8J7hI!h$ei5;eUp&+[P`hr%CRtH<]aQf#0J,4lurrn,VKn]R,qh5+O
+Kn]I)!7p`@J,~>
+nc'-soB+WF^gUbfl>^ics8V$VEr^jlF!^j-s8R0?F*%%j?\@_+gsjQtguRgp^s/sll/C at Ee_T?S
+N6:PbjSonlo[oo(kMOn;fAGcWU=aF+F8u:=F8c,2rUo!Kb3 at m<dF-b-l0;DaI;NM<mH*0Sc)e"k
+e]k2#cIUk7m&+X\p at W1,]BS;.daHk.l+=1Vp&+[P`h;\Zgsjj/jQqW at D>J>QrrmKDF*%B]qf;i=
+F*%9Z!7:<:J,~>
+nc'-soB+WF^pq"llH%)is8V]iaoKffasI)1s8U7Ab0'Fp[^j>YQ_V9iQ`\31^s/st]V_$rTpi4+
+]ZTX=jSonlo[on^[@`trSY!75U=dN/b5_M?b5M?4rUo!Kah"78Y,dqe][X1"b/Cp%a0;#+]#DY"
+Tt84_\=]:sagnqCp at Z8._n;k5X/hVb]Y^o0p&+[P`im=_Q_U=BXi.ll`;7XUrrpRFb0'baqoT!?
+b0'Y^!:B at WJ,~>
+nc'-kiPqq)a2=clc$k7ts8V0ZK`I>9KdHbQs8RfQL&18gCp<!9PC at G%R`Ocl^rr^oi4G(uKqQ]X
+MU(\gjSoeio[oo,eZ=UMM6#1qU=b(rrr<"P!WRlPs%<4Ze"6$YXGM(MQ,Mk&Dg[UsH#)m!XGM(0
+;-n6L:1/-uVU=h(JaWC0I_`,L`0GjqM6#1qT[`N/qWl/!lH,NJJssdGPfA4LL&V)UL&Zj\s8VtM
+!rmt.r;QcJo)F4~>
+nc'-kiPqjt^:9S9c"q??s8V$VEr^jlF!^j-s8R0?F8G at U>,:HCg=+9qguRgq^rr^gl/C at Ee_T?S
+IEq<ZjSoeio[oo(kMOn;fAGcWU=aG`rr<">!WR6>s%<4Ze"5mghq-3'gZ.V.?#"k-B3FQ`hq-2b
+I]UeqFg96ChWF0pEUN\uCquq6j4i&/fAGcWT[`N/qWl.om,ZsOeD0-OL;n*,F8l1CF8p<&s8Vt;
+!rm=_r;QcDo)F4~>
+nc'-kiPr.7`lc6+c,7TEs8V]iaoKffasI)1s8U7Ab51SWZ,=>TQDhQnQ`\31^rr^o]V_$rTpi4+
+\'FI?jSoeio[on^[@`trSY!75U=dNbrr<#@!WU=@s%<4Ze"4dkT:E9cQ)hdF[)'u+^9GhhT:E:/
+^W!e'^;d[TS?g83^@(jm_n`auX-KNgSY!75T[`N/qWl/*`3#B$UR/+$]Z.ndb5VDEb5]W,s8Vu=
+!rpEcr;Qcao)F4~>
+nc'-^a04poi8EeVW-3ZCrVtsXK`I>9KdHbQs8RfNKC at U-F5>6 at LN@BcR`Oco`65"GeZ=UMM6#1q
+DU\.Rp&><sr;6?dqYU6jq>V90o[oo,eZ=UMM6#1qU"4elrVc_LL&Qf)s%<.Ra/A4ERtGX5TZul!
+F+3lVHuHjZ]9%DS=&!$r>&8_S`95UOL at kE@JBOYRc(Ti2JssdGW6"<#q<Q%ulH,NJJssdGPfA4L
+L&V)UL&Zj\s8VtM!rmt.r;QcJo)F4~>
+nc'-^a/J at jl07NeV.FL`rVtgTEr^jlF!^j-s8R0<EUV\pA(g#$f$;LhguRgt`65"CkMOn;fAGcW
+?ISHBp&><sr;6?dqYU6jq>V90o[oo(kMOn;fAGcWU"4/ZrVc_:F8g7Zs%<.Ra._k\gsjQuh<"$i
+@;P]2C0e=5iS)`&P&IF at T$,U;j6OjiG4b_0DTeR;jk\J3eD0-OU<)Zrq<Q%nm,ZsOeD0-OL;n*,
+F8l1CF8p<&s8Vt;!rm=_r;QcDo)F4~>
+nc'-^a10:/]Y),+XLuKmrVuKgaoKffasI)1s8U7>aR at orYf<u=T!uJ0Q`\35`65"$[@`trSY!75
+X4-V:p&><sr;6?dqYU6jq>V90o[on^[@`trSY!75U"76\rVc`<b5TQ^s%<.Ra0ERbQ_V9gR]siL
+\AS(6_6h:rVO+@*_S*q&_nr:9X2</a_t<m(`QP7$YaV8sUR/+$Z,l8,q<Q&)`3#B$UR/+$]Z.nd
+b5VDEb5]W,s8Vu=!rpEcr;Qcao)F4~>
+nc'9SXPhXI]=Z#7iG<diqYoQ0L&[A9KdHbQrqqE>IaturhU/3UF(T]X[b^G5bKQ^LeZ=UMM6#1q
+E7a^[q>V!)rVQEao'PZ(l0e6 at rVuorrb)3,n^X9#eZ=UMM6#1qS'QTTo^qg.K(aiorVlfkjh&%`
+^ls4eKqQ]XKm&"Cq0mFMlH,NJDd5q0:1/-uVU=h8^P_gcr.3Fnn("LrFafLgjL;_]p\F-qVs;Bn
+K7]Q5lBK;<qM"qK"blu1L&_2MK`_:.L&CrNf(/ik~>
+nc'9SWnHRqiSih\fii$+qYoDoF8pmlF!^j-rqpd,Ct6(]g#h/BcG\,`iTTQ_bKQ^HkMOn;fAGcW
+ at +Y#Kq>V!)rVQEao'PZ(l0e6 at rVuorrb)3,n^X8tkMOn;fAGcWS'PsBo^qfqE;";KrVlfkjh%_]
+inDl+e_T?SG%>Leq/'Sqm,ZsObbf&mFg96ChWF1&^O#\Sr,:/\lf[0WcdLP,lE at e[p\F-qT^:ap
+eC<:7m"WMsqK)Z9"`s]bF8u:;EruA_F8Z%<d.73e~>
+nc'9SZH9MTVP^E'bd+t%qYp*/b5]ifasI)1rqsk._pu;gaKh>-\&ke at UUnmMbKQ^)[@`trSY!75
+Xk31Cq>V!)rVQEao'PZ(l0e6 at rVuorrb)3,n^X8U[@`trSY!75S'T%Do^qgsa7dUOrVlfkjh&4@
+W0XBoTpi4+\@]`Vq8BhV`3#B$^;[e"^;d[TS?g8I^W6-Kr5R<^bdF(5[&B:h^V%/=p\F-qZ,Ec2
+USF0X`4X+.qTAg;"j6kfb5_M=ao_Ucb5D8>mIL:-~>
+nc*OK[-uPGOH>aGkFupAn+bmrL&R9iKnT>Up@*O`FJtS`dAD\?@;LIZ`95R;eBafVeZ=UMM6#1q
+ES:!_s8W)trVZNep@@V6hpffb^;J=Un+chXq=jUUo^V+fQg`J+M04ZUeaJ@(GLtL"fm7s at hL4ea
+qu$0FYL217Nd?)7]&<*nH%GnjJ9ZA-dAD\?@8BKj?uq+#dI*XPNVi_RK&3]Ii4G(uH&f>hd&Ypm
+q!?,$lH,NJJssdGPf/(JL&V)UL&Zj\s8VtM!rmt.r;QcJo)F4~>
+nc'9DXR#',g=k<Al]tjkn+ba\F8ggkF&i*Wp@)nN@]5OEk2+\7ZcghPj6OdNeBafRkMOn;fAGcW
+ at bLDPs8W)trVZNep@@V6hpffb^;J=Un+chXq=jUUo^V+fQg<hlf?`(+kNdu6A_5Se;qYhuhJ;NO
+qu$0FYKH+gg!S7%iT]W0B5d_FDe<\Lk2+\7ZZeTUZ-LqWk3SV`IJa$BESdn-l/C at EdFmLBafF1f
+q!?+sm,ZsOeD0-OKu at j)F8l1CF8p<&s8Vt;!rm=_r;QcDo)F4~>
+nc'9D^Wa*WQ^<u<_SNXqn+cFqb5Tceb#S>[p@,uP\Yu4BZCIMq`knU<X2<8heBaf3[@`trSY!75
+YM&RHs8W)trVZNep@@V6hpffb^;J=Un+chXq=jUUo^V+fQcuk0S@"iY[EOK:][tfg;q\q$hSS[Q
+qu$0FYK=ANRBETXVS(E^^;g*J`kAb%ZCIMq`kJmq`jhY2ZH8leb5;2:aPO,A]V_$rY*l&raK+(e
+q!?,-`3#B$UR/+$]>VYab5VDEb5]W,s8Vu=!rpEcr;Qcao)F4~>
+nc'9;b4!l]M0t)UdGB"cfBCk=p at j[JJoL1-hpQSFL!f;8VMB5$?uLXcaQfS"h9hk`eZ=UMOLjB?
+F4p-[qYBp[oC)#,hUTfaYbA&-`lG$ifB`%tki(=Mf[S$HJa_-jM04ZUeaI.-BVD/pUMFYIER*V8
+q"!(5n("LrFaT:^i4s2VK)PX-JpVC^h6r>iB2q?'Ck.ehkL-KfO8]+XKB9bOjM6t.F,-X?m\%qq
+p[6;,lH,NJJssdGP.uJ at K`:rSL&Qd[rr)_I"T*k*rVlfr!7p`@J,~>
+nc*F?_!C1 at f@&7,k1O9PfBC_'p at j)WE,b8_hpPr4Fis+6hU]uYZ-:_QjQr5-h9hk\kMOn;g>V;]
+A(gGKqYBp[oC)#,hUTfaYb at es]t^>SfB`%tki(=Mf[S$HJa;LVf?`(+kNcc;<hZ7^;kmK!X^KH7
+o(_e.V!I4$f?_n!iT[dUBlO%LE+rRtl/C=C`JdH]bL>5+lc?3`J,TEHETOj1lJgOHcIUk7m%)Ml
+p[6;%m,ZsOeD0-OKthI!F8l.BF8g6%rr)e:s)J8>EcV-Xrr2uFo)F4~>
+nc*F?cciegSZABQZH'5YfBDD<p at lhQa2dYehpT$6\&l[rS=[40`kS:8Xi/)kh9hk=[@`trR&7OG
+YhAUCqYBp[oC)#,hUTfaYbAD=`Q,6qfB`%tki(=Mf[S$HJ]tNoS@"iY[EN9?Y+_Sa;kpS%XgcU9
+o(_e.Us-6=S@#>aVS'sU^rQEPa2#%)\tb[rahbO*_PWU!_U,F?bl.S at aQ:(S^SmHs\=]:sae[;P
+p[6;5`3#B$UR/+$]>)8Yb5VADb5TQ+rr)f<s2bE at aiXM\rr2uco)F4~>
+nc*47am[c\M03lpVU=7AX2DYthr*F?He$BWZ(@3,mG6$aLN?m+F+Tk%lJl]gjO'LdeZ=UTOLjAd
+Ems7=lK at 0_f?_FIY+_Mj_scmOi8F"D[FF'`_m?><U7RUANp=`UK5YmhX4?t5=OF+bi:--\TC1+(
+LNA'9aQgZ_I=qOuK77j9kJWX9D-KS>F,-X?m\IV[OT,:[K^6^ElH,NJDh=G!lD2;\p at -Ohn("Lr
+IZhJ,YdAcGK(o!4K(X_Io^r*6$A!`qJ:[ChrVliJo)F4~>
+nc*47_!C1 at f?_anhWEL#X2DM_hr*F-C":JEZ(?]lmHN`hf$:UhcICY1m+PXHjO'L`kMOn>g>V;,
+ at ajQ-lK@0_f?_FIY+_>^]BehKl07TM[FF'`_m?><U7RU;M!X3XeBH7jhrjb"=NRAUi:--\SF#Cp
+f$;e#jQsB`CN9 at QEGT'Llf6aKbb&=KcIUk7m$>EKJc>]LEpLf%m,ZsObgbG/m%2)Xp at -Oblf[0W
+db<^GV6jt*E;0)"E:n0ho^r*$s)/22DK#4DrVliDo)F4~>
+nc*47cciegS[>kuS?g5>X2E2thr*G/^t$]GZ(AVMa1ALFT!u_W\>,Cm`7D3;jO'LA[@`tiR&7O3
+YLD_%lK at 0_f?_FIY+_f&_p$'6]Y);*[FF'`_m?><U7RUKQc-"mUV=++T!e:9=0]X#nEnSub-IP/
+\"f:l`6Ga-aSu1[_mmP"X-KNu`4X+"T:E4/_nY?Zrr<#?lc?cXXd>fsUR/+$Xhs;qnC+,U[@`tf
+QDhR:[(u.Np\+=$ouG,Fo_li1`X)"O`qB0+rr;BVs*t~>
+nc)Y-^$jLPM039KLSiJe[@<=qYHkHOCnR8m`:*!Ic*j=$F(&HcF+Tk%lBlY.kg#aedAD\HOLjAb
+CqIj4`P/a]U7J-idI6Jci75rb]=Z>NZ*V*B]]&eWs69m3RtGWa at WdO/pXLeMmB4Okk/aLdad[p$
+JssdGPB25+rr7Y%GB`K&VMB5$:LJ7!VU=gVcgHtqs!`WjdV81#XGM(IOLjAf[,CTIfTP^RXGM=d
+]&:>mFOtothV<G1H@"5rrd"rtG^%>TGi%`Xqu51;s*t~>
+nc)Y-[-Qo4f?^qOf&#QUXI"rNYHkH=>+h:S]BehJjl,%HcEjdccICY1m#,>akg#[ak2+\;g>V;*
+>eA/$`P/a]U77dYb3SH\l0%-eiSinaWjB@;[+YBCs6L$PgsjQF\BidapZF'kmAS+ek/a:`jP88/
+eD0-OKjnn=rr7"VAS1;khU]uYGHoHEhWF0;cgHDas!`!XdT>bthq-3&g>V;.[,CTIfSo.Zhq-<1
+iT[b>@b5APhV;huBP?&Nrb)[PAnB.sBAVqGqu4t5s*t~>
+nc)V,`lti^S[?GHT:E40\tl%*YHkI?ZCmnn_p$'1YbRYY\&QG.\>,Cm`4NS3kg#pFZCIMeR&7O2
+WOp<q`P/a]U8"j)aiqfB]X=l?VP^T7\[/rJ_>DIV`!EK3UV=^f[%3f_[4Ai/\&dXmaK`[cQ_V9i
+Q`\3<\\uSgs2i6mZc]SDT!u_R`jhY2ZH9H!ma(n4.EV)-Y0=;GS@#>aVS'gRi:QTmWQ_cBS?&$S
+]Z-GOf>6A$gq_UX^Y%3<^C.ch]Z[t%hWjb1rpB:VJ,~>
+nc'0HRIA\,M0398F,-X?jR)E^rkh(<i:$+!i75rXToOhJA861.LP`(^`-6OKlH?0lad[p1OLjA^
+?]1/JV6.\_n*]K%h:9cg]<%KcOH?p,d?'OMjOsI]s2bP9K5Y!k<+:!,pT,mRg#90eh7o`Mad[p$
+JssdGQ$.\2s8Rb(H>MNmZ&Ep=<,[AWaQh5lh=Qm0s!`WngMGg$Z&EpMM6#1qUt5&,hO2^G[Z5Zl
+Z.\#UAuBONY,Q33CMTZ=rb;gTBU>]aLpG1^o)&FWs*t~>
+nc)8.O6budf?^q3cIUk7lL!oX]">S_f^%njl0%-dh:^?(^<=gJf%8gB]k;&rlH>shjP885g>V;&
+:Q(I3T;B3Blg4!'l0%0giSWGig'?U#acM\=lKJ0/s5XI at eBFe;MR_!apYRL[kh32lh7oNIjP88/
+eD0-OLLb:Cs8R.ZBj03Ri7QDkMTjT*jQsunh=Q@!s!`$]gKN:oi7QE&fAGcWUt5&,hNQ%FiRuW2
+i98d6<2X!*Y,PR!=]qJnrE'D-LnfcOZHD.squ60dJ,~>
+nc)Y9[*5qLS[?GW\"B1r^W4R at _Sa:4bfn5J]X=l:R[KkYaMt`sT:MR]^pLo8lH?NPXd>f`R&7O.
+S;WW<YI29hbf[l=]!\cCVOs3 at Q^=JYaH2S/^UO-Ks/cQnUV=^^_8ipRpR`t2\'2).h7p)1Xd>fs
+UR/+$]t;8*s8U6^^p;1nTpr=._7ub3Xi/Yoh=T(ns#A0ngTo&4Tpr<oSY!75Ut5&,hQY27URA9S
+Tsr3dXJ`D/Y,SY#YcsjrYct=7XhV3W]<]T<o)&FWs*t~>
+nc'0VN6pChNd>MP?uq+#^s1EcrSSpRe^;LNXIG6(H?!kGIYWcWX4>"cJq))3aJeCGRtGX,OLsHM
+n,MYikMY1HdE024XJ(o at M1^8)MlYCsFL1&DZ2C^'RfS.[raGtABP;P_M(>%9lEJOb\AdC<OF22-
+X4?ZQG_(PJs+Q)REO4`APC@:PDh=G!lBHDSq31gX,),dNE5LPFOF2&%TZuktbO"i\Tu,a"OF282
+Z.\U7d)!W:p$_nF#4:BQ_rC at fo)F4~>
+nc'-UK#m38g!S!WZHh%XioTA$kp,ETk2bLYgtC6*c-4M^f%8d9kI7I4D92%aU?psreBH at piT^@-
+s6LTgl07BnjPo.Uh:pZ8eC2juhrj<IX6S^&r87P0!S#?m\-'[kaj9_5/)94PWm0/*^$4M0da-P&
+kNc2]DfYmXF)bu&WTrKse'"T3eD0-OL19BBKDtlpF8+[#\EVu+d`p=ujmAV^m.98,\*;l*da6Y)
+kj.QV[^s'Cli-5TmFnMViq<9 at s*t~>
+nc'0VZcp"URBFEJ`j_P0W3E\@rOaAa[Bcp3T9kt>Y.DBTW1TWNT!cJ9^r5@#aK`[cQ_V9qR&7Oq
+bl>Tu_S!IfZE:(#T:2%3S>3$`S"@%3FLf/bU&:P_QN<kqrl5,_b0%*cS1Br.`4=.E\Ac+XQ`IKa
+T!ceF]uJ1os2rF"[_okYQDhd@^S at -t`4WYEq9]-@,0KZ>[E#qWQ`I`lR]si4bO"i\\B2C\Q`IB\
+Tsr7iaN268p!!ER#04rt_rC at fo)F4~>
+nc'0cRtpCUVMftKDeO3IPG,(drOX;ZXJVJKM1^+oFaSdtP,>;-e\H%JMh9 at BaJeCGRtGWmI#tu>
+ec3`.`4NIZVONd0M1pJ-Fa&4bMne?DB^aKQN;SP4K)foiFT?^[Hn9lHdI+0[e?m0P]9%DfOLjB?
+CjL\ds8RfLJ9?_9c(Ti2A:Tr`kMg9&nbeUMruZskl#`9Wad[p$J<e(9Xha,ll)U*7ad[p$GDrfW
+e_U5_p!s&`#0kigWQso-o)F4~>
+nc'-bOa-9ThUp<(bfS/]g>1Zai?R:<hV?i:eBuOedaZn&hV[JY\6I:+EQd[hU?psreBH(`g>W%o
+s5Y$WiSi\NgtLH5e^Msmd*gFrip,fBlf[0Xr7Ctu!6tJg!7CJf/C`P=m&8(V[(PY^g="F'iT]W2
+BlJ.ns)\$SA:3e+h:9cae(`pKfii%Yr.G"K*cq2B at Z'O5gsjQsgZ.Us^ut at SV2"?tgsjQpf\krU
+rTX"<ro=:Fkj>1kmJ?DRJ,~>
+nc'0c_RddlS=?C\^WO$WQC=G at rMCg5T:D77S>36u[&]smQCOPP[D]AsaN3T2aK`[cQ_V:;X-]^_
+[K!?GX/;YaS<oP0S=ud[['?[,S#F*RB[!lVS,AfVUB%q)ZiI9%X":$9ZH9W!e?m0,VO+?aR&7OG
+Z,"E&s8U7<`OiS!YaV8saJP6'_UPj)nbgc5ru]D[l++ at CXd>fsVNn4![_V(ul,(-PXd>fsZ(%Gp
+[CZ at MosOe$#-bSWZ-Mb5o)F4~>
+nc'0mWH+9hdBSspJp_c`IYEW=rK&7_M2-_2FaSXiM3+1,^X:TgUi1MBOG)'LbGsjLRtGW]Bmc$A
+XT+b,Q&q#_LP(&%Fa8 at dLP_+]X2!`#EpqP[M>_f(J:`B,rJ:N7oT1T#dI*ONf!WHS]9%DhP/$(r
+Dg[1ks8RfNJU2A*eZ=UMFb#q%lD8QNp\pBUruZslmWXTVc(Ti2I#tqt_m\Rsn$RH/dAD\?A9a'7
+XLA,?orS.^#GJT^e%=]9rq$/?~>
+nc'0mT4!H at k2>"HeC)^he(*('rRrLKf at JI"cdL7kf at o$;io]FXT3Z'nJ9&m$bG=LcgsjQ8b0o#C
+huDIKgY1?4f$r0rcdC1jf%8X2hr<ptEpMoGfDX,"e'umtrRV&&o\(hPk3SD[f!W0TiS)`.g>_D0
+?>FP%s8R0<DeNVGkMOn;cdU\1m$V9up\ogEruQ7YmU^h6jk\J3db<[E]XHhln#pHlk2+\7^<kNi
+hu2O,hu;C9h;RS@]B&bdoDa=~>
+nc'0mcaUU+ZD!PQUT:Z/W1f`LrKeauS=ZLV[&^.#SX>b8W3WhNX0fS)c,o5;bHo-hQ_V:4b,^m.
+TDt5pQ'[o/Sti6e['$I)T:M at 9SuBEEEm1q`SGfJjVPBo[rLEqVoU%/!ZH9;rf!WH/VO+?^QDhR:
+[DL#-s8U7>`kS_$[@`tr[&01l`4rh"p\rP=ru]D\m_$$LYaV8sX-fcs_m\Rsn'&2^ZCIMqaK_5,
+T;2C_oq25M#F_F!b.Ha0rq$/?~>
+nc'*rZ?pShmb,O`RZNG_Jq3]F,(P8sLP_+UR]F$@e`?/&Uq_5+pQC6[nC"9&c(Ti0C1q:.re^Z-
+(k@![H$k-oLP_%QR\m-saOTA/FcG>4Z','I"-o=DT`(nk[e.-]aOSk7gYKK]i4G(uI\tN\]5rFR
+L&_1,re#WFZK/fbM2 at 86lJlo1Jc#J2rr4'orUY>Wi7YAoG_1dQeaKa"o^on;_Vi%fIWojXM2 at 8l
+OS+J0K*R76eaKa"pAX[`J,~>
+nc'*rW+fV4m-*KfgtLE3eC49B,1G&kf%8X0gu%)OkN_E1U;(AZpOdP4nC"*!jk\J2bK7lSrn%2"
+(Xpg[dF-Lnf%8U/gtprIjQGg]A<#:+i;D:2gYCT?rSR5*/*,m<RbQZ1^$4M0daI"7m'L5=EHD0[
+F8g/pC8^@Vg=Os0jQtT0B5d\IKDtlmF8b]EAD-2)f[/."hrj=0ht6QO?ao:Yg="?nd+?n&rn@%s
+rmV2)hrj=0htI'@s*t~>
+nc'*rftb&#ag\=EQ^F87USdmg,,V-1T:M at 8Q_((V[D0huWP?3epX%(KnC"P]YaV9#`lcH)rga"`
+(o=:9Y,eFpT:MC;Q^jYEXgPpcZ&Qu:TpGYE"-o4>Rf/fXU\(E6XgQ]ggYKK\]V_$rW1:08`4<h-
+b5_LarlDsc`kSI<SXl1N`7D-+`r#e_rr4(_rU[h0bdX:8Z(mk][EPl4o^p_Cah4L;W3Nk;S=H#H
+Qh?mJUBd?][EPl4pAX[`J,~>
+nc'*u\:Aq>T&AebaL\XRR[*`2+-i:`VQ7;CaOT56hQihocf9S/rKDrco\?(sfs-KfIf+R4J:`B,
+M2 at 7SQ("SN[^sQ-e_o`LZZC,kVru=>rON*LaN2X)eH"Fti%+*MXL%-P`i\FBQ&q*)dI*cSmt?Dp
+s+UK+J:`(7dC-*V[`Ia4I=?hJs-*H^+GKgiIXAK`^lsA%TXs(OZJbHOaEMptdAE(bLOsu&I!>7+
+!."Qk#_8APh=.W*pAX[`J,~>
+nc'*uY&A$fS([,kjPf%RgtV\Z*o#K*hV[;OjQGdofqt?Jcf8q`rI]1;o\>qhkht+CqpHG4eC<%#
+f at em4gtprIiT0.al0R*$@pcL1lfI.)i</-$jQ6@'!9j(>/*tuiXm"ldU[-spg=kEGm%J%[Ec_9\
+F8p8uEbXn&iSWPOjQrUXCiTISKDtljF8krNCT?[Zg=4X.iT]X5i:cr_ASLMnhV-W5eGdkrd.P]b
+dJhQ"e(ipGlEB+=rq$/?~>
+nc'*uho<IFU<UQaXeqe^Q^.E7+-i1ZS=ZUVXgPg[ai('bcf<$drQr^Ro\?Un\"T:dW;N\8VPBo[
+SXl19Q'\#4USb0![CjH"`NZeU^r!=SrMB[tXf\i+[/df1]IUqCZ-):l`kK<jQ'dr/ZH9)Zn&``P
+s2tA``P8k(ZD4"_UTMJ>]#2Vgs3UcF+Nj]Y_mm\#W0X3RR\maIZJbHOhn6A>ZCI5MT;/?cX0M?)
+!3Z=%#c<r`]$de>pAX[`J,~>
+nG`s0KRr(&CnoqRi7ZN!`;7%e`5p$Ie_oNRn&(E2ER0%"p4S/"PD.Q^kH_PW^oNoer/_k_R[TnM
+X1#UXaO/Poi9Kaf`2 at ZsK6u$j_sQO`hui0-lL"Q=!7:PW0Z1`C`58R!cc#GDeW'"E`4EP$e]#+I
+p4S/"s+UK+Jr+Q8mG6=Ch<MtfL4P$Xs-*B\*rCJ?JDS\YR[Tn\m`*$(q#&EcF-Z%<^TjZ)P)tc`
+on`[/rf at DNR^VM2]&`YcoDa=~>
+nG`s&Ec9mW>*dk.l0.9jj8.^Uj5f:`kNV9ulb&!^@*`TTp2Y6SK6,B6kH:lNinrPgg)Jf%gtglF
+iSihXk3(smm-NE<TjqMPC!p\*mHXZ7"7,=?mJZ>PaL8PS[kPG'\%K5IB@"<`n(!$Vk2YFZjQF7g
+C\Dgjs8R0?F)cJ7M!aEhkNM9I[WZS0s8R`Lru1cQF)p!si8!,DiU".jk4nkrCLN%ck2P=Uh#?"-
+f_*hrg&B\2gYCcSah$R.rq$/?~>
+nG`sVai<8[ZGFc']XP2KX88\8X0&M0[Cj8mbeq,t\'MnXp;tJWd)tbNkJ>0QW1K?Ar0SFgQ^=/4
+Sti0`Xg5 at G]Yqq6`3HPV^qeC+b/_9q]E?$h`5hi#!m&F&qoCJ.aN2<A[C"97oC(5:b-J(FVQI8B
+]#+0`b5_Las2rF&\\?+q[C*Ta_7%8$aoDCfr;Ri8`k]"&ZD!VOR\n3S^ZP=hk/+XB`3Q>8S<oP/
+R%*c>!1EhR#aLaO`7)<Yq#9mbJ,~>
+nG`s0KnT*^H#n&*_;ObHkPF*YkN_@#n%cGuC:&,:II;^`rIot*PD0&7n\fXgjOM>dr44>qaN2WV
+e_T0HlL+,e_53cF\As8ONIgDKEJV6G_84'kPc0=NC29cLDYe9*[;^)AF0C>achd at tO-f:ti8EnI
+Y18(!Kn]R,L&Zj[NdPo(dI6POQFPP*K8'@*PPkG%rI]rTRd/SIaN`Q/HID9ZrmQFFEL#tQg!RmU
+]"50>WrTU-\d-0pe`rLFm/$;QJ,~>
+nG`s&F)pp:B45;E\(L'6lh]iGli-5ilaF$Q=L;R[C[Q0<rH!&[K6.(jn\AeIlK at 6fr8B-cjQ,Fc
+kNM0rm-O&Y\"B1#\Ar`.I;eFo@!T)l\$s#HKqW]l=BVT(>[@550XY4nI:9*ulcK"sk(JTXlfm[#
+afa04qK$`Xs)\3]Edhb3Gf]4:aG@@XI;s?.s+C7L*rU))D2moGjQ,FdltXu;qu4iYBjZ\_lKIBk
+io/kSp##`,#NOn.m"rsQqXXZ:~>
+nG`sWb/s;>^::DQaNVcE_YUne_SjC7bf at E1YdD!X_X>J at rQ<:_d)uCdn^Fke^U:2Br2(sEXf\h8
+[CX#f`6$6HaKD;B\AuJ(b/Wba\%BGoaN2<-]<SoLYHXt,[']V9+Lel$_s?I]p?''(ahk^'`5o+3
+`qmj#s8U7Ab/qiC\@VX_#emh#b/ha*s3U]D*rX1#]"GtjXf\h=ag]^equ5m#^p^u!^ULMNW2?Gc
+opu/Yrh]q$XgQ*^bj>2ss*t~>
+nGa!1Kn]L#JUW9nEGTluXi^IV+/5QrTVZS?Fa;npNe at 4^s8Re,s-*K_rqY&rDmSotjS[pakN_@"
+n*eT=U6Kk;DK3VAL#_KZK9Co_NI5ug]5V`#^N at SAG^=\jh>)FPidH6JI`RTGec,I;SooCU`knis
+e*;SaKn]R,L&Zj\Ob%q)EGi"#G2;SJKSBI+PPbA#qi6GYXPrI0mEp6&k4eiSeV&L#F*Y(Lmcrlk
+i7[eR!8[Y4#NtC at V/kMdrUTu=~>
+nGa!'F*%<TDesR;?Wq*9VSrA at +-iFQSY]W*A7sh;IW>7+s8R.]s+C at OrqXo^?)[)UlMTlqlg4!*
+lg)U#Q%ipS>[PFrG2qn;EIr6+I;3B3]3epV^LG;rB4tu5h.le%0]Hk`P\e3dq9T';o9*TuR(g).
+?IS1ZrH!&[s)\3]F+J7FARJcI?Y&!\JTGo4s+C4K*W(;0CSoeOm-Vl.AENXbs3G_(Bjk_Rg$J(j
+l07F)k5a`Fkm-P at l^2,=o_n@\J,~>
+nGa!Xb0'\X`l#[7[^*9F[_DX[+2G%mV5:Q4]>!4AbK0S's8U6as3UfGrqYTi[)U>.^\k_n_SjC5
+bfn8O^qI(YZaRg!_rL(+aNr!'b/(d/]=,/Z^U_J!^;%G;h8/s)0]KsdcGSSaq<\+Xo?=eT_o9a+
+[F=E^rQ<:_s2tAab0J#D]XP8P[_(A`cH=<0s3UZC*W+$u\@0W"`5g*1]B8kds6[qJ^pphlbfRf<
+]Y(`H[/df;]Ec<lbepsKo_n@\J,~>
+nGa!1Kn]R+KS,<NI<p.[_5dEP'le<6G1,&kk(&$VKT_&hL&_1,L&[A9s#'c2N-]QCWj9IZ_nj9c
+Pa-upCMn*4Fa/4[IHp9^p\L&,PD0!uJq3+II=:5?J*hc;JqE[hq1C6nK7g1Vdus^]s8MnoIX-(P
+FO#7#pOrR#L&_1,s+Q/jKS"`'I,B@&o_Oc*rr2t^qu7]9OcG4<G*nVtE-Hd'r;ZfJKnP#*G]InN
+Pd8-Bi:ZOHcbRB9UR%s&I.7"3o)F4~>
+nGa$(F*%B\EcHQoCM at D&_5:T=?N4 at H@Dud*fkTYeDt\4'F8p=]s)W8]KDtm.rRuX4 at Afp!\%KA_
+]Tn2+GFhuC?=@>UBPM>Jmsk*.JocQcrdf$,l/c\rjl^LJDf9T6p%J3$/GO4)SoN#-rm:]Eqj_J8
+A&2X"C$kY9s)W8]s)\3]F+\LPDJX(FCMre at K6.%l!/(1K*WCV=GK=BRM5O]lD"RZ*s3Ph-Deirn
+AS?gq\%:5blO1bA\%S)`X(,o6qYp'cJ,~>
+nGa$Yb0'b`aiMZk_SEk,_7@#R[K!ZL\Ac).ftlgi`qIO#b5]Was2rLad/O&&rU%_A\>Q[PaMYp:
+`5'!u\Xp(4[CEf]^VRePn'(P&ccXVWrm&R(l/fe!jlaSL`l?'>p%J4&/GR<-fZ<@)rpBabqpr[!
+]"tr&_!Um=s2rLas2tAab0\8N`P]OL_Su0Dd)u at f!7:WC*<+7,`5o:#^U1G^_t<m,s6[tN`koF!
+ZF%<aaMRSn$d6T3`500g]#!n4rpp)>~>
+nGa!1Kn]R,KnY]dK7\[@kg'*Ss*bXHJFW8`q1OG#Kp.5jL&_1,L&[A8s"<;nJUZ7pF)eXrE4U+4
+Fa)>]I!pHoJV&K+qYZNUs-&/#L&[?iK_kIrKD>7qqu26ML&V)IKc'iDKs$-\PQ056s8K*PJUcm5
+mXk<6L&Zl+rt'naKnY_EKS4u1pOe.trf`'8rrA8ZruI;cO6MFEGh%1lK)GWJs42mXKS+f(L3Ri]
+E3X7rrbE. at C20K<CMRa'DfE:/bh7GsqYp$bJ,~>
+nGa!'F*%B]F)us0EH#j_kfWg=s(iA6DXm@=q/UQUF+\Q6F8u8]F8pmks"E8\Df"(L@:-IN?b0ZT
+A7a8(C27X'DfB]9qYZ!Fs+>BFF8pl6Er,QNEVT?Mqf;[Ws8Mh8)#nYuU3"\6s3UfGrh+7LD<Pj)
+E;KNSs)\2>&9IkmF+\OTEcH*nEH;$WK6.%l!/(.J*J8oml$$cPeS8uAr;Q`rcuX8KEGoZ:An,7V
+Z!1E2=V at H2=JDQn=^#$8?FjUifkbX(rpg#=~>
+nGa!Xb0'bab0&',aN)<ekhZ0Rs2,N8`UWTAq8peYb0\<2b5_Lab5]ies"Erg`l$HP\@/iR[^ruZ
+]=cY._8=+/`lH0AqY\_>s3Sp8b5]i2ankeRaS>SQqoSi[s8Mi:)#qb$grf$2s6]jdrn>H5`9>/-
+a85bWs2t?@&Bb$qb0\;RaiMQtaN=D[d)u at f!7:TB*RN*Ul,:<Le\T5Gr;Q`rmE3SnaMu-8]t1_^
+Z*LY6YS*\7YbInsYd(L@[CWomfu(l,rpg#=~>
+nGa!1Kn]R,KnY`jKnP-Vq=so@(ANN7qLneFL&_1,s+QYjs+ULQKn]PjrVmSmPD"S[m='KDidKp;
+It3+ at JqAW-re1<*s8N^qs8S::PD0%#Kn]R,Kn]R,L&_+*s8VnK#lfU4Y(bGjs472L%'G;;K_^;u
+K`;"*s+UIP"GQl0Kp2Fg#6'=1s8S::rr2t^qZ$SZ#a5"EJV!BDKS9=(!7q+&$&!qlJUi2ti8&bZ
+HN2V.HJ$nsH@(!dIH>tHo7M_qnGe"~>
+nGa!'F*%B]F*!!6F)uC!q=so.(AMlhqJuN4F8u8]s)Wg6s)\5?F*%A6rVmJfK5tu'm;6Y!ibRXl
+D/O:_E;jkWErL.[rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^As)W7UF3oR>d/O%RU2t?qq/Z at R
+rr7'>F8l1BF8p<&KD]cprc</\s+>Clrr@]Js8R]WK)'q8Dt7mgF8c+=d/A"lEcHVJDJX+Hh.ck%
+s4 at Eef\'s;BaAHhj_aGWEH;'Js*t~>
+nGa!Xb0'bab0&*2b0%j'q=sp0(APtlqT8[6b5_Las2r^2s2tBAb0'b2rVmK$d)jB#mDQm%ikjfp
+`5Taea8X0[ao9H_rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seCs2rL>b3dRUmJd+ogrda\q8rNV
+rr:. at b5VDDb5]W,d/;#jrlWC`s3SpfrrCFBs8UFOchYi*`q%3mb5M>?mJY06aiM`H`P]RNh8'$)
+s4 at Fgf\+%=^^.cnji$TYaN=GNs*t~>
+nG`d+Kn]R,KnY`jre:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]%-3V+L&Ln$KD>4opk/R!
+!<)\Hs8N^qs8S::PD0%#Kn]R,Kn]R,L&_+*s8VnK#lfU4Y(bGjs472L!3Z<T#lfVYL&_1,s+UIP
+"GQl0Kp2Fg"oj:1s8S;]rrA8Zs8J2brfVqfrVhNLrrCXIKa*]nKS+pOpAKUCoE'X;p&0LBK*D%'
+qu)5&n,In~>
+nG`d!F*%B]F*!!6rcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M%,cbZF8buUEVT<Kpi6:R
+!<)\6s8N^as8R^mK6.'FF*%B]F*%B]F8u2[s8Vn9#leseU3"\6s3UcF!2BI6#leuGF8u8]s)\2>
+"EXTaF+aC3"oiXbs8R`Mrr@]Js8IWRre#63rVgm:rrCFCEs at 8;EcH*npAJt1oE'")p&8q0E<Z,X
+qu(SWn,In~>
+nG`dRb0'bab0&*2rlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E%.higb5M4YaS>POprNHV
+!<)]8s8N_Ys8UHgd)uC8b0'bab0'bab5_F_s8Vo;#li&igrf$2s6]gc!8RRr#li'Ib5_Las2t?@
+"Npbeb0^(/"ol`fs8UIErrCFBs8L at Jrm8d/rVjt<rrDH`ap-57aiMQtpAN&3oE*)+p&<#2a9D@\
+qu+[[n,In~>
+nG`d+Kn]R,KnY`jre:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]$fmM*L&_1,L&_1,s8 at WO
+s7h<Jrt:Oqs-&/#L&[?jL&_1,L&_1,s8 at ZOs7q?Ss+Q00L";Iff)G[LY5X+\s+UK,s8RfQL&V)T
+L&Zj\s87QSs+Q1,s-*E]!0d9Zrf[KbPD+_jre:=N!7q%$!0dA8s8MtNs8<"Prr2eK"oj;Vs+Q0q
+s*t~>
+nG`d!F*%B]F*!!6rcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M$fHYYF8u8]F8u8]s8@!=
+s7g[8rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^As)W7UF3oR>d/O%FUAf3>s)\3]s8R0?F8l1B
+F8p<&s86pAs)W8]s+C:M!/(.Jrdt at RK6),6rcA&<!7:Ua!/(5ks8Mt<s8<"?rr2e9"oiZDs)W8M
+s*t~>
+nG`dRb0'bab0&*2rlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E$hM`fb5_Lab5_Las8C(?
+s7jb:rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seCs2rL>b3dRUmJd+ch#>G%s2tAas8U7Ab5VDD
+b5]W,s8:"Cs2rLas3U`E!7:TBrm1fJd)sN2rlY3>!:B[+!7:\es8Mu>s8<#Arr2f;"olaFs2rLQ
+s*t~>
+nG`d+Kn]R,KnY`jre:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]$fmM*L&_1,L&_1,s8 at WO
+s7h<Jrt:Oqs-&/#L&[?jL&_1,L&_1,s8 at ZOs7q?Ss+Q00L";Iff)G[LY5X+Zs+UK,s8RfNrre&U
+Kn]R)Ka%L1L&_1:rVlk]qZ$PY"TO[>L&_.+rVllKqh5$6rIt:OrIt:O!ep[Sqh54RL&_1,L%#%l~>
+nG`d!F*%B]F*!!6rcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M$fHYYF8u8]F8u8]s8@!=
+s7g[8rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^As)W7UF3oR>d/O%FUAf3<s)\3]s8R0<rrdEC
+F*%BZEs;SbF8u8mrVlkMqZ$PI"TO*qF8u5\rVllEqf;airH&#=rH&#=!d"DAqf;r at F8u8]F79-Z~>
+nG`dRb0'bab0&*2rlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E$hM`fb5_Lab5_Las8C(?
+s7jb:rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seCs2rL>b3dRUmJd+ch#>G#s2tAas8U7>rrgLE
+b0'b^ap%gfb5_LgrVllEqZ$QA"TQikb5_I`rVllbqoSocrQ>0?rQ>0?!m:QCqoT*Bb5_Lab4#@\~>
+nG`O$L&V,PK`RD;re:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]$fmM*L&_1,L&_1,s8 at WO
+s7h<Jrt:Oqs-&/#L&[?jL&_1,L&_1,s8 at ZOs7q?Qs+Q00L";IcrrB5$Ka.R2s+ULQL&CrRL&Zj\
+s87QSs+Q1,s-*E]!0d9Zrf[KbPD+_jre:=N!7q%$!0dD9rr;qNs8N.Ss8W(P#lfU4s+ULQKn]!q
+J,~>
+nG`NoF8l4>ErgpnrcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M$fHYYF8u8]F8u8]s8@!=
+s7g[8rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^?s)W7UF3oR;rrAemEsDYcs)\5?F8Z%@F8p<&
+s86pAs)W8]s+C:M!/(.Jrdt at RK6),6rcA&<!7:Ua!/(8lrr;q<s8N.As8W(>#leses)\5?F*$gM
+J,~>
+nG`OKb5VG at aoTlhrlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E$hM`fb5_Lab5_Las8C(?
+s7jb:rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seAs2rL>b3dRRrrCjRap.mgs2tBAb5D8Bb5]W,
+s8:"Cs2rLas3U`E!7:TBrm1fJd)sN2rlY3>!:B[+!7:_frr;r>s8N/Cs8W)@#li&is2tBAb0'2Q
+J,~>
+nG`O$L&V,PK`RD;re:@OrIka]Kn]P\s8RfQs+UK,PD/u8s+LLRPPtLhjHG:Os8Re,s8RfQrIk7O
+pkAbJ&sN at qPD,3Ss-&.js8Re,s8RfQrIt:Oq1T%QKnZ[`es$%3!3Z<T#60DWL&_1,r;QqSs+Q1,
+s8 at WTs+Q1,s-*E]!0d9Zrf[KbPD+_jre:=N!7q%$!0dD9rr;qNs8N.Ss8W(P#lfU4s+ULQKn]!q
+J,~>
+nG`NoF8l4>ErgpnrcA)=rGrJKF*%A&s8R0?s)\3]K6."ks)S5 at KDkfXi.H)ls8R.]s8R0?rGqu=
+piHK8&qg5aK6)Zds+>B6s8R.]s8R0?rH&#=q/Zc?F*"'sd"D8r!2BI6#6/cEF8u8]r;QqAs)W8]
+s8@!Bs)W8]s+C:M!/(.Jrdt at RK6),6rcA&<!7:Ua!/(8lrr;q<s8N.As8W(>#leses)\5?F*$gM
+J,~>
+nG`OKb5VG at aoTlhrlY6?rQ5WMb0'b,s8U7As2tAad)u=es2kBBd/EtPo?bY&s8U6as8U7ArQ5-?
+pr`X:'%$[Yd)s_Xs3Sp2s8U6as8U7ArQ>0?q8rpAb0&M^mEke2!8RRr#62jGb5_Lar;QrCs2rLa
+s8C(Ds2rLas3U`E!7:TBrm1fJd)sN2rlY3>!:B[+!7:_frr;r>s8N/Cs8W)@#li&is2tBAb0'2Q
+J,~>
+nG`O$L&V,PK`RD;re:@OrIka]Kn]P\s8RfQs+UK,PD/u8s+LLRPPkFfPD+_js+Q1,s+ULOK`M/J
+L&_/cPQ1ZHKp.5js+Q1,s+Q1,s+ULOL&_2KKa.R2Ks$-\PPkF\Y5X+Zs+UK,s8RfNrrn,VKn]R,
+rIkFTKn]R,PPtL]PPY:aPQ-jHPD+_jre:=N!7q%$!0dD9rr;qNs8N.Ss8W(P#lfU4s+ULQKn]!q
+J,~>
+nG`NoF8l4>ErgpnrcA)=rGrJKF*%A&s8R0?s)\3]K6."ks)S5 at KDb`VK6),6s)W8]s)\5=Erc78
+F8u7QKE(t(F+\Q6s)W8]s)W8]s)\5=F8u:9EsDYcF/!a&KDb`LUAf3<s)\3]s8R0<rrmKDF*%B]
+rGr/BF*%B]KDkfMKDPTQKE$T(K6),6rcA&<!7:Ua!/(8lrr;q<s8N.As8W(>#leses)\5?F*$gM
+J,~>
+nG`OKb5VG at aoTlhrlY6?rQ5WMb0'b,s8U7As2tAad)u=es2kBBd/<nNd)sN2s2rLas2tB?aoMJ:
+b5_JSd/X-mb0\<2s2rLas2rLas2tB?b5_M;ap.mgb1t/,d/<nDh#>G#s2tAas8U7>rrpRFb0'ba
+rQ5<Db0'bad/EtEd/*bId/VJmd)sN2rlY3>!:B[+!7:_frr;r>s8N/Cs8W)@#li&is2tBAb0'2Q
+J,~>
+nG`O$L&V,PK`RD;re:@OrIka]Kn]P\s8RfQs+UK,PD/u8s+LLRPPkFfPD+_js+Q1,s+ULOK`M/J
+L&_/QPQ(R`Kp.5irs4>Ys+Q1,s+ULOL&V,KKa.R2Ks(I,PPkF\Y5X+Zs+UK,s8RfNrrn,VKn]R,
+rIkFTKn]R,PPtL]PPY:cPQ-jHPD+_jKn]I)!7q%$!0dD9rr;qNs8N.Ss8W(P#QKL3s+ULQL$ntk~>
+nG`NoF8l4>ErgpnrcA)=rGrJKF*%A&s8R0?s)\3]K6."ks)S5 at KDb`VK6),6s)W8]s)\5=Erc78
+F8u7?KDtlPF+\Q5rs3]Gs)W8]s)\5=F8l49EsDYcF/&]]KDb`LUAf3<s)\3]s8R0<rrmKDF*%B]
+rGr/BF*%B]KDkfMKDPTSKE$T(K6),6F*%9Z!7:Ua!/(8lrr;q<s8N.As8W(>#QJjds)\5?F70'Y~>
+nG`OKb5VG at aoTlhrlY6?rQ5WMb0'b,s8U7As2tAad)u=es2kBBd/<nNd)sN2s2rLas2tB?aoMJ:
+b5_JAd/O%Hb0\<1rs6dIs2rLas2tB?b5VG;ap.mgb2!$ad/<nDh#>G#s2tAas8U7>rrpRFb0'ba
+rQ5<Db0'bad/EtEd/*bKd/VJmd)sN2b0'Y^!:B[+!7:_frr;r>s8N/Cs8W)@#QMrhs2tBAb3o:[~>
+nG`O$L&V,PK`RD;re:@OrIkLVKn]P\s8RfOrrRn<L&M&OK`V4;r;R+fs+ULQKn]R,L&_+*!<;hJ
+qu6_OPD/o6s+ULQ!/:FPs+UIPrIkCSKn]P\rr3#MPPkFaY5a30s+UFO!/:@N%u(%;L&_1,s+Q1,
+Kn]R,PPtL]PPY:cPQ-jHPD+_jKn]I)!7q%$!0dD9rr;qNs8N.Ss8W(P#QKL3s+ULQL$ntk~>
+nG`NoF8l4>ErgpnrcA)=rGr5DF*%A&s8R0=rrR7oF8c.=Erl;nr;R+Vs)\5?F*%B]F8u2[!<;h8
+qu6_=K6-qis)\5?!-A/>s)\2>rGr,AF*%A&rr3#GKDb`QUAo:Us)\/=!-A)<%s.blF8u8]s)W8]
+F*%B]KDkfMKDPTSKE$T(K6),6F*%9Z!7:Ua!/(8lrr;q<s8N.As8W(>#QJjds)\5?F70'Y~>
+nG`OKb5VG at aoTlhrlY6?rQ5BFb0'b,s8U7?rrU?ib5MA?aoVOhr;R,Ns2tBAb0'bab5_F_!<;i:
+qu6`?d)u7cs2tBA!6Y<@s2t?@rQ59Cb0'b,rr3#dd/<nIh#GO>s2t<?!6Y6>&'Fppb5_Las2rLa
+b0'bad/EtEd/*bKd/VJmd)sN2b0'Y^!:B[+!7:_frr;r>s8N/Cs8W)@#QMrhs2tBAb3o:[~>
+nG`O$L&V,PK`RD;re:@Os+LUUL&Zj\rVlkOrVlqQPD/u8s+LLRPPkFfPQ-@:s+Q1,s+ULOK`h@/
+s+UFOs+U at M!elhlqu?\Ms8N(Qrr<"Prr;qN"TO10s+UIP!S3J4rr]G(Kn]F(!/:@N%u(%;L&_1,
+s+Q1,Kn]R,PPtL]PPY:bPQ-jHPD+_jL&:lMf)::(s+Q[9L&V,NL&_/SL&_2PKa7X3L&Zl,s+Tn@
+J,~>
+nG`NoF8l4>ErgpnrcA)=s)S>CF8p<&rVlk=rVlq?K6."ks)S5 at KDb`VKE$#ms)W8]s)\5=Es)G`
+s)\/=s)\);!cs!8qu?\;s8N(?rr<">rr;q<"TNOas)\2>!RQJsrr]"qF*%6Y!-A)<%s.blF8u8]
+s)W8]F*%B]KDkfMKDPTRKE$T(K6),6F8Pt;d/A"es)WhlF8l4<F8u7AF8u:>EsM_dF8p=]s)[W.
+J,~>
+nG`OKb5VG at aoTlhrlY6?s2kKEb5]W,rVll?rVlrAd)u=es2kBBd/<nNd/V8gs2rLas2tB?aoh[d
+s2t<?s2t6=!m8m4qu?]=s8N)Arr<#@rr;r>"TQWes2t?@!U\83rr_'Vb0'V]!6Y6>&'Fppb5_La
+s2rLab0'bad/EtEd/*bJd/VJmd)sN2b5;2=mJY0/s2r^fb5VG>b5_JCb5_M at ap7shb5]Was2sd0
+J,~>
+nG`O$L&V,PK`mV>L&Zl+s8RcUs+UK,L&M#OL&M#QKp.5hs8RcRs-*B\!gEY<rr3C\s8RfQs+UK,
+s+UK,rVunOqu6_OPD/o6s+ULQ!/:FPs+UIPrIkCSKn]P\rr3#MPPkF_Y5a30qu6YMr;R:]s+Q1,
+s+UK,L&Zj\s8S;]rrA8Zrs4hgPQ-i#L&Zl(rrCXKK`_:.PQ$:8s8 at ZOrrRoSs8I]Ws+Q1,L&_1,
+mf.e~>
+nG`NoF8l4>Es.-qF8p=\s8R-Cs)\3]F8c+=F8c+?F+\Q4s8R- at s+C7L!e^Morr3CJs8R0?s)\3]
+s)\3]rVun=qu6_=K6-qis)\5?!-A/>s)\2>rGr,AF*%A&rr3#GKDb`OUAo:Uqu6Y;r;R:Ks)W8]
+s)\3]F8p<&s8R`Mrr@]Jrs48WKE$RFF8p=YrrCFEEruA_KDorks8@$=rrR9As8I'Es)W8]F8u8]
+mf.e~>
+nG`OKb5VG at aop)kb5]W`s8U4Es2tAab5M>?b5M>Ab0\<0s8U4Bs3U]D!mptirr3DLs8U7As2tAa
+s2tAarVuo?qu6`?d)u7cs2tBA!6Y<@s2t?@rQ59Cb0'b,rr3#dd/<nGh#GO>qu6Z=r;R;Ms2rLa
+s2tAab5]W,s8UIErrCFBrs7!Od/VJ8b5]W]rrDHbao_Ucd/M2es8C+?rrU at Cs8L.Gs2rLab5_La
+mf.e~>
+nG`O$L&V,PK`[J<L&CuNK`qF0s+Q1*rr at cOrrRn<L&M&OK`V4;r;Qh^s+UIP%#+`]L&_1,s+UK,
+s+UFOs+U at M!elhlqu?\Ms8N(Qrr<"Prr;qN"TO10s+UIP!S3J4rr]G(Kn]4"%u(%;L&_1,s+Q1,
+Kn]R,PPtL]PPY:bPQ-jHPD+_jL&:lMf)::(s+Q[9L&V,PKa.R2s8RfQs8I]Ws+Q1,L&_1,mf.e~>
+nG`NoF8l4>Erq!oF8Z(<Es2Mas)W8[rr at -=rrR7oF8c.=Erl;nr;QhNs)\2>%!2IKF8u8]s)\3]
+s)\/=s)\);!cs!8qu?\;s8N(?rr<">rr;q<"TNOas)\2>!RQJsrr]"qF*%$S%s.blF8u8]s)W8]
+F*%B]KDkfMKDPTRKE$T(K6),6F8Pt;d/A"es)WhlF8l4>EsDYcs8R0?s8I'Es)W8]F8u8]mf.e~>
+nG`OKb5VG at ao]rib5D;>aoqaes2rL_rrC4?rrU?ib5MA?aoVOhr;QiFs2t?@%*JVMb5_Las2tAa
+s2t<?s2t6=!m8m4qu?]=s8N)Arr<#@rr;r>"TQWes2t?@!U\83rr_'Vb0'DW&'Fppb5_Las2rLa
+b0'bad/EtEd/*bJd/VJmd)sN2b5;2=mJY0/s2r^fb5VG at ap.mgs8U7As8L.Gs2rLab5_Lamf.e~>
+nG`O$L&V,PK`[J<L&:lRL&Zl,Kn]L*!/:CO!elhlrVunO!WSA]rrSDaL&V)\L&_1,s8RfQL&Zl,
+L&M&OL&:lOKp.5fs8RfQrr at cPs8RfPs8@WSs+Q1,L&V)Qes$%3"0VZXL%YHVL&Zj\s8RfQKn]P\
+L&_1:rVlk]qYphbs-*JHKn]P\qu6ZIrIk=QKp2Lirr<"P#60DWs+ULQre:CP"blu1s8Rf at s*t~>
+nG`NoF8l4>Erq!oF8Pt at F8p=]F*%<[!-A,=!cs!8rVun=!WRfMrrRiQF8l1JF8u8]s8R0?F8p=]
+F8c.=F8Pt=F+\Q2s8R0?rr at ->s8R0>s8@!As)W8]F8l1?d"D8r"/>g:F7oPDF8p<&s8R0?F*%A&
+F8u8mrVlkMqYphRs+C?(F*%A&qu6ZCrGr&?F+aI5rr<">#6/cEs)\5?rcA,>"`s]bs8R0.s*t~>
+nG`OKb5VG at ao]rib5;2Bb5]Wab0'\_!6Y9?!m8m4rVuo?!WUOErrURIb5VDLb5_Las8U7Ab5]Wa
+b5MA?b5;2?b0\<.s8U7ArrC4 at s8U7@s8C(Cs2rLab5VDAmEke2"5Nq!b4YcFb5]W,s8U7Ab0'b,
+b5_LgrVllEqYpiJs3Uemb0'b,qu6Z`rQ53Ab0^.1rr<#@#62jGs2tBArlY9@"j6kfs8U70s*t~>
+p]#dES,i?aJ,~>
+p]#dES,i?aJ,~>
+p]#dES,i?aJ,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+o`#!5WoMY0s5WDE!6>&<_uB_Wrr2u=p&G&loD\l4<TETKr2KbWh#Dm~>
+o`#!5WoMY0s5WDE!6>&<_uB_Wrr2u=p&G&loD\l4<TETKr2KbWh#Dm~>
+o`#!5WoMY0s5WDE!6>&<_uB_Wrr2u=p&G&loD\l4<TETKr2KbWh#Dm~>
+pAY0R<W2suEp<T)j)XYhs&K$t!TS4irr=)<!!((9s8V-ArrC+=s8T+err`=^s/H(ls8Q*krr[9A
+<TEWL!35qs!-6lpJ,~>
+pAY0R<W2suEp<T)j)XYhs&K$t!TS4irr=)<!!((9s8V-ArrC+=s8T+err`=^s/H(ls8Q*krr[9A
+<TEWL!35qs!-6lpJ,~>
+pAY0R<W2suEp<T)j)XYhs&K$t!TS4irr=)<!!((9s8V-ArrC+=s8T+err`=^s/H(ls8Q*krr[9A
+<TEWL!35qs!-6lpJ,~>
+pAY:r3TL.>j6?REj)XYhs&K$t!TS4grrE,"q#C at okPkR_!<3#uWpfrl`rK->EWF/Rs8Q*krrE+[
+n,EEg!8%7$~>
+pAY:r3TL.>j6?REj)XYhs&K$t!TS4grrE,"q#C at okPkR_!<3#uWpfrl`rK->EWF/Rs8Q*krrE+[
+n,EEg!8%7$~>
+pAY:r3TL.>j6?REj)XYhs&K$t!TS4grrE,"q#C at okPkR_!<3#uWpfrl`rK->EWF/Rs8Q*krrE+[
+n,EEg!8%7$~>
+pAY-nEr>qDEo[2[ElS0?<HA*=(33Dqj5Y1#<HA,>WrN+!<HA-"ElV1#qu?[rrVunts8N at b<E6&>
+*KF."q>WDSWrN+ZElV1?j&I*?<TF,><E5(ZWiD(ZWrN*Z<H at ."s,L*>j)R-[<N?(>j8]."<N?)Z
+ElV1?qYpb[!'1'>!36%u%rt[Ms8V+Z<B4(Zs)M+[j8Aogj&H(><TF,><E8)ZElW3#j8AoXWW;ts
+s)J7&<N9&>rr3ML<E7*>s2S,[a8b1?<E8)Qs*t~>
+pAY-nEr>qDEo[2[ElS0?<HA*=(33Dqj5Y1#<HA,>WrN+!<HA-"ElV1#qu?[rrVunts8N at b<E6&>
+*KF."q>WDSWrN+ZElV1?j&I*?<TF,><E5(ZWiD(ZWrN*Z<H at ."s,L*>j)R-[<N?(>j8]."<N?)Z
+ElV1?qYpb[!'1'>!36%u%rt[Ms8V+Z<B4(Zs)M+[j8Aogj&H(><TF,><E8)ZElW3#j8AoXWW;ts
+s)J7&<N9&>rr3ML<E7*>s2S,[a8b1?<E8)Qs*t~>
+pAY-nEr>qDEo[2[ElS0?<HA*=(33Dqj5Y1#<HA,>WrN+!<HA-"ElV1#qu?[rrVunts8N at b<E6&>
+*KF."q>WDSWrN+ZElV1?j&I*?<TF,><E5(ZWiD(ZWrN*Z<H at ."s,L*>j)R-[<N?(>j8]."<N?)Z
+ElV1?qYpb[!'1'>!36%u%rt[Ms8V+Z<B4(Zs)M+[j8Aogj&H(><TF,><E8)ZElW3#j8AoXWW;ts
+s)J7&<N9&>rr3ML<E7*>s2S,[a8b1?<E8)Qs*t~>
+pAY+mrW";dWrE(!s/H(!!!$">ErT,[<?6+[!!#"ZW`<(!WW6$>EiK*>3<6)Ws8Q*ts8Q(,s)K,[
+3E9&Z*E<*[qYrPUWrN+!!!#"ZW`:&[<TE*[3E6("<<*"Z!<6%!3?;-"NW<'"EcO/?<N?'!WrH'>
+<<1(>!!#"Za8>lS<<*%!!$-+[s&C(>!6=+"3E6&Zs&C(>*HM)X&B at cN3E>,"*B?,#rr<$>*EE%;
+!NH.u<>smt!$)%>*<<,>WW4&"!<;'Z3B8,[*B at +?WqQIC~>
+pAY+mrW";dWrE(!s/H(!!!$">ErT,[<?6+[!!#"ZW`<(!WW6$>EiK*>3<6)Ws8Q*ts8Q(,s)K,[
+3E9&Z*E<*[qYrPUWrN+!!!#"ZW`:&[<TE*[3E6("<<*"Z!<6%!3?;-"NW<'"EcO/?<N?'!WrH'>
+<<1(>!!#"Za8>lS<<*%!!$-+[s&C(>!6=+"3E6&Zs&C(>*HM)X&B at cN3E>,"*B?,#rr<$>*EE%;
+!NH.u<>smt!$)%>*<<,>WW4&"!<;'Z3B8,[*B at +?WqQIC~>
+pAY+mrW";dWrE(!s/H(!!!$">ErT,[<?6+[!!#"ZW`<(!WW6$>EiK*>3<6)Ws8Q*ts8Q(,s)K,[
+3E9&Z*E<*[qYrPUWrN+!!!#"ZW`:&[<TE*[3E6("<<*"Z!<6%!3?;-"NW<'"EcO/?<N?'!WrH'>
+<<1(>!!#"Za8>lS<<*%!!$-+[s&C(>!6=+"3E6&Zs&C(>*HM)X&B at cN3E>,"*B?,#rr<$>*EE%;
+!NH.u<>smt!$)%>*<<,>WW4&"!<;'Z3B8,[*B at +?WqQIC~>
+p&?N%WiB&!irH+ZWW<&!NrQ*Z`rM,[!33%!WrF*[<E9&>ErV."WW9(!*QS*Xs&K$ts&BI,EZL2?
+s/H(Zs&E(qruqHCs8T)!<W<'!s&E)!s)K-?*?F0?*TP0\`rN.><E8&ZNrAtYWW<%u%03EK!6>+"
+<N6%!rrB(rrttfW!-/'[<WC)>a8\/"EZP2[<E7'>N]@*>qYq$*WrN*>*WP."WW6'!EcV*X!NH.u
+<>"7k*TI-[rrB)!*EE->!<5&>rVlp>3QLdlJ,~>
+p&?N%WiB&!irH+ZWW<&!NrQ*Z`rM,[!33%!WrF*[<E9&>ErV."WW9(!*QS*Xs&K$ts&BI,EZL2?
+s/H(Zs&E(qruqHCs8T)!<W<'!s&E)!s)K-?*?F0?*TP0\`rN.><E8&ZNrAtYWW<%u%03EK!6>+"
+<N6%!rrB(rrttfW!-/'[<WC)>a8\/"EZP2[<E7'>N]@*>qYq$*WrN*>*WP."WW6'!EcV*X!NH.u
+<>"7k*TI-[rrB)!*EE->!<5&>rVlp>3QLdlJ,~>
+p&?N%WiB&!irH+ZWW<&!NrQ*Z`rM,[!33%!WrF*[<E9&>ErV."WW9(!*QS*Xs&K$ts&BI,EZL2?
+s/H(Zs&E(qruqHCs8T)!<W<'!s&E)!s)K-?*?F0?*TP0\`rN.><E8&ZNrAtYWW<%u%03EK!6>+"
+<N6%!rrB(rrttfW!-/'[<WC)>a8\/"EZP2[<E7'>N]@*>qYq$*WrN*>*WP."WW6'!EcV*X!NH.u
+<>"7k*TI-[rrB)!*EE->!<5&>rVlp>3QLdlJ,~>
+nc':'WW9(!WW<&!WrK(!WW3$!a8`.>rVumt#QFe(s/H(!!;QTo<W2st<WE(*NZB/#WW<)!<E8nq
+('(B7s/H(ZrrB)!<E9)!<<+%[j8W+Zrr35'!<<(!<N6&srrK,"rr3E-Wi?(!s&E(!!9=(ZWr2l*
+WW;'"!*-$!s/H)!s8>sts8Q(%WW3$!a8,`C!36)!<E9)!!3-%!q>UJq!;uls<=]$/WrE'>rrB)!
+WW<&!Wr;r"j)P-"p&BO~>
+nc':'WW9(!WW<&!WrK(!WW3$!a8`.>rVumt#QFe(s/H(!!;QTo<W2st<WE(*NZB/#WW<)!<E8nq
+('(B7s/H(ZrrB)!<E9)!<<+%[j8W+Zrr35'!<<(!<N6&srrK,"rr3E-Wi?(!s&E(!!9=(ZWr2l*
+WW;'"!*-$!s/H)!s8>sts8Q(%WW3$!a8,`C!36)!<E9)!!3-%!q>UJq!;uls<=]$/WrE'>rrB)!
+WW<&!Wr;r"j)P-"p&BO~>
+nc':'WW9(!WW<&!WrK(!WW3$!a8`.>rVumt#QFe(s/H(!!;QTo<W2st<WE(*NZB/#WW<)!<E8nq
+('(B7s/H(ZrrB)!<E9)!<<+%[j8W+Zrr35'!<<(!<N6&srrK,"rr3E-Wi?(!s&E(!!9=(ZWr2l*
+WW;'"!*-$!s/H)!s8>sts8Q(%WW3$!a8,`C!36)!<E9)!!3-%!q>UJq!;uls<=]$/WrE'>rrB)!
+WW<&!Wr;r"j)P-"p&BO~>
+p\u.P<WE*>3<8([WrK(!rrB)!<?9*[WrL+>WW<"ts&B=(*EE,>3N<)Ss8Q(2s/L+><E9(!j8U-"
+WW<(Z*HM)X(rrWVEiT/>!<<'!WrH(!s8R*[j8Y."<E9%u%`\Ris#F*"!36'ZWrK(!rr3E-WlG+>
+iuO/[!<<'!Wr2l8EZP0[!07'ZWlG+>iuO/#*TQ0?<Q>*>s2S.9rsJh,s8R*[j/N+>!35kp!NH.t
+s8Q(8rrB)!3E?)"ErV."ruG,>a)^4?s2P,>pA]X~>
+p\u.P<WE*>3<8([WrK(!rrB)!<?9*[WrL+>WW<"ts&B=(*EE,>3N<)Ss8Q(2s/L+><E9(!j8U-"
+WW<(Z*HM)X(rrWVEiT/>!<<'!WrH(!s8R*[j8Y."<E9%u%`\Ris#F*"!36'ZWrK(!rr3E-WlG+>
+iuO/[!<<'!Wr2l8EZP0[!07'ZWlG+>iuO/#*TQ0?<Q>*>s2S.9rsJh,s8R*[j/N+>!35kp!NH.t
+s8Q(8rrB)!3E?)"ErV."ruG,>a)^4?s2P,>pA]X~>
+p\u.P<WE*>3<8([WrK(!rrB)!<?9*[WrL+>WW<"ts&B=(*EE,>3N<)Ss8Q(2s/L+><E9(!j8U-"
+WW<(Z*HM)X(rrWVEiT/>!<<'!WrH(!s8R*[j8Y."<E9%u%`\Ris#F*"!36'ZWrK(!rr3E-WlG+>
+iuO/[!<<'!Wr2l8EZP0[!07'ZWlG+>iuO/#*TQ0?<Q>*>s2S.9rsJh,s8R*[j/N+>!35kp!NH.t
+s8Q(8rrB)!3E?)"ErV."ruG,>a)^4?s2P,>pA]X~>
+p\t5nr;Zp?WrI,<!!*&t!!92#<W2t"<N6&ts8Q("s/Q%u!lq;@q#:=orW!*BW`<(!*W?'=Wr;u!
+*TR(t!$2"<%EGIKs8N)!s&E)!s5P.!!!90#<W2pt3W/pYs&K$u"02C$!<3!-!36'!!!"&>WW<)!
+!35tss&BR/WW;)Z<HA+>!!"&>iuS+!!`f8#rVupuqYpp'WrN+Z*<6([rrB(prrM-[rDa3bEcV0[
+WrH(!s,R$Xs/Q%u!EI2>!!+,#pA]X~>
+p\t5nr;Zp?WrI,<!!*&t!!92#<W2t"<N6&ts8Q("s/Q%u!lq;@q#:=orW!*BW`<(!*W?'=Wr;u!
+*TR(t!$2"<%EGIKs8N)!s&E)!s5P.!!!90#<W2pt3W/pYs&K$u"02C$!<3!-!36'!!!"&>WW<)!
+!35tss&BR/WW;)Z<HA+>!!"&>iuS+!!`f8#rVupuqYpp'WrN+Z*<6([rrB(prrM-[rDa3bEcV0[
+WrH(!s,R$Xs/Q%u!EI2>!!+,#pA]X~>
+p\t5nr;Zp?WrI,<!!*&t!!92#<W2t"<N6&ts8Q("s/Q%u!lq;@q#:=orW!*BW`<(!*W?'=Wr;u!
+*TR(t!$2"<%EGIKs8N)!s&E)!s5P.!!!90#<W2pt3W/pYs&K$u"02C$!<3!-!36'!!!"&>WW<)!
+!35tss&BR/WW;)Z<HA+>!!"&>iuS+!!`f8#rVupuqYpp'WrN+Z*<6([rrB(prrM-[rDa3bEcV0[
+WrH(!s,R$Xs/Q%u!EI2>!!+,#pA]X~>
+pAY6TWiF,<rs6ZFa2e2[EiS1!rrpHCa8c1[rVuoXs8N8_WoO-Za8#ZHj/T->s8V->s8T+!j8Z+Z
+WiG[j#KQlEa8c2"j8K#XWWV;]j5^(;s/H;'a8c1[WoO*Y!6>*=!6>*=!QV5>rr^=As2Y$:s5X.Z
+#fluFWiH+!a/]+<s/Q+Zs8N/@WlOr8!?K5Zrrf at Bs8U.6rrC+<<<2(YrtKM6s5W/>s2V/"a8c2"
+WlP/>j/T-Os*t~>
+pAY6TWiF,<rs6ZFa2e2[EiS1!rrpHCa8c1[rVuoXs8N8_WoO-Za8#ZHj/T->s8V->s8T+!j8Z+Z
+WiG[j#KQlEa8c2"j8K#XWWV;]j5^(;s/H;'a8c1[WoO*Y!6>*=!6>*=!QV5>rr^=As2Y$:s5X.Z
+#fluFWiH+!a/]+<s/Q+Zs8N/@WlOr8!?K5Zrrf at Bs8U.6rrC+<<<2(YrtKM6s5W/>s2V/"a8c2"
+WlP/>j/T-Os*t~>
+pAY6TWiF,<rs6ZFa2e2[EiS1!rrpHCa8c1[rVuoXs8N8_WoO-Za8#ZHj/T->s8V->s8T+!j8Z+Z
+WiG[j#KQlEa8c2"j8K#XWWV;]j5^(;s/H;'a8c1[WoO*Y!6>*=!6>*=!QV5>rr^=As2Y$:s5X.Z
+#fluFWiH+!a/]+<s/Q+Zs8N/@WlOr8!?K5Zrrf at Bs8U.6rrC+<<<2(YrtKM6s5W/>s2V/"a8c2"
+WlP/>j/T-Os*t~>
+l2LbaWmUhIWW7VMec1.~>
+l2LbaWmUhIWW7VMec1.~>
+l2LbaWmUhIWW7VMec1.~>
+l2Lc)a3jnf`uTa2ec1.~>
+l2Lc)a3jnf`uTa2ec1.~>
+l2Lc)a3jnf`uTa2ec1.~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+JcCT,J,~>
+%%EndData
+showpage
+%%Trailer
+end
+%%EOF
Added: branches/bos/thirdparty/emacs/slime/doc/slime-small.pdf
==============================================================================
Binary file. No diff available.
Added: branches/bos/thirdparty/emacs/slime/doc/slime.texi
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/slime.texi Fri Jan 18 06:05:59 2008
@@ -0,0 +1,2963 @@
+\input texinfo
+ at c %**start of header
+ at setfilename slime.info
+ at settitle The Superior Lisp Interaction Mode for Emacs
+
+ at dircategory Emacs
+ at direntry
+* SLIME: (slime). Superior Lisp Interaction Mode for Emacs.
+ at end direntry
+ at c %**end of header
+
+ at set EDITION 3.0-alpha
+ at set SLIMEVER 3.0-alpha
+ at c @set UPDATED @today{}
+ at set UPDATED @code{$Date: 2007/11/27 13:16:52 $}
+ at set TITLE SLIME User Manual
+ at settitle @value{TITLE}, version @value{EDITION}
+
+ at copying
+Written by Luke Gorrie.
+
+Additional contributions: Jeff Cunningham,
+
+This file has been placed in the public domain.
+ at end copying
+
+ at titlepage
+ at title @value{TITLE}
+ at titlefont{version @value{EDITION}}
+ at sp 2
+ at center @image{slime-small}
+ at sp 4
+ at subtitle Compiled: @value{UPDATED}
+
+ at page
+ at insertcopying
+
+ at end titlepage
+
+ at c Macros
+
+ at macro SLIME
+ at acronym{SLIME}
+ at end macro
+
+ at macro SLDB
+ at acronym{SLDB}
+ at end macro
+
+ at macro REPL
+ at acronym{REPL}
+ at end macro
+
+ at macro CVS
+ at acronym{CVS}
+ at end macro
+
+ at macro kbditem{key, command}
+ at item \key\
+ at itemx M-x \command\
+ at kindex \key\
+ at findex \command\
+ at c
+ at end macro
+
+ at macro kbditempair{key1, key2, command1, command2}
+ at item \key1\, M-x \command1\
+ at itemx \key2\, M-x \command2\
+ at kindex \key1\
+ at kindex \key2\
+ at findex \command1\
+ at findex \command2\
+ at c
+ at end macro
+
+ at macro cmditem{command}
+ at item M-x \command\
+ at findex \command\
+ at c
+ at end macro
+
+ at macro kbdanchorc{key, command, comment}
+ at anchor{\command\}
+ at item \key\
+ at code{\command\}
+ at i{\comment\}@*
+ at end macro
+
+ at macro fcnindex{name}
+ at item \name\
+ at xref{\name\}.
+ at end macro
+
+ at c Merge the variable and concept indices because both are rather short
+ at synindex cp vr
+
+
+ at c @setchapternewpage off
+ at c @shortcontents
+ at contents
+
+ at ifnottex
+ at node Top
+ at top SLIME
+
+ at SLIME{} is the ``Superior Lisp Interaction Mode for Emacs''. This is
+the manual for version @value{SLIMEVER}.
+
+ at insertcopying
+ at end ifnottex
+
+ at menu
+* Introduction::
+* Getting started::
+* slime-mode::
+* REPL::
+* Debugger::
+* Misc::
+* Customization::
+* Tips and Tricks::
+* Contributed Packages::
+* Credits::
+* Key Index::
+* Command Index::
+* Variable Index::
+
+ at detailmenu
+ --- The Detailed Node Listing ---
+
+Getting started
+
+* Platforms::
+* Downloading::
+* Installation::
+* Running::
+* Setup Tuning::
+
+Downloading SLIME
+
+* CVS::
+* CVS Incantations::
+
+Downloading from CVS
+
+* CVS Incantations::
+
+Setup Tuning
+
+* Autoloading::
+* Multiple Lisps::
+* Loading Swank faster::
+
+Using slime-mode
+
+* User-interface conventions::
+* Commands::
+* Semantic indentation::
+* Reader conditionals::
+
+User-interface conventions
+
+* Temporary buffers::
+* Inferior-lisp::
+* Multithreading::
+* Key bindings::
+
+Commands
+
+* Programming::
+* Compilation::
+* Evaluation::
+* Recovery::
+* Inspector::
+* Profiling::
+* Other::
+
+Programming commands
+
+* Completion::
+* Indentation::
+* Documentation::
+* Cross-reference::
+* Finding definitions::
+* Macro-expansion::
+* Disassembly::
+
+REPL: the ``top level''
+
+* REPL commands::
+* Input Navigation::
+* Shortcuts::
+
+SLDB: the SLIME debugger
+
+* Examining frames::
+* Restarts::
+* Frame Navigation::
+* Stepping::
+* Miscellaneous::
+
+Misc
+
+* slime-selector::
+* slime-macroexpansion-minor-mode::
+* Multiple connections::
+
+Customization
+
+* Emacs-side customization::
+* Lisp-side::
+
+Emacs-side
+
+* Hooks::
+
+Lisp-side (Swank)
+
+* Communication style::
+* Other configurables::
+
+Tips and Tricks
+
+* Connecting to a remote lisp::
+* Global IO Redirection::
+* Auto-SLIME::
+
+Connecting to a remote lisp
+
+* Setting up the lisp image::
+* Setting up Emacs::
+* Setting up pathname translations::
+
+Contributed Packages
+
+* Loading Contribs::
+* Compound Completion::
+* Fuzzy Completion::
+* slime-autodoc-mode::
+* ASDF::
+* Banner::
+* Editing Commands::
+* Fancy Inspector::
+* Presentations::
+* Typeout frames::
+* TRAMP::
+* Documentation Links::
+* Xref and Class Browser::
+* Highlight Edits::
+* inferior-slime-mode::
+* Scratch Buffer::
+* slime-fancy::
+
+ at end detailmenu
+ at end menu
+
+ at c -----------------------
+ at node Introduction
+ at chapter Introduction
+
+ at SLIME{} is the ``Superior Lisp Interaction Mode for Emacs.''
+
+ at SLIME{} extends Emacs with support for interactive programming in
+Common Lisp. The features are centered around @code{slime-mode}, an
+Emacs minor-mode that complements the standard @code{lisp-mode}. While
+ at code{lisp-mode} supports editing Lisp source files, @code{slime-mode}
+adds support for interacting with a running Common Lisp process for
+compilation, debugging, documentation lookup, and so on.
+
+The @code{slime-mode} programming environment follows the example of
+Emacs's native Emacs Lisp environment. We have also included good
+ideas from similar systems (such as @acronym{ILISP}) and some new
+ideas of our own.
+
+ at SLIME{} is constructed from two parts: a user-interface written in
+Emacs Lisp, and a supporting server program written in Common
+Lisp. The two sides are connected together with a socket and
+communicate using an @acronym{RPC}-like protocol.
+
+The Lisp server is primarily written in portable Common Lisp. The
+required implementation-specific functionality is specified by a
+well-defined interface and implemented separately for each Lisp
+implementation. This makes @SLIME{} readily portable.
+
+ at c -----------------------
+ at node Getting started
+ at chapter Getting started
+
+This chapter tells you how to get @SLIME{} up and running.
+
+ at menu
+* Platforms::
+* Downloading::
+* Installation::
+* Running::
+* Setup Tuning::
+ at end menu
+
+ at c -----------------------
+ at node Platforms
+ at section Supported Platforms
+
+ at SLIME{} supports a wide range of operating systems and Lisp
+implementations. @SLIME{} runs on Unix systems, Mac OSX, and Microsoft
+Windows. GNU Emacs versions 20, 21 and 22 and XEmacs version 21 are
+supported.
+
+The supported Lisp implementations, roughly ordered from the
+best-supported, are:
+
+ at itemize @bullet
+ at item
+CMU Common Lisp (@acronym{CMUCL}), 19d or newer
+ at item
+Steel Bank Common Lisp (@acronym{SBCL}), 1.0 or newer
+ at item
+OpenMCL, version 0.14.3 or newer
+ at item
+LispWorks, version 4.3 or newer
+ at item
+Allegro Common Lisp (@acronym{ACL}), version 6 or newer
+ at item
+ at acronym{CLISP}, version 2.35 or newer
+ at item
+Armed Bear Common Lisp (@acronym{ABCL})
+ at item
+Corman Common Lisp (@acronym{CCL}), version 2.51 or newer with the
+patches from @url{http://www.grumblesmurf.org/lisp/corman-patches})
+ at item
+Scieneer Common Lisp (@acronym{SCL}), version 1.2.7 or newer
+ at end itemize
+
+Most features work uniformly across implementations, but some are
+prone to variation. These include the precision of placing
+compiler-note annotations, @acronym{XREF} support, and fancy debugger
+commands (like ``restart frame'').
+
+ at c -----------------------
+ at node Downloading
+ at section Downloading SLIME
+
+You can choose between using a released version of @SLIME{} or
+accessing our @CVS{} repository directly. You can download the latest
+released version from our website:
+
+ at url{http://www.common-lisp.net/project/slime/}
+
+We recommend that users who participate in the @code{slime-devel}
+mailing list use the @CVS{} version of the code.
+
+ at menu
+* CVS::
+* CVS Incantations::
+ at end menu
+
+ at c -----------------------
+ at node CVS
+ at subsection Downloading from CVS
+
+ at SLIME{} is available from the @CVS{} repository on
+ at file{common-lisp.net}. You have the option to use either the very
+latest code or the tagged @code{FAIRLY-STABLE} snapshot.
+
+The latest version tends to have more features and fewer bugs than the
+ at code{FAIRLY-STABLE} version, but it can be unstable during times of
+major surgery. As a rule-of-thumb recommendation we suggest that if
+you follow the @code{slime-devel} mailing list then you're better off
+with the latest version (we'll send a note when it's undergoing major
+hacking). If you don't follow the mailing list you won't know the
+status of the latest code, so tracking @code{FAIRLY-STABLE} or using a
+released version is the safe option.
+
+If you checkout from @CVS{} then remember to @code{cvs update}
+occasionally. Improvements are continually being committed, and the
+ at code{FAIRLY-STABLE} tag is moved forward from time to time.
+
+ at menu
+* CVS Incantations::
+ at end menu
+
+ at c -----------------------
+ at node CVS Incantations
+ at subsection CVS incantations
+
+To download @SLIME{} you first configure your @code{CVSROOT} and login
+to the repository.
+
+ at example
+export CVSROOT=:pserver:anonymous@@common-lisp.net:/project/slime/cvsroot
+cvs login
+ at end example
+ at emph{(The password is @code{anonymous})}
+
+The latest version can then be checked out with:
+ at example
+cvs checkout slime
+ at end example
+
+Or the @code{FAIRLY-STABLE} version can be checked out with:
+
+ at example
+cvs checkout -rFAIRLY-STABLE slime
+ at end example
+
+If you want to find out what's new since the version you're currently
+running, you can diff the local @file{ChangeLog} against the
+repository version:
+
+ at example
+cvs diff -rHEAD ChangeLog # or: -rFAIRLY-STABLE
+ at end example
+
+ at c -----------------------
+ at node Installation
+ at section Installation
+
+With a Lisp implementation that can be started from the command-line,
+installation just requires a few lines in your @file{.emacs}:
+
+ at vindex inferior-lisp-program
+ at vindex load-path
+ at example
+(setq inferior-lisp-program "@emph{the path to your Lisp system}")
+(add-to-list 'load-path "@emph{the path of your @file{slime} directory}")
+(require 'slime)
+(slime-setup)
+ at end example
+
+ at iftex
+The snippet above also appears in the @file{README} file. You can
+copy&paste it from there, but remember to fill in the appropriate
+paths.
+ at end iftex
+
+We recommend not loading the @acronym{ILISP} package into Emacs if you
+intend to use @SLIME{}. Doing so will add a lot of extra bindings to
+the keymap for Lisp source files that may be confusing and may not
+work correctly for a Lisp process started by @SLIME{}.
+
+ at c -----------------------
+ at node Running
+ at section Running SLIME
+
+ at SLIME{} is started with the Emacs command @kbd{M-x slime}. This uses
+the @code{inferior-lisp} package to start a Lisp process, loads and
+starts the Lisp-side server (known as ``Swank''), and establishes a
+socket connection between Emacs and Lisp. Finally a @REPL{} buffer is
+created where you can enter Lisp expressions for evaluation.
+
+At this point @SLIME{} is up and running and you can start exploring.
+
+You can restart the @code{inferior-lisp} process using the function:
+ at table @kbd
+ at cmditem{slime-restart-inferior-lisp}
+ at end table
+
+ at node Setup Tuning
+ at section Setup Tuning
+
+This section explains ways to reduce @SLIME{}'s startup time and how
+to configure @SLIME{} for multiple Lisp systems.
+
+Please proceed with this section only if your basic setup works. If
+you are happy with the basic setup, skip this section.
+
+ at menu
+* Autoloading::
+* Multiple Lisps::
+* Loading Swank faster::
+ at end menu
+
+ at node Autoloading
+ at subsection Autoloading
+
+The basic setup loads @SLIME{} always, even if you don't use @SLIME{}.
+Emacs will start up a little faster if we load @SLIME{} only on
+demand. To achieve that, you have to change your @file{~/.emacs}
+slightly:
+
+ at example
+(setq inferior-lisp-program "@emph{the path to your Lisp system}")
+(add-to-list 'load-path "@emph{the path of your @file{slime} directory}")
+(require 'slime-autoloads)
+(slime-setup)
+ at end example
+
+The only difference compared to the basic setup is the line
+ at code{(require 'slime-autoloads)}. It tells Emacs that the rest of
+ at SLIME{} should be loaded automatically when one of the commands
+ at kbd{M-x slime} or @kbd{M-x slime-connect} is executed the first time.
+
+ at node Multiple Lisps
+ at subsection Multiple Lisps
+
+By default, the command @kbd{M-x slime} starts the program specified
+with @code{inferior-lisp-program}. If you invoke @kbd{M-x slime} with
+a prefix argument, Emacs prompts for the program which should be
+started instead. If you need that frequently or if the command
+involves long filenames it's more convenient to set the
+ at code{slime-lisp-implementations} variable in your @file{.emacs}. For
+example here we define two programs:
+
+ at vindex slime-lisp-implementations
+ at lisp
+(setq slime-lisp-implementations
+ '((cmucl ("cmucl" "-quiet"))
+ (sbcl ("/opt/sbcl/bin/sbcl") :coding-system utf-8-unix)))
+ at end lisp
+
+This variable holds a list of programs and if you invoke @SLIME{} with
+a negative prefix argument, @kbd{M-- M-x slime}, you can select a
+program from that list. The elements of the list should look like
+
+ at lisp
+(NAME (PROGRAM PROGRAM-ARGS...) &key CODING-SYSTEM INIT INIT-FUNCTION)
+ at end lisp
+
+ at table @code
+ at item NAME
+is a symbol and is used to identify the program.
+ at item PROGRAM
+is the filename of the program. Note that the filename can contain
+spaces.
+ at item PROGRAM-ARGS
+is a list of command line arguments.
+ at item CODING-SYSTEM
+the coding system for the connection. (@pxref{slime-net-coding-system})
+ at item INIT
+should be a function which takes two arguments: a filename and a
+character encoding. The function should return a Lisp expression as a
+string which instructs Lisp to start the Swank server and to write the
+port number to the file. At startup, @SLIME{} starts the Lisp process
+and sends the result of this function to Lisp's standard input. As
+default, @code{slime-init-command} is used. An example is shown in
+ at ref{init-example,,Loading Swank faster}.
+ at itemx INIT-FUNCTION
+should be a function which takes no arguments. It is called after
+the connection is established. (See also @ref{slime-connected-hook}.)
+ at end table
+
+ at node Loading Swank faster
+ at subsection Loading Swank faster
+
+For SBCL, we recommend that you create a custom core file with socket
+support and @acronym{POSIX} bindings included because those modules
+take the most time to load. To create such a core, execute the
+following steps:
+
+ at example
+shell$ sbcl
+* (mapc 'require '(sb-bsd-sockets sb-posix sb-introspect sb-cltl2 asdf))
+* (save-lisp-and-die "sbcl.core-for-slime")
+ at end example
+
+After that, add something like this to your @file{.emacs}:
+
+ at lisp
+(setq slime-lisp-implementations
+ '((sbcl ("sbcl" "--core" "sbcl.core-for-slime"))))
+ at end lisp
+
+For maximum startup speed you can include the Swank server directly in
+a core file. The disadvantage of this approach is that the setup is a
+bit more involved and that you need to create a new core file when you
+want to update @SLIME{} or @acronym{SBCL}. The steps to execute are:
+
+ at example
+shell$ sbcl
+* (load ".../slime/swank-loader.lisp")
+* (save-lisp-and-die "sbcl.core-with-swank")
+ at end example
+
+ at noindent
+Then add this to your @file{.emacs}:
+
+ at anchor{init-example}
+ at lisp
+(setq slime-lisp-implementations
+ '((sbcl ("sbcl" "--core" "sbcl.core-with-swank")
+ :init (lambda (port-file _)
+ (format "(swank:start-server %S)\n" port-file)))))
+ at end lisp
+
+ at noindent
+Similar setups should also work for other Lisp implementations.
+
+ at node slime-mode
+ at chapter Using slime-mode
+
+ at SLIME{}'s commands are provided via @code{slime-mode}, a minor-mode
+used in conjunction with Emacs's @code{lisp-mode}. This chapter
+describes the @code{slime-mode} and its relatives.
+
+ at menu
+* User-interface conventions::
+* Commands::
+* Semantic indentation::
+* Reader conditionals::
+ at end menu
+
+ at c -----------------------
+ at node User-interface conventions
+ at section User-interface conventions
+
+To use @SLIME{} comfortably it is important to understand a few
+``global'' user-interface characteristics. The most important
+principles are described in this section.
+
+ at menu
+* Temporary buffers::
+* Inferior-lisp::
+* Multithreading::
+* Key bindings::
+ at end menu
+
+ at c -----------------------
+ at node Temporary buffers
+ at subsection Temporary buffers
+
+Some @SLIME{} commands create temporary buffers to display their
+results. Although these buffers usually have their own special-purpose
+major-modes, certain conventions are observed throughout.
+
+Temporary buffers can be dismissed by pressing @kbd{q}. This kills the
+buffer and restores the window configuration as it was before the
+buffer was displayed. Temporary buffers can also be killed with the
+usual commands like @code{kill-buffer}, in which case the previous
+window configuration won't be restored.
+
+Pressing @kbd{RET} is supposed to ``do the most obvious useful
+thing.'' For instance, in an apropos buffer this prints a full
+description of the symbol at point, and in an @acronym{XREF} buffer it
+displays the source code for the reference at point. This convention
+is inherited from Emacs's own buffers for apropos listings,
+compilation results, etc.
+
+Temporary buffers containing Lisp symbols use @code{slime-mode} in
+addition to any special mode of their own. This makes the usual
+ at SLIME{} commands available for describing symbols, looking up
+function definitions, and so on.
+
+ at c -----------------------
+ at node Inferior-lisp
+ at subsection @code{*inferior-lisp*} buffer
+
+ at SLIME{} internally uses the @code{comint} package to start Lisp
+processes. This has a few user-visible consequences, some good and
+some not-so-terribly. To avoid confusion it is useful to understand
+the interactions.
+
+The buffer @code{*inferior-lisp*} contains the Lisp process's own
+top-level. This direct access to Lisp is useful for troubleshooting,
+and some degree of @SLIME{} integration is available using the
+ at code{inferior-slime-mode}. However, in normal use we recommend using
+the fully-integrated @SLIME{} @REPL{} and ignoring the
+ at code{*inferior-lisp*} buffer.
+
+ at c -----------------------
+ at node Multithreading
+ at subsection Multithreading
+
+If the Lisp system supports multithreading, SLIME spawns a new thread
+for each request, e.g., @kbd{C-x C-e} creates a new thread to evaluate
+the expression. An exception to this rule are requests from the
+ at REPL{}: all commands entered in the @REPL{} buffer are evaluated in a
+dedicated @REPL{} thread.
+
+Some complications arise with multithreading and special variables.
+Non-global special bindings are thread-local, e.g., changing the value
+of a let bound special variable in one thread has no effect on the
+binding of the variables with the same name in other threads. This
+makes it sometimes difficult to change the printer or reader behaviour
+for new threads. The variable
+ at code{swank:*default-worker-thread-bindings*} was introduced for such
+situtuations: instead of modifying the global value of a variable, add a
+binding the @code{swank:*default-worker-thread-bindings*}. E.g., with
+the following code, new threads will read floating point values as
+doubles by default:
+
+ at example
+(push '(*read-default-float-format* . double-float)
+ swank:*default-worker-thread-bindings*).
+ at end example
+
+
+ at node Key bindings
+ at subsection Key bindings
+
+In general we try to make our key bindings fit with the overall Emacs
+style. We also have the following somewhat unusual convention of our
+own: when entering a three-key sequence, the final key can be pressed
+either with control or unmodified. For example, the
+ at code{slime-describe-symbol} command is bound to @kbd{C-c C-d d}, but
+it also works to type @kbd{C-c C-d C-d}. We're simply binding both key
+sequences because some people like to hold control for all three keys
+and others don't, and with the two-key prefix we're not afraid of
+running out of keys.
+
+There is one exception to this rule, just to trip you up. We never
+bind @kbd{C-h} anywhere in a key sequence, so @kbd{C-c C-d C-h}
+doesn't do the same thing as @kbd{C-c C-d h}. This is because Emacs
+has a built-in default so that typing a prefix followed by @kbd{C-h}
+will display all bindings starting with that prefix, so @kbd{C-c C-d
+C-h} will actually list the bindings for all documentation commands.
+This feature is just a bit too useful to clobber!
+
+ at quotation
+ at i{``Are you deliberately spiting Emacs's brilliant online help facilities? The gods will be angry!''}
+ at end quotation
+
+ at noindent This is a brilliant piece of advice. The Emacs online help facilities
+are your most immediate, up-to-date and complete resource for keybinding
+information. They are your friends:
+
+ at table @kbd
+ at kbdanchorc{C-h k <key>, describe-key, ``What does this key do?''}
+Describes current function bound to @kbd{<key>} for focus buffer.
+
+ at kbdanchorc{C-h b, describe-bindings, ``Exactly what bindings are available?''}
+Lists the current key-bindings for the focus buffer.
+
+ at kbdanchorc{C-h m, describe-mode, ``Tell me all about this mode''}
+Shows all the available major mode keys, then the minor mode keys, for
+the modes of the focus buffer.
+
+ at kbdanchorc{C-h l, view-lossage, ``Woah at comma{} what key chord did I just do?''}
+Shows you the literal sequence of keys you've pressed in order.
+
+ at c <key> is breaks links PDF, despite that it's not l it's C-h
+ at c @kbdanchorc{ <key> l, , ``What starts with?''}
+ at c Lists all keybindings that begin with @code{<key>} for the focus buffer mode.
+
+
+ at end table
+
+ at emph{Note:} In this documentation the designation @kbd{C-h} is a
+ at dfn{cannonical key} which might actually mean Ctrl-h, or F1, or
+whatever you have @code{help-command} bound to in your
+ at code{.emacs}. Here is a common situation:
+
+ at example
+(global-set-key [f1] 'help-command)
+(global-set-key "\C-h" 'delete-backward-char)
+ at end example
+
+ at noindent In this situation everywhere you see @kbd{C-h} in the
+documentation you would substitute @kbd{F1}.
+
+You can assign or change default key bindings globally using the
+ at code{global-set-key} function in your @file{~/.emacs} file like this:
+ at example
+(global-set-key "\C-c s" 'slime-selector)
+ at end example
+ at noindent
+which binds @kbd{C-c s} to the function @code{slime-selector}.
+
+Alternatively, if you want to assign or change a key binding in just a
+particular slime mode, you can use the @code{global-set-key} function
+in your @file{~/.emacs} file like this:
+ at example
+(define-key slime-repl-mode-map (kbd "C-c ;")
+ 'slime-insert-balanced-comments)
+ at end example
+ at noindent
+which binds @kbd{C-c ;} to the function
+ at code{slime-insert-balanced-comments} in the REPL buffer.
+
+ at c -----------------------
+ at node Commands
+ at section Commands
+
+ at acronym{SLIME} commands are divided into the following general
+categories: @strong{Programming, Compilation, Evaluation, Recovery,
+Inspector, and Profiling}, discussed in separate sections below. There
+are also comprehensive indices to commands by function
+(@pxref{Command Index}).
+
+ at menu
+* Programming::
+* Compilation::
+* Evaluation::
+* Recovery::
+* Inspector::
+* Profiling::
+* Other::
+ at end menu
+
+ at c -----------------------
+ at node Programming
+ at subsection Programming commands
+
+Programming commands are divided into the following categories:
+ at strong{Completion, Documentation, Cross-reference, Finding
+definitions, Macro-expansion, and Disassembly}, discussed in
+separate sections below.
+
+ at menu
+* Completion::
+* Indentation::
+* Documentation::
+* Cross-reference::
+* Finding definitions::
+* Macro-expansion::
+* Disassembly::
+ at end menu
+
+ at c -----------------------
+ at node Completion
+ at subsubsection Completion commands
+
+ at cindex Completion
+ at cindex Symbol Completion
+
+Completion commands are used to complete a symbol or form based on
+what is already present at point. Classical completion assumes an
+exact prefix and gives choices only where branches may occur. Fuzzy
+completion tries harder.
+
+ at table @kbd
+ at kbditem{M-TAB,slime-complete-symbol}
+ at itemx ESC TAB
+ at itemx C-c C-i
+ at itemx C-M-i
+Complete the symbol at point. Note that three styles of completion are
+available in @SLIME{}; the default is similar to normal Emacs
+completion (@pxref{slime-complete-symbol-function}).
+
+ at end table
+
+ at node Indentation
+ at subsubsection Indentation commands
+
+ at table @kbd
+
+ at kbditem{C-M-q, indent-sexp}
+Indents the list immediately following point to match the level at point.
+
+When given a prefix argument, the text around point will always
+be treated as a paragraph. This is useful for filling docstrings."
+ at end table
+
+ at c -----------------------
+ at node Documentation
+ at subsubsection Documentation commands
+
+ at SLIME{}'s online documentation commands follow the example of Emacs
+Lisp. The commands all share the common prefix @kbd{C-c C-d} and allow
+the final key to be modified or unmodified (@pxref{Key bindings}.)
+
+ at table @kbd
+
+ at kbditem{SPC, slime-space}
+The space key inserts a space, but also looks up and displays the
+argument list for the function at point, if there is one.
+
+ at kbditem{C-c C-d d, slime-describe-symbol}
+Describe the symbol at point.
+
+ at kbditem{C-c C-f, slime-describe-function}
+Describe the function at point.
+
+ at kbditem{C-c C-d a, slime-apropos}
+Perform an apropos search on Lisp symbol names for a regular expression
+match and display their documentation strings. By default the external
+symbols of all packages are searched. With a prefix argument you can choose a
+specific package and whether to include unexported symbols.
+
+ at kbditem{C-c C-d z, slime-apropos-all}
+Like @code{slime-apropos} but also includes internal symbols by default.
+
+ at kbditem{C-c C-d p, slime-apropos-package}
+Show apropos results of all symbols in a package. This command is for
+browsing a package at a high-level. With package-name completion it
+also serves as a rudimentary Smalltalk-ish image-browser.
+
+ at kbditem{C-c C-d h, slime-hyperspec-lookup}
+Lookup the symbol at point in the @cite{Common Lisp Hyperspec}. This
+uses the familiar @file{hyperspec.el} to show the appropriate section
+in a web browser. The Hyperspec is found either on the Web or in
+ at code{common-lisp-hyperspec-root}, and the browser is selected by
+ at code{browse-url-browser-function}.
+
+Note: this is one case where @kbd{C-c C-d h} is @emph{not} the same as
+ at kbd{C-c C-d C-h}.
+
+ at kbditem{C-c C-d ~, common-lisp-hyperspec-format}
+Lookup a @emph{format character} in the @cite{Common Lisp Hyperspec}.
+ at end table
+
+
+ at c -----------------------
+ at node Cross-reference
+ at subsubsection Cross-reference commands
+
+ at cindex xref
+ at cindex Cross-referencing
+
+ at SLIME{}'s cross-reference commands are based on the support provided
+by the Lisp system, which varies widely between Lisps. For systems
+with no built-in @acronym{XREF} support @SLIME{} queries a portable
+ at acronym{XREF} package, which is taken from the @cite{CMU AI
+Repository} and bundled with @SLIME{}.
+
+Each command operates on the symbol at point, or prompts if there is
+none. With a prefix argument they always prompt. You can either enter
+the key bindings as shown here or with the control modified on the
+last key, @xref{Key bindings}.
+
+ at table @kbd
+ at kbditem{C-c C-w c, slime-who-calls}
+Show function callers.
+
+ at kbditem{C-c C-w w, slime-calls-who}
+Show all known callees.
+
+ at kbditem{C-c C-w r, slime-who-references}
+Show references to global variable.
+
+ at kbditem{C-c C-w b, slime-who-binds}
+Show bindings of a global variable.
+
+ at kbditem{C-c C-w s, slime-who-sets}
+Show assignments to a global variable.
+
+ at kbditem{C-c C-w m, slime-who-macroexpands}
+Show expansions of a macro.
+
+ at cmditem{slime-who-specializes}
+Show all known methods specialized on a class.
+
+ at end table
+
+There are also ``List callers/callees'' commands. These operate by
+rummaging through function objects on the heap at a low-level to
+discover the call graph. They are only available with some Lisp
+systems, and are most useful as a fallback when precise @acronym{XREF}
+information is unavailable.
+
+ at table @kbd
+ at kbditem{C-c <, slime-list-callers}
+List callers of a function.
+
+ at kbditem{C-c >, slime-list-callees}
+List callees of a function.
+
+ at end table
+
+
+
+ at c -----------------------
+ at node Finding definitions
+ at subsubsection Finding definitions (``Meta-Point'' commands).
+
+ at cindex Meta-dot
+ at cindex TAGS
+
+The familiar @kbd{M-.} command is provided. For generic functions this
+command finds all methods, and with some systems it does other fancy
+things (like tracing structure accessors to their @code{DEFSTRUCT}
+definition).
+
+ at table @kbd
+
+ at kbditem{M-., slime-edit-definition}
+Go to the definition of the symbol at point.
+
+ at item M-,
+ at itemx M-*
+ at itemx M-x slime-pop-find-definition-stack
+ at kindex M-,
+ at findex slime-pop-find-definition-stack
+Go back to the point where @kbd{M-.} was invoked. This gives multi-level
+backtracking when @kbd{M-.} has been used several times.
+
+ at kbditem{C-x 4 ., slime-edit-definition-other-window}
+Like @code{slime-edit-definition} but switchs to the other window to
+edit the definition in.
+
+ at kbditem{C-x 5 ., slime-edit-definition-other-frame}
+Like @code{slime-edit-definition} but opens another frame to edit the
+definition in.
+
+ at cmditem{slime-edit-definition-with-etags}
+Use an ETAGS table to find definition at point.
+
+ at end table
+
+ at c -----------------------
+ at node Macro-expansion
+ at subsubsection Macro-expansion commands
+
+ at cindex Macros
+
+ at table @kbd
+ at kbditem{C-c C-m, slime-macroexpand-1}
+Macroexpand the expression at point once. If invoked with a prefix
+argument, use macroexpand instead of macroexpand-1.
+
+ at kbditem{C-c M-m, slime-macroexpand-all}
+Fully macroexpand the expression at point.
+
+ at cmditem{slime-compiler-macroexpand-1}
+Display the compiler-macro expansion of sexp at point.
+
+ at cmditem{slime-compiler-macroexpand}
+Repeatedy expamd compiler macros of sexp at point.
+
+ at end table
+
+For additional minor-mode commands and discussion,
+ at pxref{slime-macroexpansion-minor-mode}.
+
+
+ at c -----------------------
+ at node Disassembly
+ at subsubsection Disassembly commands
+
+ at table @kbd
+
+ at kbditem{C-c M-d, slime-disassemble-symbol}
+Disassemble the function definition of the symbol at point.
+
+ at kbditem{C-c C-t, slime-toggle-trace-fdefinition}
+Toggle tracing of the function at point. If invoked with a prefix
+argument, read additional information, like which particular method
+should be traced.
+
+ at cmditem{slime-untrace-all}
+Untrace all functions.
+
+ at end table
+
+ at c -----------------------
+ at node Compilation
+ at subsection Compilation commands
+
+ at cindex Compilation
+
+ at SLIME{} has fancy commands for compiling functions, files, and
+packages. The fancy part is that notes and warnings offered by the
+Lisp compiler are intercepted and annotated directly onto the
+corresponding expressions in the Lisp source buffer. (Give it a try to
+see what this means.)
+
+ at table @kbd
+ at cindex Compiling Functions
+ at kbditem{C-c C-c, slime-compile-defun}
+Compile the top-level form at point.
+
+ at kbditem{C-c C-y, slime-call-defun}
+Insert a call to the function defined around point into the REPL.
+
+ at kbditem{C-c C-k, slime-compile-and-load-file}
+Compile and load the current buffer's source file.
+
+ at kbditem{C-c M-k, slime-compile-file}
+Compile (but don't load) the current buffer's source file.
+
+ at kbditem{C-c C-l, slime-load-file}
+Load a source file and compile if necessary, without loading into a buffer..
+
+ at kbditem{C-c C-z, slime-switch-to-output-buffer}
+Select the output buffer, preferably in a different window.
+
+ at cmditem{slime-compile-region}
+Compile region at point.
+
+ at end table
+
+The annotations are indicated as underlining on source forms. The
+compiler message associated with an annotation can be read either by
+placing the mouse over the text or with the selection commands below.
+
+ at table @kbd
+ at kbditem{M-n, slime-next-note}
+Move the point to the next compiler note and displays the note.
+
+ at kbditem{M-p, slime-previous-note}
+Move the point to the previous compiler note and displays the note.
+
+ at kbditem{C-c M-c, slime-remove-notes}
+Remove all annotations from the buffer.
+ at end table
+
+ at c -----------------------
+ at node Evaluation
+ at subsection Evaluation commands
+
+These commands each evaluate a Common Lisp expression in a different
+way. Usually they mimic commands for evaluating Emacs Lisp code. By
+default they show their results in the echo area, but a prefix
+argument causes the results to be inserted in the current buffer.
+
+ at table @kbd
+
+ at kbditem{C-x C-e, slime-eval-last-expression}
+
+Evaluate the expression before point and show the result in the echo
+area.
+
+ at kbditem{C-M-x, slime-eval-defun}
+Evaluate the current toplevel form and show the result in the echo
+area. `C-M-x' treats `defvar' expressions specially. Normally,
+evaluating a `defvar' expression does nothing if the variable it
+defines already has a value. But `C-M-x' unconditionally resets the
+variable to the initial value specified in the `defvar' expression.
+This special feature is convenient for debugging Lisp programs.
+
+ at end table
+
+If @kbd{C-M-x} or @kbd{C-x C-e} is given a numeric argument, it
+inserts the value into the current buffer, rather than displaying it
+in the echo area.
+
+ at table @kbd
+ at kbditem{C-c :, slime-interactive-eval}
+Evaluate an expression read from the minibuffer.
+
+ at kbditem{C-c C-r, slime-eval-region}
+Evaluate the region.
+
+ at kbditem{C-c C-p, slime-pprint-eval-last-expression}
+Evaluate the expression before point and pretty-print the result in a
+fresh buffer.
+
+ at kbditem{C-c E, slime-edit-value}
+Edit the value of a setf-able form in a new buffer @file{*Edit <form>*}.
+The value is inserted into a temporary buffer for editing and then set
+in Lisp when committed with @kbd{C-c C-c}.
+
+ at kbditem{C-x M-e, slime-eval-last-expression-display-output}
+Display the output buffer and evaluate the expression preceding point.
+This is useful if the expression writes something to the output stream.
+
+ at kbditem{C-c C-u, slime-undefine-function}
+Undefine the function, with @code{fmakunbound}, for the symbol at
+point.
+
+ at end table
+
+
+ at c -----------------------
+ at node Recovery
+ at subsection Abort/Recovery commands
+
+ at table @kbd
+ at kbditem{C-c C-b, slime-interrupt}
+Interrupt Lisp (send @code{SIGINT}).
+
+ at kbditem{C-c ~, slime-sync-package-and-default-directory}
+Synchronize the current package and working directory from Emacs to
+Lisp.
+
+ at kbditem{C-c M-p, slime-repl-set-package}
+Set the current package of the @acronym{REPL}.
+
+ at end table
+
+ at c -----------------------
+ at node Inspector
+ at subsection Inspector commands
+
+The @SLIME{} inspector is a Emacs-based alternative to the
+standard @code{INSPECT} function. The inspector presents objects in
+Emacs buffers using a combination of plain text, hyperlinks to related
+objects.
+
+The inspector can easily be specialized for the objects in your own
+programs. For details see the the @code{inspect-for-emacs} generic
+function in @file{swank-backend.lisp}.
+
+ at table @kbd
+
+ at kbditem{C-c I, slime-inspect}
+Inspect the value of an expression entered in the minibuffer.
+
+ at end table
+
+The standard commands available in the inspector are:
+
+ at table @kbd
+
+ at kbditem{RET, slime-inspector-operate-on-point}
+If point is on a value then recursivly call the inspcetor on that
+value. If point is on an action then call that action.
+
+ at kbditem{d, slime-inspector-describe}
+Describe the slot at point.
+
+ at kbditem{l, slime-inspector-pop}
+Go back to the previous object (return from @kbd{RET}).
+
+ at kbditem{n, slime-inspector-next}
+The inverse of @kbd{l}. Also bound to @kbd{SPC}.
+
+ at kbditem{q, slime-inspector-quit}
+Dismiss the inspector buffer.
+
+ at kbditem{M-RET, slime-inspector-copy-down}
+Store the value under point in the variable `*'. This can
+then be used to access the object in the REPL.
+
+ at end table
+
+ at c -----------------------
+ at node Profiling
+ at subsection Profiling commands
+
+The profiling commands are based on CMUCL's profiler. These are
+simple wrappers around functions which usually print something to the
+output buffer.
+
+ at table @kbd
+ at cmditem{slime-toggle-profile-fdefinition}
+Toggle profiling of a function.
+ at cmditem{slime-profile-package}
+Profile all functions in a package.
+ at cmditem{slime-unprofile-all}
+Unprofile all functions.
+ at cmditem{slime-profile-report}
+Report profiler data.
+ at cmditem{slime-profile-reset}
+Reset profiler data.
+ at cmditem{slime-profiled-functions}
+Show list of currently profiled functions.
+ at end table
+
+ at c -----------------------
+ at node Other
+ at subsection Shadowed Commands
+
+ at table @kbd
+
+ at kbditempair{C-c C-a, C-c C-v, slime-nop, slime-nop}
+This key-binding is shadowed from inf-lisp.
+
+ at end table
+
+ at c -----------------------
+ at node Semantic indentation
+ at section Semantic indentation
+
+ at SLIME{} automatically discovers how to indent the macros in your Lisp
+system. To do this the Lisp side scans all the macros in the system and
+reports to Emacs all the ones with @code{&body} arguments. Emacs then
+indents these specially, putting the first arguments four spaces in and
+the ``body'' arguments just two spaces, as usual.
+
+This should ``just work.'' If you are a lucky sort of person you needn't
+read the rest of this section.
+
+To simplify the implementation, @SLIME{} doesn't distinguish between
+macros with the same symbol-name but different packages. This makes it
+fit nicely with Emacs's indentation code. However, if you do have
+several macros with the same symbol-name then they will all be indented
+the same way, arbitrarily using the style from one of their
+arglists. You can find out which symbols are involved in collisions
+with:
+
+ at example
+(swank:print-indentation-lossage)
+ at end example
+
+If a collision causes you irritation, don't have a nervous breakdown,
+just override the Elisp symbol's @code{common-lisp-indent-function}
+property to your taste. @SLIME{} won't override your custom settings, it
+just tries to give you good defaults.
+
+A more subtle issue is that imperfect caching is used for the sake of
+performance. @footnote{@emph{Of course} we made sure it was actually too
+slow before making the ugly optimization.}
+
+In an ideal world, Lisp would automatically scan every symbol for
+indentation changes after each command from Emacs. However, this is too
+expensive to do every time. Instead Lisp usually just scans the symbols
+whose home package matches the one used by the Emacs buffer where the
+request comes from. That is sufficient to pick up the indentation of
+most interactively-defined macros. To catch the rest we make a full scan
+of every symbol each time a new Lisp package is created between commands
+-- that takes care of things like new systems being loaded.
+
+You can use @kbd{M-x slime-update-indentation} to force all symbols to
+be scanned for indentation information.
+
+ at c -----------------------
+ at node Reader conditionals
+ at section Reader conditional fontification
+
+ at SLIME{} automatically evaluates reader-conditional expressions, like
+ at code{#+linux}, in source buffers and ``grays out'' code that will be
+skipped for the current Lisp connection.
+
+
+ at c -----------------------
+ at node REPL
+ at chapter REPL: the ``top level''
+
+ at cindex Listener
+
+ at SLIME{} uses a custom Read-Eval-Print Loop (@REPL{}, also known as a
+``top level'', or listener). The @REPL{} user-interface is written in
+Emacs Lisp, which gives more Emacs-integration than the traditional
+ at code{comint}-based Lisp interaction:
+
+ at itemize @bullet
+ at item
+Conditions signalled in @REPL{} expressions are debugged with @SLDB{}.
+ at item
+Return values are distinguished from printed output by separate Emacs
+faces (colours).
+ at item
+Emacs manages the @REPL{} prompt with markers. This ensures that Lisp
+output is inserted in the right place, and doesn't get mixed up with
+user input.
+ at end itemize
+
+ at menu
+* REPL commands::
+* Input Navigation::
+* Shortcuts::
+ at end menu
+
+ at c -----------------------
+ at node REPL commands
+ at section REPL commands
+
+ at table @kbd
+
+ at kbditem{RET, slime-repl-return}
+Evaluate the current input in Lisp if it is complete. If incomplete,
+open a new line and indent. If a prefix argument is given then the
+input is evaluated without checking for completeness.
+
+ at kbditem{C-RET, slime-repl-closing-return}
+Close any unmatched parenthesis and then evaluate the current input in
+Lisp. Also bound to @kbd{M-RET}.
+
+ at kbditem{C-j, slime-repl-newline-and-indent}
+Open and indent a new line.
+
+ at kbditem{C-a, slime-repl-bol}
+Go to the beginning of the line, but stop at the @REPL{} prompt.
+
+ at c @anchor{slime-interrupt}
+ at kbditem{C-c C-c, slime-interrupt}
+Interrupt the Lisp process with @code{SIGINT}.
+
+ at c @kbditem{C-c M-g, slime-quit}
+ at c Quit slime.
+
+ at kbditem{C-c C-t, slime-repl-clear-buffer}
+Clear the entire buffer, leaving only a prompt.
+
+ at kbditem{C-c C-o, slime-repl-clear-output}
+Remove the output and result of the previous expression from the
+buffer.
+
+ at end table
+
+ at c -----------------------
+ at node Input Navigation
+ at section Input navigation
+
+ at cindex Input History
+
+The input navigation (a.k.a. history) commands are modelled after
+ at code{coming}-mode. Be careful if you are used to Bash-like
+keybindings: @kbd{M-p} and @kbd{M-n} use the current input as search
+pattern and only work Bash-like if the current line is
+empty. @kbd{C-<up>} and @kbd{C-<up>} work like the up and down keys in
+Bash.
+
+ at table @kbd
+
+ at kbditempair{C-<up>, C-<down>,
+ slime-repl-forward-input, slime-repl-backward-input}
+Go to the next/previous history item.
+
+ at kbditempair{M-n, M-p, slime-repl-next-input, slime-repl-previous-input}
+Search the next/previous item in the command history using the current
+input as search pattern. If @kbd{M-n}/@kbd{M-n} is typed two times in
+a row, the second invocation uses the same search pattern (even if the
+current input has changed).
+
+ at kbditempair{M-s, M-r,
+slime-repl-next-matching-input, slime-repl-previous-matching-input}
+Search forward/reverse through command history with regex
+
+ at c @code{slime-repl-@{next,previous@}-input}@*
+ at c @code{slime-repl-@{next,previous@}-matching-input}@*
+ at c @code{comint}-style input history commands.
+
+ at kbditempair{C-c C-n, C-c C-p,
+slime-repl-next-prompt, slime-repl-previous-prompt}
+Move between the current and previous prompts in the @REPL{} buffer.
+Pressing RET on a line with old input copies that line to the newest
+prompt.
+ at end table
+
+ at vindex slime-repl-wrap-history
+The variable @code{slime-repl-wrap-history} controls wrap around
+behaviour, i.e. whether cycling should restart at the beginning of the
+history if the end is reached.
+
+ at c -----------------------
+ at comment node-name, next, previous, up
+ at node Shortcuts
+ at section Shortcuts
+
+ at cindex Shortcuts
+
+``Shortcuts'' are a special set of @REPL{} commands that are invoked
+by name. To invoke a shortcut you first press @kbd{,} (comma) at the
+ at REPL{} prompt and then enter the shortcut's name when prompted.
+
+Shortcuts deal with things like switching between directories and
+compiling and loading Lisp systems. The set of shortcuts is listed
+below, and you can also use the @code{help}
+shortcut to list them interactively.
+
+ at table @kbd
+ at item change-directory (aka !d, cd)
+Change the current directory.
+
+ at item change-package (aka !p)
+Change the current package.
+
+ at item compile-and-load (aka cl)
+Compile (if neccessary) and load a lisp file.
+
+
+ at item defparameter (aka !)
+Define a new global, special, variable.
+
+ at item help (aka ?)
+Display the help.
+
+
+
+ at item pop-directory (aka -d)
+Pop the current directory.
+
+ at item pop-package (aka -p)
+Pop the top of the package stack.
+
+ at item push-directory (aka +d, pushd)
+Push a new directory onto the directory stack.
+
+ at item push-package (aka +p)
+Push a package onto the package stack.
+
+ at item pwd
+Show the current directory.
+
+ at item quit
+Quit the current Lisp.
+
+ at item resend-form
+Resend the last form.
+
+ at item restart-inferior-lisp
+Restart *inferior-lisp* and reconnect SLIME.
+
+ at item sayoonara
+Quit all Lisps and close all SLIME buffers.
+
+ at end table
+
+ at c -----------------------
+ at node Debugger
+ at chapter SLDB: the SLIME debugger
+
+ at cindex Debugger
+
+ at SLIME{} has a custom Emacs-based debugger called @SLDB{}. Conditions
+signalled in the Lisp system invoke @SLDB{} in Emacs by way of the
+Lisp @code{*DEBUGGER-HOOK*}.
+
+ at SLDB{} pops up a buffer when a condition is signalled. The buffer
+displays a description of the condition, a list of restarts, and a
+backtrace. Commands are offered for invoking restarts, examining the
+backtrace, and poking around in stack frames.
+
+ at menu
+* Examining frames::
+* Restarts::
+* Frame Navigation::
+* Stepping::
+* Miscellaneous::
+ at end menu
+
+ at c -----------------------
+ at node Examining frames
+ at section Examining frames
+
+Commands for examining the stack frame at point.
+
+ at table @kbd
+ at kbditem{t, sldb-toggle-details}
+Toggle display of local variables and @code{CATCH} tags.
+
+ at kbditem{v, sldb-show-source}
+View the frame's current source expression. The expression is
+presented in the Lisp source file's buffer.
+
+ at kbditem{e, sldb-eval-in-frame}
+Evaluate an expression in the frame. The expression can refer to the
+available local variables in the frame.
+
+ at kbditem{d, sldb-pprint-eval-in-frame}
+Evaluate an expression in the frame and pretty-print the result in a
+temporary buffer.
+
+ at kbditem{D, sldb-disassemble}
+Disassemble the frame's function. Includes information such as the
+instruction pointer within the frame.
+
+ at kbditem{i, sldb-inspect-in-frame}
+Inspect the result of evaluating an expression in the frame.
+ at end table
+
+ at c -----------------------
+ at node Restarts
+ at section Invoking restarts
+
+ at table @kbd
+ at kbditem{a, sldb-abort}
+Invoke the @code{ABORT} restart.
+
+ at kbditem{q, sldb-quit}
+``Quit'' -- @code{THROW} to a tag that the top-level @SLIME{}
+request-loop catches.
+
+ at kbditem{c, sldb-continue}
+Invoke the @code{CONTINUE} restart.
+
+ at item 0 ... 9
+Invoke a restart by number.
+ at end table
+
+Restarts can also be invoked by pressing @kbd{RET} or @kbd{Mouse-2} on
+them in the buffer.
+
+ at c -----------------------
+ at node Frame Navigation
+ at section Navigating between frames
+
+ at table @kbd
+ at kbditempair{n,p,sldb-down,sldb-up}
+Move between frames.
+
+ at kbditempair{M-n, M-p, sldb-details-down, sldb-details-up}
+Move between frames ``with sugar'': hide the details of the original
+frame and display the details and source code of the next. Sugared
+motion makes you see the details and source code for the current frame
+only.
+ at end table
+
+ at node Stepping
+ at section Stepping
+
+ at cindex Stepping
+
+Stepping is not available in all implementations and works very
+differently in those in which it is available.
+
+ at table @kbd
+ at kbditem{s, sldb-step}
+Step to the next expression in the frame. For CMUCL that means, set a
+breakpoint at all those code locations in the current code block which
+are reachable from the current code location.
+
+ at kbditem{x, sldb-next}
+[Step to the next form in the current function.]
+
+ at kbditem{o, sldb-next}
+[Stop single-stepping temporarily, but resume it once the current
+function returns.]
+
+ at end table
+
+ at node Miscellaneous
+ at section Miscellaneous Commands
+
+ at table @kbd
+ at kbditem{r, sldb-restart-frame}
+Restart execution of the frame with the same arguments it was
+originally called with. (This command is not available in all
+implementations.)
+
+ at kbditem{R, sldb-return-from-frame}
+Return from the frame with a value entered in the minibuffer. (This
+command is not available in all implementations.)
+
+
+ at kbditem{B, sldb-break-with-default-debugger}
+Exit @SLDB{} and debug the condition using the Lisp system's default
+debugger.
+
+ at kbditem{:, slime-interactive-eval}
+Evaluate an expression entered in the minibuffer.
+ at end table
+
+
+ at c -----------------------
+ at node Misc
+ at chapter Misc
+
+ at menu
+* slime-selector::
+* slime-macroexpansion-minor-mode::
+* Multiple connections::
+ at end menu
+
+ at c -----------------------
+ at node slime-selector
+ at section @code{slime-selector}
+
+The @code{slime-selector} command is for quickly switching to
+important buffers: the @REPL{}, @SLDB{}, the Lisp source you were just
+hacking, etc. Once invoked the command prompts for a single letter to
+specify which buffer it should display. Here are some of the options:
+
+ at table @kbd
+ at item ?
+A help buffer listing all @code{slime-selectors}'s available buffers.
+ at item r
+The @REPL{} buffer for the current @SLIME{} connection.
+ at item d
+The most recently activated @SLDB{} buffer for the current connection.
+ at item l
+The most recently visited @code{lisp-mode} source buffer.
+ at item s
+The @code{*slime-scratch*} buffer (@pxref{slime-scratch}).
+ at end table
+
+ at code{slime-selector} doesn't have a key binding by default but we
+suggest that you assign it a global one. You can bind it to @kbd{C-c s}
+like this:
+
+ at example
+(global-set-key "\C-cs" 'slime-selector)
+ at end example
+
+ at noindent
+And then you can switch to the @REPL{} from anywhere with @kbd{C-c s
+r}.
+
+The macro @code{def-slime-selector-method} can be used to define new
+buffers for @code{slime-selector} to find.
+
+ at c -----------------------
+ at node slime-macroexpansion-minor-mode
+ at section slime-macroexpansion-minor-mode
+
+Within a slime macroexpansion buffer some extra commands are provided
+(these commands are always available but are only bound to keys in a
+macroexpansion buffer).
+
+ at table @kbd
+ at kbditem{C-c C-m, slime-macroexpand-1-inplace}
+Just like slime-macroexpand-1 but the original form is replaced with
+the expansion.
+
+ at c @anchor{slime-macroexpand-1-inplace}
+ at kbditem{g, slime-macroexpand-1-inplace}
+The last macroexpansion is performed again, the current contents of
+the macroexpansion buffer are replaced with the new expansion.
+
+ at kbditem{q, slime-temp-buffer-quit}
+Close the expansion buffer.
+
+ at end table
+
+ at c -----------------------
+ at node Multiple connections
+ at section Multiple connections
+
+ at SLIME{} is able to connect to multiple Lisp processes at the same
+time. The @kbd{M-x slime} command, when invoked with a prefix
+argument, will offer to create an additional Lisp process if one is
+already running. This is often convenient, but it requires some
+understanding to make sure that your @SLIME{} commands execute in the
+Lisp that you expect them to.
+
+Some buffers are tied to specific Lisp processes. Each Lisp connection
+has its own @acronym{REPL} buffer, and all expressions entered or
+ at SLIME{} commands invoked in that buffer are sent to the associated
+connection. Other buffers created by @SLIME{} are similarly tied to
+the connections they originate from, including @SLDB{} buffers,
+apropos result listings, and so on. These buffers are the result of
+some interaction with a Lisp process, so commands in them always go
+back to that same process.
+
+Commands executed in other places, such as @code{slime-mode} source
+buffers, always use the ``default'' connection. Usually this is the
+most recently established connection, but this can be reassigned via
+the ``connection list'' buffer:
+
+ at table @kbd
+ at kbditem{C-c C-x c, slime-list-connections}
+Pop up a buffer listing the established connections.
+
+ at kbditem{C-c C-x t, slime-list-threads}
+Pop up a buffer listing the current threads.
+
+ at end table
+
+The buffer displayed by @code{slime-list-connections} gives a one-line
+summary of each connection. The summary shows the connection's serial
+number, the name of the Lisp implementation, and other details of the
+Lisp process. The current ``default'' connection is indicated with an
+asterisk.
+
+The commands available in the connection-list buffer are:
+
+ at table @kbd
+ at kbditem{RET, slime-goto-connection}
+Pop to the @acronym{REPL} buffer of the connection at point.
+
+ at kbditem{d, slime-connection-list-make-default}
+Make the connection at point the ``default'' connection. It will then
+be used for commands in @code{slime-mode} source buffers.
+
+ at kbditem{g, slime-update-connection-list}
+Update the connection list in the buffer.
+
+ at kbditem{q, slime-temp-buffer-quit}
+Quit the connection list (kill buffer, restore window configuration).
+
+ at kbditem{R, slime-restart-connection-at-point}
+Restart the Lisp process for the connection at point.
+
+ at cmditem{slime-connect}
+Connect to a running Swank server.
+
+ at cmditem{slime-disconnect}
+Disconnect all connections.
+
+ at cmditem{slime-abort-connection}
+Abort the current attempt to connect.
+
+ at end table
+
+
+ at c -----------------------
+ at node Customization
+ at chapter Customization
+
+ at menu
+* Emacs-side customization::
+* Lisp-side::
+ at end menu
+
+ at c -----------------------
+ at node Emacs-side customization
+ at section Emacs-side
+
+The Emacs part of @SLIME{} can be configured with the Emacs
+ at code{customize} system, just use @kbd{M-x customize-group slime
+RET}. Because the customize system is self-describing, we only cover a
+few important or obscure configuration options here in the manual.
+
+ at table @code
+
+ at item slime-truncate-lines
+The value to use for @code{truncate-lines} in line-by-line summary
+buffers popped up by @SLIME{}. This is @code{t} by default, which
+ensures that lines do not wrap in backtraces, apropos listings, and so
+on. It can however cause information to spill off the screen.
+
+ at anchor{slime-complete-symbol-function}
+ at vindex slime-complete-symbol-function
+ at item slime-complete-symbol-function
+The function to use for completion of Lisp symbols. Three completion
+styles are available: @code{slime-simple-complete-symbol},
+ at code{slime-complete-symbol*} (@pxref{Compound Completion}),
+and @code{slime-fuzzy-complete-symbol} (@pxref{Fuzzy Completion}).
+
+The default is @code{slime-simple-complete-symbol}, which completes in
+the usual Emacs way.
+
+ at vindex slime-filename-translations
+ at item slime-filename-translations
+This variable controls filename translation between Emacs and the Lisp
+system. It is useful if you run Emacs and Lisp on separate machines
+which don't share a common file system or if they share the filessytem
+but have different layouts, as is the case with @acronym{SMB}-based
+file sharing.
+
+ at anchor{slime-net-coding-system}
+ at vindex slime-net-coding-system
+ at cindex Unicode
+ at cindex UTF-8
+ at cindex ASCII
+ at cindex LATIN-1
+ at cindex Character Encoding
+ at item slime-net-coding-system
+If you want to transmit Unicode characters between Emacs and the Lisp
+system, you should customize this variable. E.g., if you use SBCL, you
+can set:
+ at example
+(setq slime-net-coding-system 'utf-8-unix)
+ at end example
+To actually display Unicode characters you also need appropriate
+fonts, otherwise the characters will be rendered as hollow boxes. If
+you are using Allegro CL and GNU Emacs, you can also
+use @code{emacs-mule-unix} as coding system. GNU Emacs has often
+nicer fonts for the latter encoding. (Different encodings can be used
+for different Lisps, see @ref{Multiple Lisps}.)
+
+ at end table
+
+ at menu
+* Hooks::
+ at end menu
+
+ at c -----------------------
+ at node Hooks
+ at subsection Hooks
+
+ at table @code
+
+ at vindex slime-mode-hook
+ at item slime-mode-hook
+This hook is run each time a buffer enters @code{slime-mode}. It is
+most useful for setting buffer-local configuration in your Lisp source
+buffers. An example use is to enable @code{slime-autodoc-mode}
+(@pxref{slime-autodoc-mode}).
+
+ at anchor{slime-connected-hook}
+ at vindex slime-connected-hook
+ at item slime-connected-hook
+This hook is run when @SLIME{} establishes a connection to a Lisp
+server. An example use is to create a Typeout frame (@xref{Typeout frames}.)
+
+ at vindex sldb-hook
+ at item sldb-hook
+This hook is run after @SLDB{} is invoked. The hook functions are
+called from the @SLDB{} buffer after it is initialized. An example use
+is to add @code{sldb-print-condition} to this hook, which makes all
+conditions debugged with @SLDB{} be recorded in the @REPL{} buffer.
+
+ at end table
+
+ at c -----------------------
+ at node Lisp-side
+ at section Lisp-side (Swank)
+
+The Lisp server side of @SLIME{} (known as ``Swank'') offers several
+variables to configure. The initialization file @file{~/.swank.lisp}
+is automatically evaluated at startup and can be used to set these
+variables.
+
+ at menu
+* Communication style::
+* Other configurables::
+ at end menu
+
+ at c -----------------------
+ at node Communication style
+ at subsection Communication style
+ at vindex SWANK:*COMMUNICATION-STYLE*
+
+The most important configurable is @code{SWANK:*COMMUNICATION-STYLE*},
+which specifies the mechanism by which Lisp reads and processes
+protocol messages from Emacs. The choice of communication style has a
+global influence on @SLIME{}'s operation.
+
+The available communication styles are:
+
+ at table @code
+ at item NIL
+This style simply loops reading input from the communication socket
+and serves @SLIME{} protocol events as they arise. The simplicity
+means that the Lisp cannot do any other processing while under
+ at SLIME{}'s control.
+
+ at item :FD-HANDLER
+This style uses the classical Unix-style ``@code{select()}-loop.''
+Swank registers the communication socket with an event-dispatching
+framework (such as @code{SERVE-EVENT} in @acronym{CMUCL} and
+ at acronym{SBCL}) and receives a callback when data is available. In
+this style requests from Emacs are only detected and processed when
+Lisp enters the event-loop. This style is simple and predictable.
+
+ at item :SIGIO
+This style uses @dfn{signal-driven I/O} with a @code{SIGIO} signal
+handler. Lisp receives requests from Emacs along with a signal,
+causing it to interrupt whatever it is doing to serve the
+request. This style has the advantage of responsiveness, since Emacs
+can perform operations in Lisp even while it is busy doing other
+things. It also allows Emacs to issue requests concurrently, e.g. to
+send one long-running request (like compilation) and then interrupt
+that with several short requests before it completes. The
+disadvantages are that it may conflict with other uses of @code{SIGIO}
+by Lisp code, and it may cause untold havoc by interrupting Lisp at an
+awkward moment.
+
+ at item :SPAWN
+This style uses multiprocessing support in the Lisp system to execute
+each request in a separate thread. This style has similar properties
+to @code{:SIGIO}, but it does not use signals and all requests issued
+by Emacs can be executed in parallel.
+
+ at end table
+
+The default request handling style is chosen according to the
+capabilities of your Lisp system. The general order of preference is
+ at code{:SPAWN}, then @code{:SIGIO}, then @code{:FD-HANDLER}, with
+ at code{NIL} as a last resort. You can check the default style by
+calling @code{SWANK-BACKEND:PREFERRED-COMMUNICATION-STYLE}. You can
+also override the default by setting
+ at code{SWANK:*COMMUNICATION-STYLE*} in your Swank init file.
+
+ at c -----------------------
+ at node Other configurables
+ at subsection Other configurables
+
+These Lisp variables can be configured via your @file{~/.swank.lisp}
+file:
+
+ at table @code
+
+ at vindex SWANK:*CONFIGURE-EMACS-INDENTATION*
+ at item SWANK:*CONFIGURE-EMACS-INDENTATION*
+This variable controls whether indentation styles for
+ at code{&body}-arguments in macros are discovered and sent to Emacs. It
+is enabled by default.
+
+ at vindex SWANK:*GLOBALLY-REDIRECT-IO*
+ at item SWANK:*GLOBALLY-REDIRECT-IO*
+When true this causes the standard streams (@code{*standard-output*},
+etc) to be globally redirected to the @REPL{} in Emacs. When
+ at code{NIL} (the default) these streams are only temporarily redirected
+to Emacs using dynamic bindings while handling requests. Note that
+ at code{*standard-input*} is currently never globally redirected into
+Emacs, because it can interact badly with the Lisp's native @REPL{} by
+having it try to read from the Emacs one.
+
+ at vindex SWANK:*GLOBAL-DEBUGGER*
+ at item SWANK:*GLOBAL-DEBUGGER*
+When true (the default) this causes @code{*DEBUGGER-HOOK*} to be
+globally set to @code{SWANK:SWANK-DEBUGGER-HOOK} and thus for @SLIME{}
+to handle all debugging in the Lisp image. This is for debugging
+multithreaded and callback-driven applications.
+
+ at vindex SWANK:*SLDB-PRINTER-BINDINGS*
+ at vindex SWANK:*MACROEXPAND-PRINTER-BINDINGS*
+ at vindex SWANK:*SWANK-PPRINT-BINDINGS*
+ at item SWANK:*SLDB-PRINTER-BINDINGS*
+ at itemx SWANK:*MACROEXPAND-PRINTER-BINDINGS*
+ at itemx SWANK:*SWANK-PPRINT-BINDINGS*
+These variables can be used to customize the printer in various
+situations. The values of the variables are association lists of
+printer variable names with the corresponding value. E.g., to enable
+the pretty printer for formatting backtraces in @SLDB{}, you can use:
+ at example
+(push '(*print-pretty* . t) swank:*sldb-printer-bindings*).
+ at end example
+
+ at vindex SWANK:*USE-DEDICATED-OUTPUT-STREAM*
+ at item SWANK:*USE-DEDICATED-OUTPUT-STREAM*
+This variable controls whether to use an unsafe efficiency hack for
+sending printed output from Lisp to Emacs. The default is @code{nil},
+don't use it, and is strongly recommended to keep.
+
+When @code{t}, a separate socket is established solely for Lisp to send
+printed output to Emacs through, which is faster than sending the output
+in protocol-messages to Emacs. However, as nothing can be guaranteed
+about the timing between the dedicated output stream and the stream of
+protocol messages, the output of a Lisp command can arrive before or
+after the corresponding REPL results. Thus output and REPL results can
+end up in the wrong order, or even interleaved, in the REPL buffer.
+Using a dedicated output stream also makes it more difficult to
+communicate to a Lisp running on a remote host via SSH
+(@pxref{Connecting to a remote lisp}).
+
+ at vindex SWANK:*DEDICATED-OUTPUT-STREAM-PORT*
+ at item SWANK:*DEDICATED-OUTPUT-STREAM-PORT*
+When @code{*USE-DEDICATED-OUTPUT-STREAM*} is @code{t} the stream will
+be opened on this port. The default value, @code{0}, means that the
+stream will be opened on some random port.
+
+ at vindex SWANK:*LOG-EVENTS*
+ at item SWANK:*LOG-EVENTS*
+Setting this variable to @code{t} causes all protocol messages
+exchanged with Emacs to be printed to @code{*TERMINAL-IO*}. This is
+useful for low-level debugging and for observing how @SLIME{} works
+``on the wire.'' The output of @code{*TERMINAL-IO*} can be found in
+your Lisp system's own listener, usually in the buffer
+ at code{*inferior-lisp*}.
+
+ at end table
+
+ at c -----------------------
+ at node Tips and Tricks
+ at chapter Tips and Tricks
+
+ at menu
+* Connecting to a remote lisp::
+* Global IO Redirection::
+* Auto-SLIME::
+ at end menu
+
+ at c -----------------------
+ at node Connecting to a remote lisp
+ at section Connecting to a remote lisp
+
+One of the advantages of the way @SLIME{} is implemented is that we
+can easily run the Emacs side (slime.el) on one machine and the lisp
+backend (swank) on another. The basic idea is to start up lisp on the
+remote machine, load swank and wait for incoming slime connections. On
+the local machine we start up emacs and tell slime to connect to the
+remote machine. The details are a bit messier but the underlying idea
+is that simple.
+
+ at menu
+* Setting up the lisp image::
+* Setting up Emacs::
+* Setting up pathname translations::
+ at end menu
+
+ at c -----------------------
+ at node Setting up the lisp image
+ at subsection Setting up the lisp image
+
+
+When you want to load swank without going through the normal, Emacs
+based, process just load the @file{swank-loader.lisp} file. Just
+execute
+
+ at example
+(load "/path/to/swank-loader.lisp")
+ at end example
+
+inside a running lisp image at footnote{@SLIME{} also provides an
+ at acronym{ASDF} system definiton which does the same thing}. Now all we
+need to do is startup our swank server. The first example assumes we're
+using the default settings.
+
+ at example
+(swank:create-server)
+ at end example
+
+Since we're going to be tunneling our connection via
+ssh at footnote{there is a way to connect without an ssh tunnel, but it
+has the side-effect of giving the entire world access to your lisp
+image, so we're not going to talk about it} and we'll only have one
+port open we want to tell swank to not use an extra connection for
+output (this is actually the default in current SLIME):
+
+ at example
+(setf swank:*use-dedicated-output-stream* nil)
+ at end example
+
+ at c -----------------------
+If you need to do anything particular
+(like be able to reconnect to swank after you're done), look into
+ at code{swank:create-server}'s other arguments. Some of these arguments
+are
+ at table @code
+
+ at item :PORT
+Port number for the server to listen on (default: 4005).
+ at item :STYLE
+See @xref{Communication style}.
+ at item :DONT-CLOSE
+Boolean indicating if the server will continue to accept connections
+after the first one (default: @code{NIL}). For ``long-running'' lisp processes
+to which you want to be able to connect from time to time,
+specify @code{:dont-close t}
+ at item :CODING-SYSTEM
+String designating the encoding to be used to communicate between the
+Emacs and Lisp.
+ at end table
+
+So the more complete example will be
+ at example
+(swank:create-server :port 4005 :dont-close t :coding-system "utf-8-unix")
+ at end example
+On the emacs side you will use something like
+ at example
+(setq slime-net-coding-system 'utf-8-unix)
+(slime-connect "127.0.0.1" 4005))
+ at end example
+to connect to this lisp image from the same machine.
+
+
+ at node Setting up Emacs
+ at subsection Setting up Emacs
+
+Now we need to create the tunnel between the local machine and the
+remote machine.
+
+ at example
+ssh -L4005:127.0.0.1:4005 username@@remote.example.com
+ at end example
+
+That ssh invocation creates an ssh tunnel between the port 4005 on our
+local machine and the port 4005 on the remote machine at footnote{By
+default swank listens for incoming connections on port 4005, had we
+passed a @code{:port} parameter to @code{swank:create-server} we'd be
+using that port number instead}.
+
+Finally we can start @SLIME{}:
+
+ at example
+M-x slime-connect RET RET
+ at end example
+
+The @kbd{RET RET} sequence just means that we want to use the default
+host (@code{127.0.0.1}) and the default port (@code{4005}). Even
+though we're connecting to a remote machine the ssh tunnel fools Emacs
+into thinking it's actually @code{127.0.0.1}.
+
+ at c -----------------------
+ at node Setting up pathname translations
+ at subsection Setting up pathname translations
+
+One of the main problems with running swank remotely is that Emacs
+assumes the files can be found using normal filenames. if we want
+things like @code{slime-compile-and-load-file} (@kbd{C-c C-k}) and
+ at code{slime-edit-definition} (@kbd{M-.}) to work correctly we need to
+find a way to let our local Emacs refer to remote files.
+
+There are, mainly, two ways to do this. The first is to mount, using
+NFS or similar, the remote machine's hard disk on the local machine's
+file system in such a fashion that a filename like
+ at file{/opt/project/source.lisp} refers to the same file on both
+machines. Unfortunetly NFS is usually slow, often buggy, and not
+always feasable, fortunetely we have an ssh connection and Emacs'
+ at code{tramp-mode} can do the rest.
+(See @inforef{Top, TRAMP User Manual,tramp}.)
+
+What we do is teach Emacs how to take a filename on the remote machine
+and translate it into something that tramp can understand and access
+(and vice-versa). Assuming the remote machine's host name is
+ at code{remote.example.com}, @code{cl:machine-instance} returns
+``remote'' and we login as the user ``user'' we can use @SLIME{}'s
+built-in mechanism to setup the proper transaltions by simply doing:
+
+ at example
+(push (slime-create-filename-translator :machine-instance "remote.example.com"
+ :remote-host "remote"
+ :username "user")
+ slime-filename-translations)
+ at end example
+
+ at c -----------------------
+ at node Global IO Redirection
+ at section Globally redirecting all IO to the REPL
+
+By default @SLIME{} does not change @code{*standard-output*} and
+friends outside of the @REPL{}. If you have any other threads which
+call @code{format}, @code{write-string}, etc. that output will be seen
+only in the @code{*inferior-lisp*} buffer or on the terminal, more
+often than not this is inconvenient. So, if you want code such as this:
+
+ at example
+(run-in-new-thread
+ (lambda ()
+ (write-line "In some random thread.~%" *standard-output*)))
+ at end example
+
+to send its output to @SLIME{}'s repl buffer, as opposed to
+ at code{*inferior-lisp*}, set @code{swank:*globally-redirect-io*} to T.
+
+Note that the value of this variable is only checked when swank
+accepts the connection so you should set it via
+ at file{~/.swank.lisp}. Otherwise you will need to call
+ at code{swank::globally-redirect-io-to-connection} yourself, but you
+shouldn't do that unless you know what you're doing.
+
+ at c -----------------------
+ at node Auto-SLIME
+ at section Connecting to SLIME automatically
+
+To make @SLIME{} connect to your lisp whenever you open a lisp file
+just add this to your @file{.emacs}:
+
+ at example
+(add-hook 'slime-mode-hook
+ (lambda ()
+ (unless (slime-connected-p)
+ (save-excursion (slime)))))
+ at end example
+
+ at node Contributed Packages
+ at chapter Contributed Packages
+
+In version 3.0 we moved some functionility to separate packages. This
+chapter tells you how to load contrib modules and describes what the
+particular packages do.
+
+ at menu
+* Loading Contribs::
+* Compound Completion::
+* Fuzzy Completion::
+* slime-autodoc-mode::
+* ASDF::
+* Banner::
+* Editing Commands::
+* Fancy Inspector::
+* Presentations::
+* Typeout frames::
+* TRAMP::
+* Documentation Links::
+* Xref and Class Browser::
+* Highlight Edits::
+* inferior-slime-mode::
+* Scratch Buffer::
+* slime-fancy::
+ at end menu
+
+ at node Loading Contribs
+ at section Loading Contrib Packages
+
+ at cindex Contribs
+ at cindex Contributions
+ at cindex Plugins
+
+Contrib packages aren't loaded by default. You have to modify your
+setup a bit so that Emacs knows where to find them and which of them
+to load, i.e. you should add the contrib directory to
+Emacs' @code{load-path} and call @code{slime-setup} with the list of
+package-names. For example, a setup to load the @code{slime-scratch}
+and @code{slime-editing-commands} looks like:
+
+ at example
+(add-to-list 'load-path ".../slime") ; path for core
+(add-to-list 'load-path ".../slime/contrib") ; path for contribs
+(require 'slime-autoloads)
+(slime-setup '(slime-scratch slime-editing-commands))
+ at end example
+
+After starting SLIME, the commands of both packages should be
+available.
+
+ at node Compound Completion
+ at section Compund Completion
+
+ at anchor{slime-complete-symbol*}
+The package @code{slime-c-p-c} provides a different symbol completion
+algorithm, which performs completion ``in parallel'' over the
+hyphen-delimited sub-words of a symbol name.
+ at footnote{This style of completion is modelled on @file{completer.el}
+by Chris McConnell. That package is bundled with @acronym{ILISP}.}
+Formally this means that ``@code{a-b-c}'' can complete to any symbol
+matching the regular expression ``@code{^a.*-b.*-c.*}'' (where ``dot''
+matches anything but a hyphen). Examples give a more intuitive
+feeling:
+ at itemize @bullet
+ at item
+ at code{m-v-b} completes to @code{multiple-value-bind}.
+ at item
+ at code{w-open} is ambiguous: it completes to either
+ at code{with-open-file} or @code{with-open-stream}. The symbol is
+expanded to the longest common completion (@code{with-open-}) and the
+point is placed at the first point of ambiguity, which in this case is
+the end.
+ at item
+ at code{w--stream} completes to @code{with-open-stream}.
+ at end itemize
+
+The variable @code{slime-c-p-c-unambiguous-prefix-p} specifies where
+point should be placed after completion. E.g. the possible
+completions for @code{f-o} are @code{finish-output} and
+ at code{force-output}. By the default point is moved after the
+ at code{f}, because that is the unambigous prefix. If
+ at code{slime-c-p-c-unambiguous-prefix-p} is nil, point moves to
+the end of the inserted text, after the @code{o} in this case.
+
+ at table @kbd
+ at kbditem{C-c C-s, slime-complete-form}
+Looks up and inserts into the current buffer the argument list for the
+function at point, if there is one. More generally, the command
+completes an incomplete form with a template for the missing arguments.
+There is special code for discovering extra keywords of generic
+functions and for handling @code{make-instance} and
+ at code{defmethod}. Examples:
+
+ at example
+(subseq "abc" <C-c C-s>
+ --inserts--> start [end])
+(find 17 <C-c C-s>
+ --inserts--> sequence :from-end from-end :test test
+ :test-not test-not :start start :end end
+ :key key)
+(find 17 '(17 18 19) :test #'= <C-c C-s>
+ --inserts--> :from-end from-end
+ :test-not test-not :start start :end end
+ :key key)
+(defclass foo () ((bar :initarg :bar)))
+(defmethod print-object <C-c C-s>
+ --inserts--> (object stream)
+ body...)
+(defmethod initialize-instance :after ((object foo) &key blub))
+(make-instance 'foo <C-c C-s>
+ --inserts--> :bar bar :blub blub initargs...)
+ at end example
+ at end table
+
+ at node Fuzzy Completion
+ at section Fuzzy Completion
+
+The package @code{slime-fuzzy} implements yet another symbol
+completion heuristic.
+
+[Somebody please describe what the algorithm actually does]
+
+It attempts to complete a symbol all at once, instead of in pieces.
+For example, ``mvb'' will find ``@code{multiple-value-bind}'' and
+``norm-df'' will find
+``@code{least-positive-normalized-double-float}''.
+
+The algorithm tries to expand every character in various ways and
+rates the list of possible completions with the following heuristic.
+
+Letters are given scores based on their position in the string.
+Letters at the beginning of a string or after a prefix letter at
+the beginning of a string are scored highest. Letters after a
+word separator such as #\- are scored next highest. Letters at
+the end of a string or before a suffix letter at the end of a
+string are scored medium, and letters anywhere else are scored
+low.
+
+If a letter is directly after another matched letter, and its
+intrinsic value in that position is less than a percentage of the
+previous letter's value, it will use that percentage instead.
+
+Finally, a small scaling factor is applied to favor shorter
+matches, all other things being equal.
+
+ at table @kbd
+ at anchor{slime-fuzzy-complete-symbol}
+ at kbditem{C-c M-i, slime-fuzzy-complete-symbol}
+Presents a list of likely completions to choose from for an
+abbreviation at point. If you set the
+variable @code{slime-complete-symbol-function} to this command, fuzzy
+completion will also be used for @kbd{M-TAB}.
+ at end table
+
+ at node slime-autodoc-mode
+ at section @code{slime-autodoc-mode}
+
+Autodoc mode is an additional minor-mode for automatically showing
+information about symbols near the point. For function names the
+argument list is displayed, and for global variables, the value.
+This is a clone of @code{eldoc-mode} for Emacs Lisp.
+
+The mode can be enabled by default in the @code{slime-setup} call of your
+ at code{~/.emacs}:
+ at example
+(slime-setup '(slime-autodoc))
+ at end example
+
+ at table @kbd
+ at cmditem{slime-arglist NAME}
+Show the argument list of the function NAME.
+
+ at cmditem{slime-autodoc-mode}
+Toggles autodoc-mode on or off according to the argument, and
+toggles the mode when invoked without argument.
+ at end table
+
+If the variable @code{slime-use-autodoc-mode} is set (default), Emacs
+starts a timer, otherwise the information is only displayed after
+pressing SPC.
+
+ at node ASDF
+ at section ASDF
+
+ at acronym{ASDF} is a popular ``system construction tool''. The package
+ at code{slime-asdf} provides some commands to load and compile such
+systems from Emacs. @acronym{ASDF} itself is not included with
+ at SLIME{}; you have to load that yourself into your Lisp. In
+particular, you must load @acronym{ASDF} before you connect, otherwise
+you will get errors about missing symbols.
+
+ at table @kbd
+ at cmditem{slime-load-system NAME}
+Compile and load an ASDF system. The default system name is taken
+from the first file matching *.asd in the current directory.
+ at end table
+
+The package also installs some new REPL shortcuts (@pxref{Shortcuts}):
+
+ at table @kbd
+ at item load-system
+Compile (as needed) and load an ASDF system.
+ at item compile-system
+Compile (but not load) an ASDF system.
+ at item force-compile-system
+Recompile (but not load) an ASDF system.
+ at item force-load-system
+Recompile and load an ASDF system.
+ at end table
+
+ at node Banner
+ at section Banner
+The package @code{slime-banner} installs a window header line (
+ at inforef{Header Lines, , elisp}.) in the REPL buffer. It also runs an
+animation at startup.
+
+ at vindex slime-startup-animation
+ at vindex slime-header-line-p
+By setting the variable @code{slime-startup-animation} to nil you can
+disable the animation respectivly with the
+variable @code{slime-header-line-p} the header line.
+
+ at node Editing Commands
+ at section Editing Commands
+
+The package @code{slime-editing-commands} provides some commands to
+edit Lisp expressions.
+
+ at table @kbd
+ at kbditem{C-c M-q, slime-reindent-defun}
+Re-indents the current defun, or refills the current paragraph.
+If point is inside a comment block, the text around point will be
+treated as a paragraph and will be filled with @code{fill-paragraph}.
+Otherwise, it will be treated as Lisp code, and the current defun
+will be reindented. If the current defun has unbalanced parens,
+an attempt will be made to fix it before reindenting.
+
+ at cmditem{slime-close-all-parens-in-sexp}
+Balance parentheses of open s-expressions at point.
+Insert enough right parentheses to balance unmatched left parentheses.
+Delete extra left parentheses. Reformat trailing parentheses
+Lisp-stylishly.
+
+If REGION is true, operate on the region. Otherwise operate on
+the top-level sexp before point.
+
+ at cmditem{slime-insert-balanced-comments}
+Insert a set of balanced comments around the s-expression containing
+the point. If this command is invoked repeatedly (without any other
+command occurring between invocations), the comment progressively
+moves outward over enclosing expressions. If invoked with a positive
+prefix argument, the s-expression arg expressions out is enclosed in a
+set of balanced comments.
+
+ at kbditem{M-C-a, slime-beginning-of-defun}
+ at kbditem{M-C-e, slime-end-of-defun}
+ at end table
+
+ at node Fancy Inspector
+ at section Fancy Inspector
+
+ at cindex Methods
+
+An alternative to default inspector is provided by the package
+`slime-fancy-inspector'. This inspector knows a lot about CLOS
+objects and methods. It provides many ``actions'' that can be
+selected to invoke Lisp code on the inspected object. For example, to
+present a generic function the inspector shows the documentation in
+plain text and presents each method with both a hyperlink to inspect
+the method object and a ``remove method'' action that you can invoke
+interactively. The key-bindings are the same as for the basic
+inspector (@pxref{Inspector}).
+
+ at node Presentations
+ at section Presentations
+
+ at cindex Presentations
+
+A ``presentation''@footnote{Presentations are a feature originating
+from the Lisp machines. It was possible to define @code{present}
+methods specialized to various devices, e.g. to draw an object to
+bitmapped screen or to write some text to a character stream.} in
+ at SLIME{} is a region of text associated with a Lisp object.
+Right-clicking on the text brings up a menu with operations for the
+particular object. Some operations, like inspecting, are available
+for all objects, but the object may also have specialized operations.
+E.g. pathnames have a dired operation.
+
+The package @code{slime-presentations} installs presentations in the
+REPL, i.e. the results of evaluation commands become presentations.
+
+For some implementations you can also install
+ at code{slime-presentation-streams} which enables presentations on the
+Lisp @code{*standard-output*} stream. E.g. printing a list to such a
+stream will create presentions in the Emacs buffer.
+
+ at table @kbd
+ at cmditem{slime-copy-or-inspect-presentation-at-mouse}
+ at cmditem{slime-inspect-presentation-at-mouse}
+ at cmditem{slime-copy-presentation-at-mouse}
+ at cmditem{slime-copy-presentation-at-mouse-to-point}
+ at cmditem{slime-copy-presentation-at-mouse-to-kill-ring}
+ at cmditem{slime-describe-presentation-at-mouse}
+ at cmditem{slime-pretty-print-presentation-at-mouse}
+ at cmditem{slime-clear-presentations}
+ at end table
+
+ at node Typeout frames
+ at section Typeout frames
+
+ at cindex Typeout Frame
+
+A ``typeout frame'' is a special Emacs frame which is used instead of
+the echo area (minibuffer) to display messages from @SLIME{} commands.
+This is an optional feature. The advantage of a typeout frame over the
+echo area is that it can hold more text, it can be scrolled, and its
+contents don't disappear when you press a key. All potentially long
+messages are sent to the typeout frame, such as argument lists, macro
+expansions, and so on.
+
+ at table @kbd
+ at cmditem{slime-ensure-typeout-frame}
+Ensure that a typeout frame exists, creating one if necessary.
+ at end table
+
+If the typeout frame is closed then the echo area will be used again
+as usual.
+
+To have a typeout frame created automatically at startup you should
+load the @code{slime-typeout-frame} package. (@pxref{Loading Contribs}.)
+
+The variable @code{slime-typeout-frame-properties} specifies the
+height and possibly other properties of the frame. Its value is
+passed to @code{make-frame}. (@inforef{Creating Frames, ,elisp}.)
+
+ at node TRAMP
+ at section TRAMP
+
+ at cindex TRAMP
+
+The package @code{slime-tramp} provides some functions to set up
+filename translations for TRAMP. (@pxref{Setting up pathname
+translations})
+
+ at node Documentation Links
+ at section Documentation Links
+
+For certain error messages, SBCL includes references to the ANSI
+Standard or the SBCL User Manual. The @code{slime-references} package
+turns those references into clickable links. This makes finding the
+referenced section of the HyperSpec much easier.
+
+ at node Xref and Class Browser
+ at section Xref and Class Browser
+
+A rudimentary class browser is provied by
+the @code{slime-xref-browser} package.
+
+ at table @kbd
+ at cmditem{slime-browse-classes}
+This command asks for a class name and displays inheritance tree of
+for the class.
+
+ at cmditem{slime-browse-xrefs}
+This command prompts for a symbol and the kind of cross reference,
+e.g. callers. The cross reference tree rooted at the symbol is then
+then displayed.
+
+ at end table
+
+
+ at node Highlight Edits
+ at section Highlight Edits
+
+ at code{slime-highlight-edits} is a minor mode to highlight those
+regions in a Lisp source file which are modified. This is useful to
+quickly find those functions which need to be recompiled (whith
+ at kbd{C-c C-c})
+
+ at table @kbd
+ at cmditem{slime-highlight-edits-mode}
+Turns @code{slime-highlight-edits-mode} on or off.
+ at end table
+
+ at node inferior-slime-mode
+ at section @code{inferior-slime-mode}
+
+The @code{inferior-slime-mode} is a minor mode is intended to use with
+a comint buffer. It provides some of the SLIME commands, like symbol
+completion and documentation lookup. To install it, add something
+like this to user @file{.emacs}:
+
+ at example
+(slime-setup '(inferior-slime-mode))
+(add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode 1)))
+ at end example
+
+ at table @kbd
+ at cmditem{inferior-slime-mode}
+Turns inferior-slime-mode on or off.
+ at end table
+
+ at vindex inferior-slime-mode-map
+The variable @code{inferior-slime-mode-map} contains the extra
+keybindings.
+
+ at node Scratch Buffer
+ at section Scratch Buffer
+
+ at anchor{slime-scratch}
+The @SLIME{} scratch buffer, in contrib package @code{slime-scratch},
+imitates Emacs' usual @code{*scratch*} buffer. It's just like any
+other Lisp buffer, except for the command bound to @kbd{C-j}.
+
+ at table @kbd
+
+ at kbditem{C-j, slime-eval-print-last-expression}
+Evaluate the expression sexp before point and insert print value into
+the current buffer.
+
+ at cmditem{slime-scratch}
+Create a @file{*slime-scratch*} buffer. In this
+buffer you can enter Lisp expressions and evaluate them with
+ at kbd{C-j}, like in Emacs's @file{*scratch*} buffer.
+
+ at end table
+
+ at node slime-fancy
+ at section Meta package: @code{slime-fancy}
+
+ at code{slime-fancy} is a meta package which loads a combination of the
+most popular packages.
+
+ at c -----------------------
+ at node Credits
+ at chapter Credits
+
+ at emph{The soppy ending...}
+
+ at unnumberedsec Hackers of the good hack
+
+ at SLIME{} is an Extension of @acronym{SLIM} by Eric Marsden. At the
+time of writing, the authors and code-contributors of @SLIME{} are:
+
+ at include contributors.texi
+
+... not counting the bundled code from @file{hyperspec.el},
+ at cite{CLOCC}, and the @cite{CMU AI Repository}.
+
+Many people on the @code{slime-devel} mailing list have made non-code
+contributions to @SLIME{}. Life is hard though: you gotta send code to
+get your name in the manual. @code{:-)}
+
+ at unnumberedsec Thanks!
+
+We're indebted to the good people of @code{common-lisp.net} for their
+hosting and help, and for rescuing us from ``Sourceforge hell.''
+
+Implementors of the Lisps that we support have been a great help. We'd
+like to thank the @acronym{CMUCL} maintainers for their helpful
+answers, Craig Norvell and Kevin Layer at Franz providing Allegro CL
+licenses for @SLIME{} development, and Peter Graves for his help to
+get @SLIME{} running with @acronym{ABCL}.
+
+Most of all we're happy to be working with the Lisp implementors
+who've joined in the @SLIME{} development: Dan Barlow and Christophe
+Rhodes of @acronym{SBCL}, Gary Byers of OpenMCL, and Martin Simmons of
+LispWorks. Thanks also to Alain Picard and Memetrics for funding
+Martin's initial work on the LispWorks backend!
+
+ at ignore
+This index is currently ingored, because texinfo's built-in indexing
+produces nicer results. -- Helmut Eller
+
+ at c@node Index to Functions
+ at c@appendix Index to Functions
+
+These functions are all available (when relevant). To find the
+keybinding (if there is one) refer to the function description.
+
+ at c Note to editors: @fcnindex{...} lines commented out below are place holders
+ at c ----------------
+ at c They have yet to be documented
+ at c Please feel free to add descriptions in the text where appropriate, add the
+ at c appropriate anchors and uncomment them.
+ at c
+ at c [jkc]
+
+ at table @code
+ at fcnindex{common-lisp-hyperspec-format}
+ at fcnindex{sldb-abort}
+ at c @fcnindex{sldb-activate}
+ at c @fcnindex{sldb-add-face}
+ at c @fcnindex{sldb-backward-frame}
+ at c @fcnindex{sldb-beginning-of-backtrace}
+ at c @fcnindex{sldb-break}
+ at c @fcnindex{sldb-break-on-return}
+ at fcnindex{sldb-break-with-default-debugger}
+ at c @fcnindex{sldb-buffers}
+ at c @fcnindex{sldb-catch-tags}
+ at fcnindex{sldb-continue}
+ at c @fcnindex{sldb-debugged-continuations}
+ at c @fcnindex{sldb-default-action}
+ at c @fcnindex{sldb-default-action/mouse}
+ at c @fcnindex{sldb-delete-overlays}
+ at c @fcnindex{sldb-details-down}
+ at c @fcnindex{sldb-details-up}
+ at fcnindex{sldb-disassemble}
+ at c @fcnindex{sldb-dispatch-extras}
+ at c @fcnindex{sldb-down}
+ at c @fcnindex{sldb-end-of-backtrace}
+ at fcnindex{sldb-eval-in-frame}
+ at c @fcnindex{sldb-exit}
+ at c @fcnindex{sldb-fetch-all-frames}
+ at c @fcnindex{sldb-fetch-more-frames}
+ at c @fcnindex{sldb-find-buffer}
+ at c @fcnindex{sldb-format-reference-node}
+ at c @fcnindex{sldb-format-reference-source}
+ at c @fcnindex{sldb-forward-frame}
+ at c @fcnindex{sldb-frame-details-visible-p}
+ at c @fcnindex{sldb-frame-locals}
+ at c @fcnindex{sldb-frame-number-at-point}
+ at c @fcnindex{sldb-frame-region}
+ at c @fcnindex{sldb-get-buffer}
+ at c @fcnindex{sldb-get-default-buffer}
+ at c @fcnindex{sldb-goto-last-frame}
+ at c @fcnindex{sldb-help-summary}
+ at c @fcnindex{sldb-hide-frame-details}
+ at c @fcnindex{sldb-highlight-sexp}
+ at c @fcnindex{sldb-insert-condition}
+ at c @fcnindex{sldb-insert-frame}
+ at c @fcnindex{sldb-insert-frames}
+ at c @fcnindex{sldb-insert-locals}
+ at c @fcnindex{sldb-insert-references}
+ at c @fcnindex{sldb-insert-restarts}
+ at c @fcnindex{sldb-inspect-condition}
+ at fcnindex{sldb-inspect-in-frame}
+ at c @fcnindex{sldb-inspect-var}
+ at c @fcnindex{sldb-invoke-restart}
+ at c @fcnindex{sldb-level}
+ at c @fcnindex{sldb-list-catch-tags}
+ at c @fcnindex{sldb-list-locals}
+ at c @fcnindex{sldb-lookup-reference}
+ at c @fcnindex{sldb-maybe-recenter-region}
+ at c @fcnindex{sldb-mode-hook}
+ at c @fcnindex{sldb-next}
+ at c @fcnindex{sldb-out}
+ at fcnindex{sldb-pprint-eval-in-frame}
+ at c @fcnindex{sldb-previous-frame-number}
+ at c @fcnindex{sldb-print-condition}
+ at c @fcnindex{sldb-prune-initial-frames}
+ at fcnindex{sldb-quit}
+ at c @fcnindex{sldb-reference-properties}
+ at c @fcnindex{sldb-restart-at-point}
+ at fcnindex{sldb-restart-frame}
+ at fcnindex{sldb-return-from-frame}
+ at c @fcnindex{sldb-setup}
+ at c @fcnindex{sldb-show-frame-details}
+ at c @fcnindex{sldb-show-frame-source}
+ at fcnindex{sldb-show-source}
+ at fcnindex{sldb-step}
+ at c @fcnindex{sldb-sugar-move}
+ at fcnindex{sldb-toggle-details}
+ at c @fcnindex{sldb-up}
+ at c @fcnindex{sldb-var-number-at-point}
+ at c @fcnindex{sldb-xemacs-emulate-point-entered-hook}
+ at c @fcnindex{sldb-xemacs-post-command-hook}
+
+
+ at c @fcnindex{inferior-slime-closing-return}
+ at c @fcnindex{inferior-slime-indent-line}
+ at c @fcnindex{inferior-slime-mode}
+ at c @fcnindex{inferior-slime-return}
+ at fcnindex{slime-abort-connection}
+ at fcnindex{slime-apropos}
+ at fcnindex{slime-apropos-all}
+ at fcnindex{slime-apropos-package}
+ at c @fcnindex{slime-arglist}
+ at fcnindex{slime-autodoc-mode}
+ at c @fcnindex{slime-autodoc-start-timer}
+ at c @fcnindex{slime-background-activities-enabled-p}
+ at c @fcnindex{slime-background-message}
+ at c @fcnindex{slime-browse-classes}
+ at c @fcnindex{slime-browse-xrefs}
+ at fcnindex{slime-call-defun}
+ at fcnindex{slime-calls-who}
+ at c @fcnindex{slime-check-coding-system}
+ at fcnindex{slime-close-all-sexp}
+ at fcnindex{slime-close-parens-at-point}
+ at fcnindex{slime-compile-and-load-file}
+ at fcnindex{slime-compile-defun}
+ at fcnindex{slime-compile-file}
+ at fcnindex{slime-compile-region}
+ at fcnindex{slime-compiler-macroexpand}
+ at fcnindex{slime-compiler-macroexpand-1}
+ at c @fcnindex{slime-compiler-notes-default-action-or-show-details}
+ at c @fcnindex{slime-compiler-notes-default-action-or-show-details/mouse}
+ at c @fcnindex{slime-compiler-notes-quit}
+ at c @fcnindex{slime-compiler-notes-show-details}
+ at c @fcnindex{slime-complete-form}
+ at fcnindex{slime-complete-symbol}
+ at fcnindex{slime-connect}
+ at fcnindex{slime-connection-list-make-default}
+ at c @fcnindex{slime-connection-list-mode}
+ at c @fcnindex{slime-copy-presentation-at-point}
+ at fcnindex{slime-describe-function}
+ at fcnindex{slime-describe-symbol}
+ at fcnindex{slime-disassemble-symbol}
+ at fcnindex{slime-disconnect}
+ at c @fcnindex{slime-documentation}
+ at fcnindex{slime-edit-definition}
+ at fcnindex{slime-edit-definition-other-frame}
+ at fcnindex{slime-edit-definition-other-window}
+ at fcnindex{slime-edit-definition-with-etags}
+ at fcnindex{slime-edit-value}
+ at c @fcnindex{slime-edit-value-commit}
+ at c @fcnindex{slime-edit-value-mode}
+ at fcnindex{slime-ensure-typeout-frame}
+ at c @fcnindex{slime-eval-buffer}
+ at fcnindex{slime-eval-defun}
+ at fcnindex{slime-eval-last-expression}
+ at fcnindex{slime-eval-last-expression-display-output}
+ at c @fcnindex{slime-eval-print-last-expression}
+ at fcnindex{slime-eval-region}
+ at fcnindex{slime-fuzzy-abort}
+ at fcnindex{slime-fuzzy-complete-symbol}
+ at fcnindex{slime-fuzzy-completions-mode}
+ at c @fcnindex{slime-fuzzy-next}
+ at c @fcnindex{slime-fuzzy-prev}
+ at c @fcnindex{slime-fuzzy-select}
+ at c @fcnindex{slime-fuzzy-select/mouse}
+ at fcnindex{slime-goto-connection}
+ at fcnindex{slime-goto-xref}
+ at c @fcnindex{slime-handle-repl-shortcut}
+ at c @fcnindex{slime-highlight-notes}
+ at fcnindex{slime-hyperspec-lookup}
+ at c @fcnindex{slime-indent-and-complete-symbol}
+ at c @fcnindex{slime-init-keymaps}
+ at c @fcnindex{slime-insert-arglist}
+ at c @fcnindex{slime-insert-balanced-comments}
+ at fcnindex{slime-inspect}
+ at fcnindex{slime-inspector-copy-down}
+ at fcnindex{slime-inspector-describe}
+ at fcnindex{slime-inspector-next}
+ at c @fcnindex{slime-inspector-next-inspectable-object}
+ at fcnindex{slime-inspector-quit}
+ at c @fcnindex{slime-inspector-reinspect}
+ at fcnindex{slime-interactive-eval}
+ at fcnindex{slime-interrupt}
+ at fcnindex{slime-list-callees}
+ at fcnindex{slime-list-callers}
+ at c @fcnindex{slime-list-compiler-notes}
+ at fcnindex{slime-list-connections}
+ at c @fcnindex{slime-list-repl-shortcuts}
+ at fcnindex{slime-list-threads}
+ at fcnindex{slime-load-file}
+ at c @fcnindex{slime-load-system}
+ at fcnindex{slime-macroexpand-1}
+ at fcnindex{slime-macroexpand-1-inplace}
+ at fcnindex{slime-macroexpand-all}
+ at c @fcnindex{slime-make-default-connection}
+ at c @fcnindex{slime-make-typeout-frame}
+ at fcnindex{slime-mode}
+ at c @fcnindex{slime-next-line/not-add-newlines}
+ at c @fcnindex{slime-next-location}
+ at fcnindex{slime-next-note}
+ at fcnindex{slime-nop}
+ at c @fcnindex{slime-ping}
+ at fcnindex{slime-pop-find-definition-stack}
+ at fcnindex{slime-pprint-eval-last-expression}
+ at c @fcnindex{slime-presentation-menu}
+ at c @fcnindex{slime-pretty-lambdas}
+ at fcnindex{slime-previous-note}
+ at fcnindex{slime-profile-package}
+ at fcnindex{slime-profile-report}
+ at fcnindex{slime-profile-reset}
+ at fcnindex{slime-profiled-functions}
+ at fcnindex{slime-quit}
+ at c @fcnindex{slime-quit-connection-at-point}
+ at c @fcnindex{slime-quit-lisp}
+ at c @fcnindex{slime-re-evaluate-defvar}
+ at c @fcnindex{slime-recompile-bytecode}
+ at c @fcnindex{slime-register-lisp-implementation}
+ at fcnindex{slime-reindent-defun}
+ at c @fcnindex{slime-remove-balanced-comments}
+ at fcnindex{slime-remove-notes}
+ at c @fcnindex{slime-repl}
+ at fcnindex{slime-repl-beginning-of-defun}
+ at fcnindex{slime-repl-bol}
+ at fcnindex{slime-repl-clear-buffer}
+ at fcnindex{slime-repl-clear-output}
+ at fcnindex{slime-repl-closing-return}
+ at c @fcnindex{slime-repl-compile-and-load}
+ at c @fcnindex{slime-repl-compile-system}
+ at c @fcnindex{slime-repl-compile/force-system}
+ at c @fcnindex{slime-repl-defparameter}
+ at fcnindex{slime-repl-end-of-defun}
+ at c @fcnindex{slime-repl-eol}
+ at c @fcnindex{slime-repl-load-system}
+ at c @fcnindex{slime-repl-load/force-system}
+ at c @fcnindex{slime-repl-mode}
+ at fcnindex{slime-repl-newline-and-indent}
+ at fcnindex{slime-repl-next-input}
+ at fcnindex{slime-repl-next-matching-input}
+ at fcnindex{slime-repl-next-prompt}
+ at c @fcnindex{slime-repl-pop-directory}
+ at c @fcnindex{slime-repl-pop-packages}
+ at fcnindex{slime-repl-previous-input}
+ at fcnindex{slime-repl-previous-matching-input}
+ at fcnindex{slime-repl-previous-prompt}
+ at c @fcnindex{slime-repl-push-directory}
+ at c @fcnindex{slime-repl-push-package}
+ at c @fcnindex{slime-repl-read-break}
+ at c @fcnindex{slime-repl-read-mode}
+ at fcnindex{slime-repl-return}
+ at fcnindex{slime-repl-set-package}
+ at c @fcnindex{slime-repl-shortcut-help}
+ at c @fcnindex{slime-reset}
+ at c @fcnindex{slime-restart-connection-at-point}
+ at c @fcnindex{slime-restart-inferior-lisp}
+ at c @fcnindex{slime-restart-inferior-lisp-aux}
+ at fcnindex{slime-scratch}
+ at c @fcnindex{slime-select-lisp-implementation}
+ at fcnindex{slime-selector}
+ at c @fcnindex{slime-send-sigint}
+ at c @fcnindex{slime-set-default-directory}
+ at c @fcnindex{slime-set-package}
+ at c @fcnindex{slime-show-xref}
+ at fcnindex{slime-space}
+ at c @fcnindex{slime-start-and-load}
+ at fcnindex{slime-switch-to-output-buffer}
+ at fcnindex{slime-sync-package-and-default-directory}
+ at c @fcnindex{slime-temp-buffer-mode}
+ at fcnindex{slime-temp-buffer-quit}
+ at c @fcnindex{slime-thread-attach}
+ at c @fcnindex{slime-thread-debug}
+ at c @fcnindex{slime-thread-control-mode}
+ at c @fcnindex{slime-thread-kill}
+ at c @fcnindex{slime-thread-quit}
+ at fcnindex{slime-toggle-profile-fdefinition}
+ at fcnindex{slime-toggle-trace-fdefinition}
+ at fcnindex{slime-undefine-function}
+ at fcnindex{slime-unprofile-all}
+ at fcnindex{slime-untrace-all}
+ at fcnindex{slime-update-connection-list}
+ at c @fcnindex{slime-update-indentation} ???
+ at fcnindex{slime-who-binds}
+ at fcnindex{slime-who-calls}
+ at fcnindex{slime-who-macroexpands}
+ at fcnindex{slime-who-references}
+ at fcnindex{slime-who-sets}
+ at fcnindex{slime-who-specializes}
+ at c @fcnindex{slime-xref-mode}
+ at c @fcnindex{slime-xref-quit}
+ at end table
+
+ at end ignore
+
+ at node Key Index
+ at unnumbered Key (Character) Index
+ at printindex ky
+
+ at node Command Index
+ at unnumbered Command and Function Index
+ at printindex fn
+
+ at node Variable Index
+ at unnumbered Variable and Concept Index
+ at printindex vr
+
+ at bye
+Local Variables:
+paragraph-start: "@[a-zA-Z]+\\({[^}]+}\\)?[ \n]\\|[ ]*$"
+paragraph-separate: "@[a-zA-Z]+\\({[^}]+}\\)?[ \n]\\|[ ]*$"
+End:
Added: branches/bos/thirdparty/emacs/slime/doc/texinfo-tabulate.awk
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/doc/texinfo-tabulate.awk Fri Jan 18 06:05:59 2008
@@ -0,0 +1,21 @@
+#!/usr/bin/env awk -f
+#
+# Format input lines into a multi-column texinfo table.
+# Note: does not do texinfo-escaping of the input.
+
+# This code has been placed in the Public Domain. All warranties
+# are disclaimed.
+
+BEGIN {
+ columns = 3;
+ printf("@multitable @columnfractions");
+ for (i = 0; i < columns; i++)
+ printf(" %f", 1.0/columns);
+ print
+}
+
+{ if (NR % columns == 1) printf("\n at item %s", $0);
+ else printf(" @tab %s", $0); }
+
+END { printf("\n at end multitable\n"); }
+
Added: branches/bos/thirdparty/emacs/slime/hyperspec.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/hyperspec.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,1671 @@
+;;; hyperspec.el --- Browse documentation from the Common Lisp HyperSpec
+
+;; Copyright 1997 Naggum Software
+
+;; Author: Erik Naggum <erik at naggum.no>
+;; Keywords: lisp
+
+;; This file is not part of GNU Emacs, but distributed under the same
+;; conditions as GNU Emacs, and is useless without GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; Kent Pitman and Xanalys Inc. have made the text of American National
+;; Standard for Information Technology -- Programming Language -- Common
+;; Lisp, ANSI X3.226-1994 available on the WWW, in the form of the Common
+;; Lisp HyperSpec. This package makes it convenient to peruse this
+;; documentation from within Emacs.
+
+;;; Code:
+
+(require 'cl)
+(require 'browse-url) ;you need the Emacs 20 version
+(require 'thingatpt)
+
+(defvar common-lisp-hyperspec-root
+ "http://www.lispworks.com/reference/HyperSpec/"
+ "The root of the Common Lisp HyperSpec URL.
+If you copy the HyperSpec to your local system, set this variable to
+something like \"file:/usr/local/doc/HyperSpec/\".")
+
+;;; Added variable for CLHS symbol table. See details below.
+;;;
+;;; 20011201 Edi Weitz
+
+(defvar common-lisp-hyperspec-symbol-table nil
+ "The HyperSpec symbol table file.
+If you copy the HyperSpec to your local system, set this variable to
+the location of the symbol table which is usually \"Map_Sym.txt\"
+or \"Symbol-Table.text\".")
+
+(defvar common-lisp-hyperspec-history nil
+ "History of symbols looked up in the Common Lisp HyperSpec.")
+
+;;if only we had had packages or hash tables..., but let's fake it.
+
+(defvar common-lisp-hyperspec-symbols (make-vector 67 0))
+
+(defun common-lisp-hyperspec-strip-cl-package (name)
+ (if (string-match "^\\([^:]*\\)::?\\([^:]*\\)$" name)
+ (let ((package-name (match-string 1 name))
+ (symbol-name (match-string 2 name)))
+ (if (member (downcase package-name)
+ '("cl" "common-lisp"))
+ symbol-name
+ name))
+ name))
+
+(defun common-lisp-hyperspec (symbol-name)
+ "View the documentation on SYMBOL-NAME from the Common Lisp HyperSpec.
+If SYMBOL-NAME has more than one definition, all of them are displayed with
+your favorite browser in sequence. The browser should have a \"back\"
+function to view the separate definitions.
+
+The Common Lisp HyperSpec is the full ANSI Standard Common Lisp, provided
+by Kent Pitman and Xanalys Inc. By default, the Xanalys Web site is
+visited to retrieve the information. Xanalys Inc. allows you to transfer
+the entire Common Lisp HyperSpec to your own site under certain conditions.
+Visit http://www.lispworks.com/reference/HyperSpec/ for more information.
+If you copy the HyperSpec to another location, customize the variable
+`common-lisp-hyperspec-root' to point to that location."
+ (interactive (list (let* ((symbol-at-point (thing-at-point 'symbol))
+ (stripped-symbol
+ (and symbol-at-point
+ (substring-no-properties
+ (downcase
+ (common-lisp-hyperspec-strip-cl-package
+ symbol-at-point))))))
+ (if (and stripped-symbol
+ (intern-soft stripped-symbol
+ common-lisp-hyperspec-symbols))
+ stripped-symbol
+ (completing-read
+ "Look up symbol in Common Lisp HyperSpec: "
+ common-lisp-hyperspec-symbols #'boundp
+ t stripped-symbol
+ 'common-lisp-hyperspec-history)))))
+ (maplist (lambda (entry)
+ (browse-url (concat common-lisp-hyperspec-root "Body/" (car entry)))
+ (if (cdr entry)
+ (sleep-for 1.5)))
+ (let ((symbol (intern-soft
+ (common-lisp-hyperspec-strip-cl-package
+ (downcase symbol-name))
+ common-lisp-hyperspec-symbols)))
+ (if (and symbol (boundp symbol))
+ (symbol-value symbol)
+ (error "The symbol `%s' is not defined in Common Lisp"
+ symbol-name)))))
+
+;;; Added the following just to provide a common entry point according
+;;; to the various 'hyperspec' implementations.
+;;;
+;;; 19990820 Marco Antoniotti
+
+(eval-when (load eval)
+ (defalias 'hyperspec-lookup 'common-lisp-hyperspec))
+
+
+;;; Added dynamic lookup of symbol in CLHS symbol table
+;;;
+;;; 20011202 Edi Weitz
+
+;;; Replaced symbol table for v 4.0 with the one for v 6.0
+;;; (which is now online at Xanalys' site)
+;;;
+;;; 20020213 Edi Weitz
+
+(if common-lisp-hyperspec-symbol-table
+ (let ((index-buffer (find-file-noselect common-lisp-hyperspec-symbol-table)))
+ (labels ((get-one-line ()
+ (prog1
+ (delete* ?\n (thing-at-point 'line))
+ (forward-line))))
+ (save-excursion
+ (set-buffer index-buffer)
+ (goto-char (point-min))
+ (while (< (point) (point-max))
+ (let* ((symbol (intern (downcase (get-one-line))
+ common-lisp-hyperspec-symbols))
+ (relative-url (get-one-line)))
+ (set symbol (list (subseq relative-url
+ (1+ (position ?\/ relative-url :from-end t))))))))))
+ (mapcar (lambda (entry)
+ (let ((symbol (intern (car entry) common-lisp-hyperspec-symbols)))
+ (if (boundp symbol)
+ (push (cadr entry) (symbol-value symbol))
+ (set symbol (cdr entry)))))
+ '(("&allow-other-keys" "03_da.htm")
+ ("&aux" "03_da.htm")
+ ("&body" "03_dd.htm")
+ ("&environment" "03_dd.htm")
+ ("&key" "03_da.htm")
+ ("&optional" "03_da.htm")
+ ("&rest" "03_da.htm")
+ ("&whole" "03_dd.htm")
+ ("*" "a_st.htm")
+ ("**" "v__stst_.htm")
+ ("***" "v__stst_.htm")
+ ("*break-on-signals*" "v_break_.htm")
+ ("*compile-file-pathname*" "v_cmp_fi.htm")
+ ("*compile-file-truename*" "v_cmp_fi.htm")
+ ("*compile-print*" "v_cmp_pr.htm")
+ ("*compile-verbose*" "v_cmp_pr.htm")
+ ("*debug-io*" "v_debug_.htm")
+ ("*debugger-hook*" "v_debugg.htm")
+ ("*default-pathname-defaults*" "v_defaul.htm")
+ ("*error-output*" "v_debug_.htm")
+ ("*features*" "v_featur.htm")
+ ("*gensym-counter*" "v_gensym.htm")
+ ("*load-pathname*" "v_ld_pns.htm")
+ ("*load-print*" "v_ld_prs.htm")
+ ("*load-truename*" "v_ld_pns.htm")
+ ("*load-verbose*" "v_ld_prs.htm")
+ ("*macroexpand-hook*" "v_mexp_h.htm")
+ ("*modules*" "v_module.htm")
+ ("*package*" "v_pkg.htm")
+ ("*print-array*" "v_pr_ar.htm")
+ ("*print-base*" "v_pr_bas.htm")
+ ("*print-case*" "v_pr_cas.htm")
+ ("*print-circle*" "v_pr_cir.htm")
+ ("*print-escape*" "v_pr_esc.htm")
+ ("*print-gensym*" "v_pr_gen.htm")
+ ("*print-length*" "v_pr_lev.htm")
+ ("*print-level*" "v_pr_lev.htm")
+ ("*print-lines*" "v_pr_lin.htm")
+ ("*print-miser-width*" "v_pr_mis.htm")
+ ("*print-pprint-dispatch*" "v_pr_ppr.htm")
+ ("*print-pretty*" "v_pr_pre.htm")
+ ("*print-radix*" "v_pr_bas.htm")
+ ("*print-readably*" "v_pr_rda.htm")
+ ("*print-right-margin*" "v_pr_rig.htm")
+ ("*query-io*" "v_debug_.htm")
+ ("*random-state*" "v_rnd_st.htm")
+ ("*read-base*" "v_rd_bas.htm")
+ ("*read-default-float-format*" "v_rd_def.htm")
+ ("*read-eval*" "v_rd_eva.htm")
+ ("*read-suppress*" "v_rd_sup.htm")
+ ("*readtable*" "v_rdtabl.htm")
+ ("*standard-input*" "v_debug_.htm")
+ ("*standard-output*" "v_debug_.htm")
+ ("*terminal-io*" "v_termin.htm")
+ ("*trace-output*" "v_debug_.htm")
+ ("+" "a_pl.htm")
+ ("++" "v_pl_plp.htm")
+ ("+++" "v_pl_plp.htm")
+ ("-" "a__.htm")
+ ("/" "a_sl.htm")
+ ("//" "v_sl_sls.htm")
+ ("///" "v_sl_sls.htm")
+ ("/=" "f_eq_sle.htm")
+ ("1+" "f_1pl_1_.htm")
+ ("1-" "f_1pl_1_.htm")
+ ("<" "f_eq_sle.htm")
+ ("<=" "f_eq_sle.htm")
+ ("=" "f_eq_sle.htm")
+ (">" "f_eq_sle.htm")
+ (">=" "f_eq_sle.htm")
+ ("abort" "a_abort.htm")
+ ("abs" "f_abs.htm")
+ ("acons" "f_acons.htm")
+ ("acos" "f_asin_.htm")
+ ("acosh" "f_sinh_.htm")
+ ("add-method" "f_add_me.htm")
+ ("adjoin" "f_adjoin.htm")
+ ("adjust-array" "f_adjust.htm")
+ ("adjustable-array-p" "f_adju_1.htm")
+ ("allocate-instance" "f_alloca.htm")
+ ("alpha-char-p" "f_alpha_.htm")
+ ("alphanumericp" "f_alphan.htm")
+ ("and" "a_and.htm")
+ ("append" "f_append.htm")
+ ("apply" "f_apply.htm")
+ ("apropos" "f_apropo.htm")
+ ("apropos-list" "f_apropo.htm")
+ ("aref" "f_aref.htm")
+ ("arithmetic-error" "e_arithm.htm")
+ ("arithmetic-error-operands" "f_arithm.htm")
+ ("arithmetic-error-operation" "f_arithm.htm")
+ ("array" "t_array.htm")
+ ("array-dimension" "f_ar_dim.htm")
+ ("array-dimension-limit" "v_ar_dim.htm")
+ ("array-dimensions" "f_ar_d_1.htm")
+ ("array-displacement" "f_ar_dis.htm")
+ ("array-element-type" "f_ar_ele.htm")
+ ("array-has-fill-pointer-p" "f_ar_has.htm")
+ ("array-in-bounds-p" "f_ar_in_.htm")
+ ("array-rank" "f_ar_ran.htm")
+ ("array-rank-limit" "v_ar_ran.htm")
+ ("array-row-major-index" "f_ar_row.htm")
+ ("array-total-size" "f_ar_tot.htm")
+ ("array-total-size-limit" "v_ar_tot.htm")
+ ("arrayp" "f_arrayp.htm")
+ ("ash" "f_ash.htm")
+ ("asin" "f_asin_.htm")
+ ("asinh" "f_sinh_.htm")
+ ("assert" "m_assert.htm")
+ ("assoc" "f_assocc.htm")
+ ("assoc-if" "f_assocc.htm")
+ ("assoc-if-not" "f_assocc.htm")
+ ("atan" "f_asin_.htm")
+ ("atanh" "f_sinh_.htm")
+ ("atom" "a_atom.htm")
+ ("base-char" "t_base_c.htm")
+ ("base-string" "t_base_s.htm")
+ ("bignum" "t_bignum.htm")
+ ("bit" "a_bit.htm")
+ ("bit-and" "f_bt_and.htm")
+ ("bit-andc1" "f_bt_and.htm")
+ ("bit-andc2" "f_bt_and.htm")
+ ("bit-eqv" "f_bt_and.htm")
+ ("bit-ior" "f_bt_and.htm")
+ ("bit-nand" "f_bt_and.htm")
+ ("bit-nor" "f_bt_and.htm")
+ ("bit-not" "f_bt_and.htm")
+ ("bit-orc1" "f_bt_and.htm")
+ ("bit-orc2" "f_bt_and.htm")
+ ("bit-vector" "t_bt_vec.htm")
+ ("bit-vector-p" "f_bt_vec.htm")
+ ("bit-xor" "f_bt_and.htm")
+ ("block" "s_block.htm")
+ ("boole" "f_boole.htm")
+ ("boole-1" "v_b_1_b.htm")
+ ("boole-2" "v_b_1_b.htm")
+ ("boole-and" "v_b_1_b.htm")
+ ("boole-andc1" "v_b_1_b.htm")
+ ("boole-andc2" "v_b_1_b.htm")
+ ("boole-c1" "v_b_1_b.htm")
+ ("boole-c2" "v_b_1_b.htm")
+ ("boole-clr" "v_b_1_b.htm")
+ ("boole-eqv" "v_b_1_b.htm")
+ ("boole-ior" "v_b_1_b.htm")
+ ("boole-nand" "v_b_1_b.htm")
+ ("boole-nor" "v_b_1_b.htm")
+ ("boole-orc1" "v_b_1_b.htm")
+ ("boole-orc2" "v_b_1_b.htm")
+ ("boole-set" "v_b_1_b.htm")
+ ("boole-xor" "v_b_1_b.htm")
+ ("boolean" "t_ban.htm")
+ ("both-case-p" "f_upper_.htm")
+ ("boundp" "f_boundp.htm")
+ ("break" "f_break.htm")
+ ("broadcast-stream" "t_broadc.htm")
+ ("broadcast-stream-streams" "f_broadc.htm")
+ ("built-in-class" "t_built_.htm")
+ ("butlast" "f_butlas.htm")
+ ("byte" "f_by_by.htm")
+ ("byte-position" "f_by_by.htm")
+ ("byte-size" "f_by_by.htm")
+ ("caaaar" "f_car_c.htm")
+ ("caaadr" "f_car_c.htm")
+ ("caaar" "f_car_c.htm")
+ ("caadar" "f_car_c.htm")
+ ("caaddr" "f_car_c.htm")
+ ("caadr" "f_car_c.htm")
+ ("caar" "f_car_c.htm")
+ ("cadaar" "f_car_c.htm")
+ ("cadadr" "f_car_c.htm")
+ ("cadar" "f_car_c.htm")
+ ("caddar" "f_car_c.htm")
+ ("cadddr" "f_car_c.htm")
+ ("caddr" "f_car_c.htm")
+ ("cadr" "f_car_c.htm")
+ ("call-arguments-limit" "v_call_a.htm")
+ ("call-method" "m_call_m.htm")
+ ("call-next-method" "f_call_n.htm")
+ ("car" "f_car_c.htm")
+ ("case" "m_case_.htm")
+ ("catch" "s_catch.htm")
+ ("ccase" "m_case_.htm")
+ ("cdaaar" "f_car_c.htm")
+ ("cdaadr" "f_car_c.htm")
+ ("cdaar" "f_car_c.htm")
+ ("cdadar" "f_car_c.htm")
+ ("cdaddr" "f_car_c.htm")
+ ("cdadr" "f_car_c.htm")
+ ("cdar" "f_car_c.htm")
+ ("cddaar" "f_car_c.htm")
+ ("cddadr" "f_car_c.htm")
+ ("cddar" "f_car_c.htm")
+ ("cdddar" "f_car_c.htm")
+ ("cddddr" "f_car_c.htm")
+ ("cdddr" "f_car_c.htm")
+ ("cddr" "f_car_c.htm")
+ ("cdr" "f_car_c.htm")
+ ("ceiling" "f_floorc.htm")
+ ("cell-error" "e_cell_e.htm")
+ ("cell-error-name" "f_cell_e.htm")
+ ("cerror" "f_cerror.htm")
+ ("change-class" "f_chg_cl.htm")
+ ("char" "f_char_.htm")
+ ("char-code" "f_char_c.htm")
+ ("char-code-limit" "v_char_c.htm")
+ ("char-downcase" "f_char_u.htm")
+ ("char-equal" "f_chareq.htm")
+ ("char-greaterp" "f_chareq.htm")
+ ("char-int" "f_char_i.htm")
+ ("char-lessp" "f_chareq.htm")
+ ("char-name" "f_char_n.htm")
+ ("char-not-equal" "f_chareq.htm")
+ ("char-not-greaterp" "f_chareq.htm")
+ ("char-not-lessp" "f_chareq.htm")
+ ("char-upcase" "f_char_u.htm")
+ ("char/=" "f_chareq.htm")
+ ("char<" "f_chareq.htm")
+ ("char<=" "f_chareq.htm")
+ ("char=" "f_chareq.htm")
+ ("char>" "f_chareq.htm")
+ ("char>=" "f_chareq.htm")
+ ("character" "a_ch.htm")
+ ("characterp" "f_chp.htm")
+ ("check-type" "m_check_.htm")
+ ("cis" "f_cis.htm")
+ ("class" "t_class.htm")
+ ("class-name" "f_class_.htm")
+ ("class-of" "f_clas_1.htm")
+ ("clear-input" "f_clear_.htm")
+ ("clear-output" "f_finish.htm")
+ ("close" "f_close.htm")
+ ("clrhash" "f_clrhas.htm")
+ ("code-char" "f_code_c.htm")
+ ("coerce" "f_coerce.htm")
+ ("compilation-speed" "d_optimi.htm")
+ ("compile" "f_cmp.htm")
+ ("compile-file" "f_cmp_fi.htm")
+ ("compile-file-pathname" "f_cmp__1.htm")
+ ("compiled-function" "t_cmpd_f.htm")
+ ("compiled-function-p" "f_cmpd_f.htm")
+ ("compiler-macro" "f_docume.htm")
+ ("compiler-macro-function" "f_cmp_ma.htm")
+ ("complement" "f_comple.htm")
+ ("complex" "a_comple.htm")
+ ("complexp" "f_comp_3.htm")
+ ("compute-applicable-methods" "f_comput.htm")
+ ("compute-restarts" "f_comp_1.htm")
+ ("concatenate" "f_concat.htm")
+ ("concatenated-stream" "t_concat.htm")
+ ("concatenated-stream-streams" "f_conc_1.htm")
+ ("cond" "m_cond.htm")
+ ("condition" "e_cnd.htm")
+ ("conjugate" "f_conjug.htm")
+ ("cons" "a_cons.htm")
+ ("consp" "f_consp.htm")
+ ("constantly" "f_cons_1.htm")
+ ("constantp" "f_consta.htm")
+ ("continue" "a_contin.htm")
+ ("control-error" "e_contro.htm")
+ ("copy-alist" "f_cp_ali.htm")
+ ("copy-list" "f_cp_lis.htm")
+ ("copy-pprint-dispatch" "f_cp_ppr.htm")
+ ("copy-readtable" "f_cp_rdt.htm")
+ ("copy-seq" "f_cp_seq.htm")
+ ("copy-structure" "f_cp_stu.htm")
+ ("copy-symbol" "f_cp_sym.htm")
+ ("copy-tree" "f_cp_tre.htm")
+ ("cos" "f_sin_c.htm")
+ ("cosh" "f_sinh_.htm")
+ ("count" "f_countc.htm")
+ ("count-if" "f_countc.htm")
+ ("count-if-not" "f_countc.htm")
+ ("ctypecase" "m_tpcase.htm")
+ ("debug" "d_optimi.htm")
+ ("decf" "m_incf_.htm")
+ ("declaim" "m_declai.htm")
+ ("declaration" "d_declar.htm")
+ ("declare" "s_declar.htm")
+ ("decode-float" "f_dec_fl.htm")
+ ("decode-universal-time" "f_dec_un.htm")
+ ("defclass" "m_defcla.htm")
+ ("defconstant" "m_defcon.htm")
+ ("defgeneric" "m_defgen.htm")
+ ("define-compiler-macro" "m_define.htm")
+ ("define-condition" "m_defi_5.htm")
+ ("define-method-combination" "m_defi_4.htm")
+ ("define-modify-macro" "m_defi_2.htm")
+ ("define-setf-expander" "m_defi_3.htm")
+ ("define-symbol-macro" "m_defi_1.htm")
+ ("defmacro" "m_defmac.htm")
+ ("defmethod" "m_defmet.htm")
+ ("defpackage" "m_defpkg.htm")
+ ("defparameter" "m_defpar.htm")
+ ("defsetf" "m_defset.htm")
+ ("defstruct" "m_defstr.htm")
+ ("deftype" "m_deftp.htm")
+ ("defun" "m_defun.htm")
+ ("defvar" "m_defpar.htm")
+ ("delete" "f_rm_rm.htm")
+ ("delete-duplicates" "f_rm_dup.htm")
+ ("delete-file" "f_del_fi.htm")
+ ("delete-if" "f_rm_rm.htm")
+ ("delete-if-not" "f_rm_rm.htm")
+ ("delete-package" "f_del_pk.htm")
+ ("denominator" "f_numera.htm")
+ ("deposit-field" "f_deposi.htm")
+ ("describe" "f_descri.htm")
+ ("describe-object" "f_desc_1.htm")
+ ("destructuring-bind" "m_destru.htm")
+ ("digit-char" "f_digit_.htm")
+ ("digit-char-p" "f_digi_1.htm")
+ ("directory" "f_dir.htm")
+ ("directory-namestring" "f_namest.htm")
+ ("disassemble" "f_disass.htm")
+ ("division-by-zero" "e_divisi.htm")
+ ("do" "m_do_do.htm")
+ ("do*" "m_do_do.htm")
+ ("do-all-symbols" "m_do_sym.htm")
+ ("do-external-symbols" "m_do_sym.htm")
+ ("do-symbols" "m_do_sym.htm")
+ ("documentation" "f_docume.htm")
+ ("dolist" "m_dolist.htm")
+ ("dotimes" "m_dotime.htm")
+ ("double-float" "t_short_.htm")
+ ("double-float-epsilon" "v_short_.htm")
+ ("double-float-negative-epsilon" "v_short_.htm")
+ ("dpb" "f_dpb.htm")
+ ("dribble" "f_dribbl.htm")
+ ("dynamic-extent" "d_dynami.htm")
+ ("ecase" "m_case_.htm")
+ ("echo-stream" "t_echo_s.htm")
+ ("echo-stream-input-stream" "f_echo_s.htm")
+ ("echo-stream-output-stream" "f_echo_s.htm")
+ ("ed" "f_ed.htm")
+ ("eighth" "f_firstc.htm")
+ ("elt" "f_elt.htm")
+ ("encode-universal-time" "f_encode.htm")
+ ("end-of-file" "e_end_of.htm")
+ ("endp" "f_endp.htm")
+ ("enough-namestring" "f_namest.htm")
+ ("ensure-directories-exist" "f_ensu_1.htm")
+ ("ensure-generic-function" "f_ensure.htm")
+ ("eq" "f_eq.htm")
+ ("eql" "a_eql.htm")
+ ("equal" "f_equal.htm")
+ ("equalp" "f_equalp.htm")
+ ("error" "a_error.htm")
+ ("etypecase" "m_tpcase.htm")
+ ("eval" "f_eval.htm")
+ ("eval-when" "s_eval_w.htm")
+ ("evenp" "f_evenpc.htm")
+ ("every" "f_everyc.htm")
+ ("exp" "f_exp_e.htm")
+ ("export" "f_export.htm")
+ ("expt" "f_exp_e.htm")
+ ("extended-char" "t_extend.htm")
+ ("fboundp" "f_fbound.htm")
+ ("fceiling" "f_floorc.htm")
+ ("fdefinition" "f_fdefin.htm")
+ ("ffloor" "f_floorc.htm")
+ ("fifth" "f_firstc.htm")
+ ("file-author" "f_file_a.htm")
+ ("file-error" "e_file_e.htm")
+ ("file-error-pathname" "f_file_e.htm")
+ ("file-length" "f_file_l.htm")
+ ("file-namestring" "f_namest.htm")
+ ("file-position" "f_file_p.htm")
+ ("file-stream" "t_file_s.htm")
+ ("file-string-length" "f_file_s.htm")
+ ("file-write-date" "f_file_w.htm")
+ ("fill" "f_fill.htm")
+ ("fill-pointer" "f_fill_p.htm")
+ ("find" "f_find_.htm")
+ ("find-all-symbols" "f_find_a.htm")
+ ("find-class" "f_find_c.htm")
+ ("find-if" "f_find_.htm")
+ ("find-if-not" "f_find_.htm")
+ ("find-method" "f_find_m.htm")
+ ("find-package" "f_find_p.htm")
+ ("find-restart" "f_find_r.htm")
+ ("find-symbol" "f_find_s.htm")
+ ("finish-output" "f_finish.htm")
+ ("first" "f_firstc.htm")
+ ("fixnum" "t_fixnum.htm")
+ ("flet" "s_flet_.htm")
+ ("float" "a_float.htm")
+ ("float-digits" "f_dec_fl.htm")
+ ("float-precision" "f_dec_fl.htm")
+ ("float-radix" "f_dec_fl.htm")
+ ("float-sign" "f_dec_fl.htm")
+ ("floating-point-inexact" "e_floa_1.htm")
+ ("floating-point-invalid-operation" "e_floati.htm")
+ ("floating-point-overflow" "e_floa_2.htm")
+ ("floating-point-underflow" "e_floa_3.htm")
+ ("floatp" "f_floatp.htm")
+ ("floor" "f_floorc.htm")
+ ("fmakunbound" "f_fmakun.htm")
+ ("force-output" "f_finish.htm")
+ ("format" "f_format.htm")
+ ("formatter" "m_format.htm")
+ ("fourth" "f_firstc.htm")
+ ("fresh-line" "f_terpri.htm")
+ ("fround" "f_floorc.htm")
+ ("ftruncate" "f_floorc.htm")
+ ("ftype" "d_ftype.htm")
+ ("funcall" "f_funcal.htm")
+ ("function" "a_fn.htm")
+ ("function-keywords" "f_fn_kwd.htm")
+ ("function-lambda-expression" "f_fn_lam.htm")
+ ("functionp" "f_fnp.htm")
+ ("gcd" "f_gcd.htm")
+ ("generic-function" "t_generi.htm")
+ ("gensym" "f_gensym.htm")
+ ("gentemp" "f_gentem.htm")
+ ("get" "f_get.htm")
+ ("get-decoded-time" "f_get_un.htm")
+ ("get-dispatch-macro-character" "f_set__1.htm")
+ ("get-internal-real-time" "f_get_in.htm")
+ ("get-internal-run-time" "f_get__1.htm")
+ ("get-macro-character" "f_set_ma.htm")
+ ("get-output-stream-string" "f_get_ou.htm")
+ ("get-properties" "f_get_pr.htm")
+ ("get-setf-expansion" "f_get_se.htm")
+ ("get-universal-time" "f_get_un.htm")
+ ("getf" "f_getf.htm")
+ ("gethash" "f_gethas.htm")
+ ("go" "s_go.htm")
+ ("graphic-char-p" "f_graphi.htm")
+ ("handler-bind" "m_handle.htm")
+ ("handler-case" "m_hand_1.htm")
+ ("hash-table" "t_hash_t.htm")
+ ("hash-table-count" "f_hash_1.htm")
+ ("hash-table-p" "f_hash_t.htm")
+ ("hash-table-rehash-size" "f_hash_2.htm")
+ ("hash-table-rehash-threshold" "f_hash_3.htm")
+ ("hash-table-size" "f_hash_4.htm")
+ ("hash-table-test" "f_hash_5.htm")
+ ("host-namestring" "f_namest.htm")
+ ("identity" "f_identi.htm")
+ ("if" "s_if.htm")
+ ("ignorable" "d_ignore.htm")
+ ("ignore" "d_ignore.htm")
+ ("ignore-errors" "m_ignore.htm")
+ ("imagpart" "f_realpa.htm")
+ ("import" "f_import.htm")
+ ("in-package" "m_in_pkg.htm")
+ ("incf" "m_incf_.htm")
+ ("initialize-instance" "f_init_i.htm")
+ ("inline" "d_inline.htm")
+ ("input-stream-p" "f_in_stm.htm")
+ ("inspect" "f_inspec.htm")
+ ("integer" "t_intege.htm")
+ ("integer-decode-float" "f_dec_fl.htm")
+ ("integer-length" "f_intege.htm")
+ ("integerp" "f_inte_1.htm")
+ ("interactive-stream-p" "f_intera.htm")
+ ("intern" "f_intern.htm")
+ ("internal-time-units-per-second" "v_intern.htm")
+ ("intersection" "f_isec_.htm")
+ ("invalid-method-error" "f_invali.htm")
+ ("invoke-debugger" "f_invoke.htm")
+ ("invoke-restart" "f_invo_1.htm")
+ ("invoke-restart-interactively" "f_invo_2.htm")
+ ("isqrt" "f_sqrt_.htm")
+ ("keyword" "t_kwd.htm")
+ ("keywordp" "f_kwdp.htm")
+ ("labels" "s_flet_.htm")
+ ("lambda" "a_lambda.htm")
+ ("lambda-list-keywords" "v_lambda.htm")
+ ("lambda-parameters-limit" "v_lamb_1.htm")
+ ("last" "f_last.htm")
+ ("lcm" "f_lcm.htm")
+ ("ldb" "f_ldb.htm")
+ ("ldb-test" "f_ldb_te.htm")
+ ("ldiff" "f_ldiffc.htm")
+ ("least-negative-double-float" "v_most_1.htm")
+ ("least-negative-long-float" "v_most_1.htm")
+ ("least-negative-normalized-double-float" "v_most_1.htm")
+ ("least-negative-normalized-long-float" "v_most_1.htm")
+ ("least-negative-normalized-short-float" "v_most_1.htm")
+ ("least-negative-normalized-single-float" "v_most_1.htm")
+ ("least-negative-short-float" "v_most_1.htm")
+ ("least-negative-single-float" "v_most_1.htm")
+ ("least-positive-double-float" "v_most_1.htm")
+ ("least-positive-long-float" "v_most_1.htm")
+ ("least-positive-normalized-double-float" "v_most_1.htm")
+ ("least-positive-normalized-long-float" "v_most_1.htm")
+ ("least-positive-normalized-short-float" "v_most_1.htm")
+ ("least-positive-normalized-single-float" "v_most_1.htm")
+ ("least-positive-short-float" "v_most_1.htm")
+ ("least-positive-single-float" "v_most_1.htm")
+ ("length" "f_length.htm")
+ ("let" "s_let_l.htm")
+ ("let*" "s_let_l.htm")
+ ("lisp-implementation-type" "f_lisp_i.htm")
+ ("lisp-implementation-version" "f_lisp_i.htm")
+ ("list" "a_list.htm")
+ ("list*" "f_list_.htm")
+ ("list-all-packages" "f_list_a.htm")
+ ("list-length" "f_list_l.htm")
+ ("listen" "f_listen.htm")
+ ("listp" "f_listp.htm")
+ ("load" "f_load.htm")
+ ("load-logical-pathname-translations" "f_ld_log.htm")
+ ("load-time-value" "s_ld_tim.htm")
+ ("locally" "s_locall.htm")
+ ("log" "f_log.htm")
+ ("logand" "f_logand.htm")
+ ("logandc1" "f_logand.htm")
+ ("logandc2" "f_logand.htm")
+ ("logbitp" "f_logbtp.htm")
+ ("logcount" "f_logcou.htm")
+ ("logeqv" "f_logand.htm")
+ ("logical-pathname" "a_logica.htm")
+ ("logical-pathname-translations" "f_logica.htm")
+ ("logior" "f_logand.htm")
+ ("lognand" "f_logand.htm")
+ ("lognor" "f_logand.htm")
+ ("lognot" "f_logand.htm")
+ ("logorc1" "f_logand.htm")
+ ("logorc2" "f_logand.htm")
+ ("logtest" "f_logtes.htm")
+ ("logxor" "f_logand.htm")
+ ("long-float" "t_short_.htm")
+ ("long-float-epsilon" "v_short_.htm")
+ ("long-float-negative-epsilon" "v_short_.htm")
+ ("long-site-name" "f_short_.htm")
+ ("loop" "m_loop.htm")
+ ("loop-finish" "m_loop_f.htm")
+ ("lower-case-p" "f_upper_.htm")
+ ("machine-instance" "f_mach_i.htm")
+ ("machine-type" "f_mach_t.htm")
+ ("machine-version" "f_mach_v.htm")
+ ("macro-function" "f_macro_.htm")
+ ("macroexpand" "f_mexp_.htm")
+ ("macroexpand-1" "f_mexp_.htm")
+ ("macrolet" "s_flet_.htm")
+ ("make-array" "f_mk_ar.htm")
+ ("make-broadcast-stream" "f_mk_bro.htm")
+ ("make-concatenated-stream" "f_mk_con.htm")
+ ("make-condition" "f_mk_cnd.htm")
+ ("make-dispatch-macro-character" "f_mk_dis.htm")
+ ("make-echo-stream" "f_mk_ech.htm")
+ ("make-hash-table" "f_mk_has.htm")
+ ("make-instance" "f_mk_ins.htm")
+ ("make-instances-obsolete" "f_mk_i_1.htm")
+ ("make-list" "f_mk_lis.htm")
+ ("make-load-form" "f_mk_ld_.htm")
+ ("make-load-form-saving-slots" "f_mk_l_1.htm")
+ ("make-method" "m_call_m.htm")
+ ("make-package" "f_mk_pkg.htm")
+ ("make-pathname" "f_mk_pn.htm")
+ ("make-random-state" "f_mk_rnd.htm")
+ ("make-sequence" "f_mk_seq.htm")
+ ("make-string" "f_mk_stg.htm")
+ ("make-string-input-stream" "f_mk_s_1.htm")
+ ("make-string-output-stream" "f_mk_s_2.htm")
+ ("make-symbol" "f_mk_sym.htm")
+ ("make-synonym-stream" "f_mk_syn.htm")
+ ("make-two-way-stream" "f_mk_two.htm")
+ ("makunbound" "f_makunb.htm")
+ ("map" "f_map.htm")
+ ("map-into" "f_map_in.htm")
+ ("mapc" "f_mapc_.htm")
+ ("mapcan" "f_mapc_.htm")
+ ("mapcar" "f_mapc_.htm")
+ ("mapcon" "f_mapc_.htm")
+ ("maphash" "f_maphas.htm")
+ ("mapl" "f_mapc_.htm")
+ ("maplist" "f_mapc_.htm")
+ ("mask-field" "f_mask_f.htm")
+ ("max" "f_max_m.htm")
+ ("member" "a_member.htm")
+ ("member-if" "f_mem_m.htm")
+ ("member-if-not" "f_mem_m.htm")
+ ("merge" "f_merge.htm")
+ ("merge-pathnames" "f_merge_.htm")
+ ("method" "t_method.htm")
+ ("method-combination" "a_method.htm")
+ ("method-combination-error" "f_meth_1.htm")
+ ("method-qualifiers" "f_method.htm")
+ ("min" "f_max_m.htm")
+ ("minusp" "f_minusp.htm")
+ ("mismatch" "f_mismat.htm")
+ ("mod" "a_mod.htm")
+ ("most-negative-double-float" "v_most_1.htm")
+ ("most-negative-fixnum" "v_most_p.htm")
+ ("most-negative-long-float" "v_most_1.htm")
+ ("most-negative-short-float" "v_most_1.htm")
+ ("most-negative-single-float" "v_most_1.htm")
+ ("most-positive-double-float" "v_most_1.htm")
+ ("most-positive-fixnum" "v_most_p.htm")
+ ("most-positive-long-float" "v_most_1.htm")
+ ("most-positive-short-float" "v_most_1.htm")
+ ("most-positive-single-float" "v_most_1.htm")
+ ("muffle-warning" "a_muffle.htm")
+ ("multiple-value-bind" "m_multip.htm")
+ ("multiple-value-call" "s_multip.htm")
+ ("multiple-value-list" "m_mult_1.htm")
+ ("multiple-value-prog1" "s_mult_1.htm")
+ ("multiple-value-setq" "m_mult_2.htm")
+ ("multiple-values-limit" "v_multip.htm")
+ ("name-char" "f_name_c.htm")
+ ("namestring" "f_namest.htm")
+ ("nbutlast" "f_butlas.htm")
+ ("nconc" "f_nconc.htm")
+ ("next-method-p" "f_next_m.htm")
+ ("nil" "a_nil.htm")
+ ("nintersection" "f_isec_.htm")
+ ("ninth" "f_firstc.htm")
+ ("no-applicable-method" "f_no_app.htm")
+ ("no-next-method" "f_no_nex.htm")
+ ("not" "a_not.htm")
+ ("notany" "f_everyc.htm")
+ ("notevery" "f_everyc.htm")
+ ("notinline" "d_inline.htm")
+ ("nreconc" "f_revapp.htm")
+ ("nreverse" "f_revers.htm")
+ ("nset-difference" "f_set_di.htm")
+ ("nset-exclusive-or" "f_set_ex.htm")
+ ("nstring-capitalize" "f_stg_up.htm")
+ ("nstring-downcase" "f_stg_up.htm")
+ ("nstring-upcase" "f_stg_up.htm")
+ ("nsublis" "f_sublis.htm")
+ ("nsubst" "f_substc.htm")
+ ("nsubst-if" "f_substc.htm")
+ ("nsubst-if-not" "f_substc.htm")
+ ("nsubstitute" "f_sbs_s.htm")
+ ("nsubstitute-if" "f_sbs_s.htm")
+ ("nsubstitute-if-not" "f_sbs_s.htm")
+ ("nth" "f_nth.htm")
+ ("nth-value" "m_nth_va.htm")
+ ("nthcdr" "f_nthcdr.htm")
+ ("null" "a_null.htm")
+ ("number" "t_number.htm")
+ ("numberp" "f_nump.htm")
+ ("numerator" "f_numera.htm")
+ ("nunion" "f_unionc.htm")
+ ("oddp" "f_evenpc.htm")
+ ("open" "f_open.htm")
+ ("open-stream-p" "f_open_s.htm")
+ ("optimize" "d_optimi.htm")
+ ("or" "a_or.htm")
+ ("otherwise" "m_case_.htm")
+ ("output-stream-p" "f_in_stm.htm")
+ ("package" "t_pkg.htm")
+ ("package-error" "e_pkg_er.htm")
+ ("package-error-package" "f_pkg_er.htm")
+ ("package-name" "f_pkg_na.htm")
+ ("package-nicknames" "f_pkg_ni.htm")
+ ("package-shadowing-symbols" "f_pkg_sh.htm")
+ ("package-use-list" "f_pkg_us.htm")
+ ("package-used-by-list" "f_pkg__1.htm")
+ ("packagep" "f_pkgp.htm")
+ ("pairlis" "f_pairli.htm")
+ ("parse-error" "e_parse_.htm")
+ ("parse-integer" "f_parse_.htm")
+ ("parse-namestring" "f_pars_1.htm")
+ ("pathname" "a_pn.htm")
+ ("pathname-device" "f_pn_hos.htm")
+ ("pathname-directory" "f_pn_hos.htm")
+ ("pathname-host" "f_pn_hos.htm")
+ ("pathname-match-p" "f_pn_mat.htm")
+ ("pathname-name" "f_pn_hos.htm")
+ ("pathname-type" "f_pn_hos.htm")
+ ("pathname-version" "f_pn_hos.htm")
+ ("pathnamep" "f_pnp.htm")
+ ("peek-char" "f_peek_c.htm")
+ ("phase" "f_phase.htm")
+ ("pi" "v_pi.htm")
+ ("plusp" "f_minusp.htm")
+ ("pop" "m_pop.htm")
+ ("position" "f_pos_p.htm")
+ ("position-if" "f_pos_p.htm")
+ ("position-if-not" "f_pos_p.htm")
+ ("pprint" "f_wr_pr.htm")
+ ("pprint-dispatch" "f_ppr_di.htm")
+ ("pprint-exit-if-list-exhausted" "m_ppr_ex.htm")
+ ("pprint-fill" "f_ppr_fi.htm")
+ ("pprint-indent" "f_ppr_in.htm")
+ ("pprint-linear" "f_ppr_fi.htm")
+ ("pprint-logical-block" "m_ppr_lo.htm")
+ ("pprint-newline" "f_ppr_nl.htm")
+ ("pprint-pop" "m_ppr_po.htm")
+ ("pprint-tab" "f_ppr_ta.htm")
+ ("pprint-tabular" "f_ppr_fi.htm")
+ ("prin1" "f_wr_pr.htm")
+ ("prin1-to-string" "f_wr_to_.htm")
+ ("princ" "f_wr_pr.htm")
+ ("princ-to-string" "f_wr_to_.htm")
+ ("print" "f_wr_pr.htm")
+ ("print-not-readable" "e_pr_not.htm")
+ ("print-not-readable-object" "f_pr_not.htm")
+ ("print-object" "f_pr_obj.htm")
+ ("print-unreadable-object" "m_pr_unr.htm")
+ ("probe-file" "f_probe_.htm")
+ ("proclaim" "f_procla.htm")
+ ("prog" "m_prog_.htm")
+ ("prog*" "m_prog_.htm")
+ ("prog1" "m_prog1c.htm")
+ ("prog2" "m_prog1c.htm")
+ ("progn" "s_progn.htm")
+ ("program-error" "e_progra.htm")
+ ("progv" "s_progv.htm")
+ ("provide" "f_provid.htm")
+ ("psetf" "m_setf_.htm")
+ ("psetq" "m_psetq.htm")
+ ("push" "m_push.htm")
+ ("pushnew" "m_pshnew.htm")
+ ("quote" "s_quote.htm")
+ ("random" "f_random.htm")
+ ("random-state" "t_rnd_st.htm")
+ ("random-state-p" "f_rnd_st.htm")
+ ("rassoc" "f_rassoc.htm")
+ ("rassoc-if" "f_rassoc.htm")
+ ("rassoc-if-not" "f_rassoc.htm")
+ ("ratio" "t_ratio.htm")
+ ("rational" "a_ration.htm")
+ ("rationalize" "f_ration.htm")
+ ("rationalp" "f_rati_1.htm")
+ ("read" "f_rd_rd.htm")
+ ("read-byte" "f_rd_by.htm")
+ ("read-char" "f_rd_cha.htm")
+ ("read-char-no-hang" "f_rd_c_1.htm")
+ ("read-delimited-list" "f_rd_del.htm")
+ ("read-from-string" "f_rd_fro.htm")
+ ("read-line" "f_rd_lin.htm")
+ ("read-preserving-whitespace" "f_rd_rd.htm")
+ ("read-sequence" "f_rd_seq.htm")
+ ("reader-error" "e_rder_e.htm")
+ ("readtable" "t_rdtabl.htm")
+ ("readtable-case" "f_rdtabl.htm")
+ ("readtablep" "f_rdta_1.htm")
+ ("real" "t_real.htm")
+ ("realp" "f_realp.htm")
+ ("realpart" "f_realpa.htm")
+ ("reduce" "f_reduce.htm")
+ ("reinitialize-instance" "f_reinit.htm")
+ ("rem" "f_mod_r.htm")
+ ("remf" "m_remf.htm")
+ ("remhash" "f_remhas.htm")
+ ("remove" "f_rm_rm.htm")
+ ("remove-duplicates" "f_rm_dup.htm")
+ ("remove-if" "f_rm_rm.htm")
+ ("remove-if-not" "f_rm_rm.htm")
+ ("remove-method" "f_rm_met.htm")
+ ("remprop" "f_rempro.htm")
+ ("rename-file" "f_rn_fil.htm")
+ ("rename-package" "f_rn_pkg.htm")
+ ("replace" "f_replac.htm")
+ ("require" "f_provid.htm")
+ ("rest" "f_rest.htm")
+ ("restart" "t_rst.htm")
+ ("restart-bind" "m_rst_bi.htm")
+ ("restart-case" "m_rst_ca.htm")
+ ("restart-name" "f_rst_na.htm")
+ ("return" "m_return.htm")
+ ("return-from" "s_ret_fr.htm")
+ ("revappend" "f_revapp.htm")
+ ("reverse" "f_revers.htm")
+ ("room" "f_room.htm")
+ ("rotatef" "m_rotate.htm")
+ ("round" "f_floorc.htm")
+ ("row-major-aref" "f_row_ma.htm")
+ ("rplaca" "f_rplaca.htm")
+ ("rplacd" "f_rplaca.htm")
+ ("safety" "d_optimi.htm")
+ ("satisfies" "t_satisf.htm")
+ ("sbit" "f_bt_sb.htm")
+ ("scale-float" "f_dec_fl.htm")
+ ("schar" "f_char_.htm")
+ ("search" "f_search.htm")
+ ("second" "f_firstc.htm")
+ ("sequence" "t_seq.htm")
+ ("serious-condition" "e_seriou.htm")
+ ("set" "f_set.htm")
+ ("set-difference" "f_set_di.htm")
+ ("set-dispatch-macro-character" "f_set__1.htm")
+ ("set-exclusive-or" "f_set_ex.htm")
+ ("set-macro-character" "f_set_ma.htm")
+ ("set-pprint-dispatch" "f_set_pp.htm")
+ ("set-syntax-from-char" "f_set_sy.htm")
+ ("setf" "a_setf.htm")
+ ("setq" "s_setq.htm")
+ ("seventh" "f_firstc.htm")
+ ("shadow" "f_shadow.htm")
+ ("shadowing-import" "f_shdw_i.htm")
+ ("shared-initialize" "f_shared.htm")
+ ("shiftf" "m_shiftf.htm")
+ ("short-float" "t_short_.htm")
+ ("short-float-epsilon" "v_short_.htm")
+ ("short-float-negative-epsilon" "v_short_.htm")
+ ("short-site-name" "f_short_.htm")
+ ("signal" "f_signal.htm")
+ ("signed-byte" "t_sgn_by.htm")
+ ("signum" "f_signum.htm")
+ ("simple-array" "t_smp_ar.htm")
+ ("simple-base-string" "t_smp_ba.htm")
+ ("simple-bit-vector" "t_smp_bt.htm")
+ ("simple-bit-vector-p" "f_smp_bt.htm")
+ ("simple-condition" "e_smp_cn.htm")
+ ("simple-condition-format-arguments" "f_smp_cn.htm")
+ ("simple-condition-format-control" "f_smp_cn.htm")
+ ("simple-error" "e_smp_er.htm")
+ ("simple-string" "t_smp_st.htm")
+ ("simple-string-p" "f_smp_st.htm")
+ ("simple-type-error" "e_smp_tp.htm")
+ ("simple-vector" "t_smp_ve.htm")
+ ("simple-vector-p" "f_smp_ve.htm")
+ ("simple-warning" "e_smp_wa.htm")
+ ("sin" "f_sin_c.htm")
+ ("single-float" "t_short_.htm")
+ ("single-float-epsilon" "v_short_.htm")
+ ("single-float-negative-epsilon" "v_short_.htm")
+ ("sinh" "f_sinh_.htm")
+ ("sixth" "f_firstc.htm")
+ ("sleep" "f_sleep.htm")
+ ("slot-boundp" "f_slt_bo.htm")
+ ("slot-exists-p" "f_slt_ex.htm")
+ ("slot-makunbound" "f_slt_ma.htm")
+ ("slot-missing" "f_slt_mi.htm")
+ ("slot-unbound" "f_slt_un.htm")
+ ("slot-value" "f_slt_va.htm")
+ ("software-type" "f_sw_tpc.htm")
+ ("software-version" "f_sw_tpc.htm")
+ ("some" "f_everyc.htm")
+ ("sort" "f_sort_.htm")
+ ("space" "d_optimi.htm")
+ ("special" "d_specia.htm")
+ ("special-operator-p" "f_specia.htm")
+ ("speed" "d_optimi.htm")
+ ("sqrt" "f_sqrt_.htm")
+ ("stable-sort" "f_sort_.htm")
+ ("standard" "07_ffb.htm")
+ ("standard-char" "t_std_ch.htm")
+ ("standard-char-p" "f_std_ch.htm")
+ ("standard-class" "t_std_cl.htm")
+ ("standard-generic-function" "t_std_ge.htm")
+ ("standard-method" "t_std_me.htm")
+ ("standard-object" "t_std_ob.htm")
+ ("step" "m_step.htm")
+ ("storage-condition" "e_storag.htm")
+ ("store-value" "a_store_.htm")
+ ("stream" "t_stream.htm")
+ ("stream-element-type" "f_stm_el.htm")
+ ("stream-error" "e_stm_er.htm")
+ ("stream-error-stream" "f_stm_er.htm")
+ ("stream-external-format" "f_stm_ex.htm")
+ ("streamp" "f_stmp.htm")
+ ("string" "a_string.htm")
+ ("string-capitalize" "f_stg_up.htm")
+ ("string-downcase" "f_stg_up.htm")
+ ("string-equal" "f_stgeq_.htm")
+ ("string-greaterp" "f_stgeq_.htm")
+ ("string-left-trim" "f_stg_tr.htm")
+ ("string-lessp" "f_stgeq_.htm")
+ ("string-not-equal" "f_stgeq_.htm")
+ ("string-not-greaterp" "f_stgeq_.htm")
+ ("string-not-lessp" "f_stgeq_.htm")
+ ("string-right-trim" "f_stg_tr.htm")
+ ("string-stream" "t_stg_st.htm")
+ ("string-trim" "f_stg_tr.htm")
+ ("string-upcase" "f_stg_up.htm")
+ ("string/=" "f_stgeq_.htm")
+ ("string<" "f_stgeq_.htm")
+ ("string<=" "f_stgeq_.htm")
+ ("string=" "f_stgeq_.htm")
+ ("string>" "f_stgeq_.htm")
+ ("string>=" "f_stgeq_.htm")
+ ("stringp" "f_stgp.htm")
+ ("structure" "f_docume.htm")
+ ("structure-class" "t_stu_cl.htm")
+ ("structure-object" "t_stu_ob.htm")
+ ("style-warning" "e_style_.htm")
+ ("sublis" "f_sublis.htm")
+ ("subseq" "f_subseq.htm")
+ ("subsetp" "f_subset.htm")
+ ("subst" "f_substc.htm")
+ ("subst-if" "f_substc.htm")
+ ("subst-if-not" "f_substc.htm")
+ ("substitute" "f_sbs_s.htm")
+ ("substitute-if" "f_sbs_s.htm")
+ ("substitute-if-not" "f_sbs_s.htm")
+ ("subtypep" "f_subtpp.htm")
+ ("svref" "f_svref.htm")
+ ("sxhash" "f_sxhash.htm")
+ ("symbol" "t_symbol.htm")
+ ("symbol-function" "f_symb_1.htm")
+ ("symbol-macrolet" "s_symbol.htm")
+ ("symbol-name" "f_symb_2.htm")
+ ("symbol-package" "f_symb_3.htm")
+ ("symbol-plist" "f_symb_4.htm")
+ ("symbol-value" "f_symb_5.htm")
+ ("symbolp" "f_symbol.htm")
+ ("synonym-stream" "t_syn_st.htm")
+ ("synonym-stream-symbol" "f_syn_st.htm")
+ ("t" "a_t.htm")
+ ("tagbody" "s_tagbod.htm")
+ ("tailp" "f_ldiffc.htm")
+ ("tan" "f_sin_c.htm")
+ ("tanh" "f_sinh_.htm")
+ ("tenth" "f_firstc.htm")
+ ("terpri" "f_terpri.htm")
+ ("the" "s_the.htm")
+ ("third" "f_firstc.htm")
+ ("throw" "s_throw.htm")
+ ("time" "m_time.htm")
+ ("trace" "m_tracec.htm")
+ ("translate-logical-pathname" "f_tr_log.htm")
+ ("translate-pathname" "f_tr_pn.htm")
+ ("tree-equal" "f_tree_e.htm")
+ ("truename" "f_tn.htm")
+ ("truncate" "f_floorc.htm")
+ ("two-way-stream" "t_two_wa.htm")
+ ("two-way-stream-input-stream" "f_two_wa.htm")
+ ("two-way-stream-output-stream" "f_two_wa.htm")
+ ("type" "a_type.htm")
+ ("type-error" "e_tp_err.htm")
+ ("type-error-datum" "f_tp_err.htm")
+ ("type-error-expected-type" "f_tp_err.htm")
+ ("type-of" "f_tp_of.htm")
+ ("typecase" "m_tpcase.htm")
+ ("typep" "f_typep.htm")
+ ("unbound-slot" "e_unboun.htm")
+ ("unbound-slot-instance" "f_unboun.htm")
+ ("unbound-variable" "e_unbo_1.htm")
+ ("undefined-function" "e_undefi.htm")
+ ("unexport" "f_unexpo.htm")
+ ("unintern" "f_uninte.htm")
+ ("union" "f_unionc.htm")
+ ("unless" "m_when_.htm")
+ ("unread-char" "f_unrd_c.htm")
+ ("unsigned-byte" "t_unsgn_.htm")
+ ("untrace" "m_tracec.htm")
+ ("unuse-package" "f_unuse_.htm")
+ ("unwind-protect" "s_unwind.htm")
+ ("update-instance-for-different-class" "f_update.htm")
+ ("update-instance-for-redefined-class" "f_upda_1.htm")
+ ("upgraded-array-element-type" "f_upgr_1.htm")
+ ("upgraded-complex-part-type" "f_upgrad.htm")
+ ("upper-case-p" "f_upper_.htm")
+ ("use-package" "f_use_pk.htm")
+ ("use-value" "a_use_va.htm")
+ ("user-homedir-pathname" "f_user_h.htm")
+ ("values" "a_values.htm")
+ ("values-list" "f_vals_l.htm")
+ ("variable" "f_docume.htm")
+ ("vector" "a_vector.htm")
+ ("vector-pop" "f_vec_po.htm")
+ ("vector-push" "f_vec_ps.htm")
+ ("vector-push-extend" "f_vec_ps.htm")
+ ("vectorp" "f_vecp.htm")
+ ("warn" "f_warn.htm")
+ ("warning" "e_warnin.htm")
+ ("when" "m_when_.htm")
+ ("wild-pathname-p" "f_wild_p.htm")
+ ("with-accessors" "m_w_acce.htm")
+ ("with-compilation-unit" "m_w_comp.htm")
+ ("with-condition-restarts" "m_w_cnd_.htm")
+ ("with-hash-table-iterator" "m_w_hash.htm")
+ ("with-input-from-string" "m_w_in_f.htm")
+ ("with-open-file" "m_w_open.htm")
+ ("with-open-stream" "m_w_op_1.htm")
+ ("with-output-to-string" "m_w_out_.htm")
+ ("with-package-iterator" "m_w_pkg_.htm")
+ ("with-simple-restart" "m_w_smp_.htm")
+ ("with-slots" "m_w_slts.htm")
+ ("with-standard-io-syntax" "m_w_std_.htm")
+ ("write" "f_wr_pr.htm")
+ ("write-byte" "f_wr_by.htm")
+ ("write-char" "f_wr_cha.htm")
+ ("write-line" "f_wr_stg.htm")
+ ("write-sequence" "f_wr_seq.htm")
+ ("write-string" "f_wr_stg.htm")
+ ("write-to-string" "f_wr_to_.htm")
+ ("y-or-n-p" "f_y_or_n.htm")
+ ("yes-or-no-p" "f_y_or_n.htm")
+ ("zerop" "f_zerop.htm"))))
+
+;;; FORMAT character lookup by Frode Vatvedt Fjeld <frodef at acm.org> 20030902
+;;;
+;;; adjusted for ILISP by Nikodemus Siivola 20030903
+
+(defvar common-lisp-hyperspec-format-history nil
+ "History of format characters looked up in the Common Lisp HyperSpec.")
+
+(defvar common-lisp-hyperspec-format-characters (make-vector 67 0))
+
+
+(defun common-lisp-hyperspec-section-6.0 (indices)
+ (let ((string (format "%sBody/%s_"
+ common-lisp-hyperspec-root
+ (let ((base (pop indices)))
+ (if (< base 10)
+ (format "0%s" base)
+ base)))))
+ (concat string
+ (mapconcat (lambda (n)
+ (make-string 1 (+ ?a (- n 1))))
+ indices
+ "")
+ ".htm")))
+
+(defun common-lisp-hyperspec-section-4.0 (indices)
+ (let ((string (format "%sBody/sec_"
+ common-lisp-hyperspec-root)))
+ (concat string
+ (mapconcat (lambda (n)
+ (format "%d" n))
+ indices
+ "-")
+ ".html")))
+
+(defvar common-lisp-hyperspec-section-fun 'common-lisp-hyperspec-section-6.0)
+
+(defun common-lisp-hyperspec-section (indices)
+ (funcall common-lisp-hyperspec-section-fun indices))
+
+(defun common-lisp-hyperspec-format (character-name)
+ (interactive
+ (list (let ((char-at-point
+ (ignore-errors (char-to-string (char-after (point))))))
+ (if (and char-at-point
+ (intern-soft (upcase char-at-point)
+ common-lisp-hyperspec-format-characters))
+ char-at-point
+ (completing-read
+ "Look up format control character in Common Lisp HyperSpec: "
+ common-lisp-hyperspec-format-characters nil #'boundp
+ nil nil 'common-lisp-hyperspec-format-history)))))
+ (maplist (lambda (entry)
+ (browse-url (common-lisp-hyperspec-section (car entry))))
+ (let ((symbol (intern-soft character-name
+ common-lisp-hyperspec-format-characters)))
+ (if (and symbol (boundp symbol))
+ (symbol-value symbol)
+ (error "The symbol `%s' is not defined in Common Lisp"
+ character-name)))))
+
+(eval-when (load eval)
+ (defalias 'hyperspec-lookup-format 'common-lisp-hyperspec-format))
+
+(mapcar (lambda (entry)
+ (let ((symbol (intern (car entry)
+ common-lisp-hyperspec-format-characters)))
+ (if (boundp symbol)
+ (pushnew (cadr entry) (symbol-value symbol) :test 'equal)
+ (set symbol (cdr entry))))
+ (when (and (= 1 (length (car entry)))
+ (not (string-equal (car entry) (upcase (car entry)))))
+ (let ((symbol (intern (upcase (car entry))
+ common-lisp-hyperspec-format-characters)))
+ (if (boundp symbol)
+ (pushnew (cadr entry) (symbol-value symbol) :test 'equal)
+ (set symbol (cdr entry))))))
+ '(("c" (22 3 1 1)) ("C: Character" (22 3 1 1))
+ ("%" (22 3 1 2)) ("Percent: Newline" (22 3 1 2))
+ ("&" (22 3 1 3)) ("Ampersand: Fresh-line" (22 3 1 3))
+ ("|" (22 3 1 4)) ("Vertical-Bar: Page" (22 3 1 4))
+ ("~" (22 3 1 5)) ("Tilde: Tilde" (22 3 1 5))
+ ("r" (22 3 2 1)) ("R: Radix" (22 3 2 1))
+ ("d" (22 3 2 2)) ("D: Decimal" (22 3 2-2))
+ ("b" (22 3 2 3)) ("B: Binary" (22 3 2 3))
+ ("o" (22 3 2 4)) ("O: Octal" (22 3 2 4))
+ ("x" (22 3 2 5)) ("X: Hexadecimal" (22 3 2 5))
+ ("f" (22 3 3 1)) ("F: Fixed-Format Floating-Point" (22 3 3 1))
+ ("e" (22 3 3 2)) ("E: Exponential Floating-Point" (22 3 3 2))
+ ("g" (22 3 3 3)) ("G: General Floating-Point" (22 3 3 3))
+ ("$" (22 3 3 4)) ("Dollarsign: Monetary Floating-Point" (22 3 3 4))
+ ("a" (22 3 4 1)) ("A: Aesthetic" (22 3 4 1))
+ ("s" (22 3 4 2)) ("S: Standard" (22 3 4 2))
+ ("w" (22 3 4 3)) ("W: Write" (22 3 4 3))
+ ("_" (22 3 5 1)) ("Underscore: Conditional Newline" (22 3 5 1))
+ ("<" (22 3 5 2)) ("Less-Than-Sign: Logical Block" (22 3 5 2))
+ ("i" (22 3 5 3)) ("I: Indent" (22 3 5 3))
+ ("/" (22 3 5 4)) ("Slash: Call Function" (22 3 5 4))
+ ("t" (22 3 6 1)) ("T: Tabulate" (22 3 6 1))
+ ("<" (22 3 6 2)) ("Less-Than-Sign: Justification" (22 3 6 2))
+ (">" (22 3 6 3)) ("Greater-Than-Sign: End of Justification" (22 3 6 3))
+ ("*" (22 3 7 1)) ("Asterisk: Go-To" (22 3 7 1))
+ ("[" (22 3 7 2)) ("Left-Bracket: Conditional Expression" (22 3 7 2))
+ ("]" (22 3 7 3)) ("Right-Bracket: End of Conditional Expression" (22 3 7 3))
+ ("{" (22 3 7 4)) ("Left-Brace: Iteration" (22 3 7 4))
+ ("}" (22 3 7 5)) ("Right-Brace: End of Iteration" (22 3 7 5))
+ ("?" (22 3 7 6)) ("Question-Mark: Recursive Processing" (22 3 7 6))
+ ("(" (22 3 8 1)) ("Left-Paren: Case Conversion" (22 3 8 1))
+ (")" (22 3 8 2)) ("Right-Paren: End of Case Conversion" (22 3 8 2))
+ ("p" (22 3 8 3)) ("P: Plural" (22 3 8-3))
+ (";" (22 3 9 1)) ("Semicolon: Clause Separator" (22 3 9 1))
+ ("^" (22 3 9 2)) ("Circumflex: Escape Upward" (22 3 9 2))
+ ("Newline: Ignored Newline" (22 3 9 3))
+ ("Nesting of FORMAT Operations" (22 3 10 1))
+ ("Missing and Additional FORMAT Arguments" (22 3 10 2))
+ ("Additional FORMAT Parameters" (22 3 10 3))))
+
+(defvar common-lisp-glossary-fun 'common-lisp-glossary-6.0)
+
+(defun common-lisp-glossary-6.0 (string)
+ (format "%sBody/26_glo_%s.htm#%s"
+ common-lisp-hyperspec-root
+ (let ((char (string-to-char string)))
+ (if (and (<= ?a char)
+ (<= char ?z))
+ (make-string 1 char)
+ "9"))
+ (subst-char-in-string ?\ ?_ string)))
+
+(defun common-lisp-glossary-4.0 (string)
+ (format "%sBody/glo_%s.html#%s"
+ common-lisp-hyperspec-root
+ (let ((char (string-to-char string)))
+ (if (and (<= ?a char)
+ (<= char ?z))
+ (make-string 1 char)
+ "9"))
+ (subst-char-in-string ?\ ?_ string)))
+
+(defvar common-lisp-hyperspec-issuex-table nil
+ "The HyperSpec IssueX table file. If you copy the HyperSpec to your
+local system, set this variable to the location of the Issue
+cross-references table which is usually \"Map_IssX.txt\" or
+\"Issue-Cross-Refs.text\".")
+
+(defvar common-lisp-hyperspec-issuex-symbols (make-vector 67 0))
+
+(if common-lisp-hyperspec-issuex-table
+ (let ((index-buffer (find-file-noselect common-lisp-hyperspec-issuex-table)))
+ (labels ((get-one-line ()
+ (prog1
+ (delete* ?\n (thing-at-point 'line))
+ (forward-line))))
+ (save-excursion
+ (set-buffer index-buffer)
+ (goto-char (point-min))
+ (while (< (point) (point-max))
+ (let* ((symbol (intern (downcase (get-one-line))
+ common-lisp-hyperspec-issuex-symbols))
+ (relative-url (get-one-line)))
+ (set symbol (subseq relative-url
+ (1+ (position ?\/ relative-url :from-end t)))))))))
+ (mapcar
+ (lambda (entry)
+ (let ((symbol (intern (car entry) common-lisp-hyperspec-issuex-symbols)))
+ (set symbol (cadr entry))))
+ '(("&environment-binding-order:first" "iss001.htm")
+ ("access-error-name" "iss002.htm")
+ ("adjust-array-displacement" "iss003.htm")
+ ("adjust-array-fill-pointer" "iss004.htm")
+ ("adjust-array-not-adjustable:implicit-copy" "iss005.htm")
+ ("allocate-instance:add" "iss006.htm")
+ ("allow-local-inline:inline-notinline" "iss007.htm")
+ ("allow-other-keys-nil:permit" "iss008.htm")
+ ("aref-1d" "iss009.htm")
+ ("argument-mismatch-error-again:consistent" "iss010.htm")
+ ("argument-mismatch-error-moon:fix" "iss011.htm")
+ ("argument-mismatch-error:more-clarifications" "iss012.htm")
+ ("arguments-underspecified:specify" "iss013.htm")
+ ("array-dimension-limit-implications:all-fixnum" "iss014.htm")
+ ("array-type-element-type-semantics:unify-upgrading" "iss015.htm")
+ ("assert-error-type:error" "iss016.htm")
+ ("assoc-rassoc-if-key" "iss017.htm")
+ ("assoc-rassoc-if-key:yes" "iss018.htm")
+ ("boa-aux-initialization:error-on-read" "iss019.htm")
+ ("break-on-warnings-obsolete:remove" "iss020.htm")
+ ("broadcast-stream-return-values:clarify-minimally" "iss021.htm")
+ ("butlast-negative:should-signal" "iss022.htm")
+ ("change-class-initargs:permit" "iss023.htm")
+ ("char-name-case:x3j13-mar-91" "iss024.htm")
+ ("character-loose-ends:fix" "iss025.htm")
+ ("character-proposal:2" "iss026.htm")
+ ("character-proposal:2-1-1" "iss027.htm")
+ ("character-proposal:2-1-2" "iss028.htm")
+ ("character-proposal:2-2-1" "iss029.htm")
+ ("character-proposal:2-3-1" "iss030.htm")
+ ("character-proposal:2-3-2" "iss031.htm")
+ ("character-proposal:2-3-3" "iss032.htm")
+ ("character-proposal:2-3-4" "iss033.htm")
+ ("character-proposal:2-3-5" "iss034.htm")
+ ("character-proposal:2-3-6" "iss035.htm")
+ ("character-proposal:2-4-1" "iss036.htm")
+ ("character-proposal:2-4-2" "iss037.htm")
+ ("character-proposal:2-4-3" "iss038.htm")
+ ("character-proposal:2-5-2" "iss039.htm")
+ ("character-proposal:2-5-6" "iss040.htm")
+ ("character-proposal:2-5-7" "iss041.htm")
+ ("character-proposal:2-6-1" "iss042.htm")
+ ("character-proposal:2-6-2" "iss043.htm")
+ ("character-proposal:2-6-3" "iss044.htm")
+ ("character-proposal:2-6-5" "iss045.htm")
+ ("character-vs-char:less-inconsistent-short" "iss046.htm")
+ ("class-object-specializer:affirm" "iss047.htm")
+ ("clos-conditions-again:allow-subset" "iss048.htm")
+ ("clos-conditions:integrate" "iss049.htm")
+ ("clos-error-checking-order:no-applicable-method-first" "iss050.htm")
+ ("clos-macro-compilation:minimal" "iss051.htm")
+ ("close-constructed-stream:argument-stream-only" "iss052.htm")
+ ("closed-stream-operations:allow-inquiry" "iss053.htm")
+ ("coercing-setf-name-to-function:all-function-names" "iss054.htm")
+ ("colon-number" "iss055.htm")
+ ("common-features:specify" "iss056.htm")
+ ("common-type:remove" "iss057.htm")
+ ("compile-argument-problems-again:fix" "iss058.htm")
+ ("compile-file-handling-of-top-level-forms:clarify" "iss059.htm")
+ ("compile-file-output-file-defaults:input-file" "iss060.htm")
+ ("compile-file-package" "iss061.htm")
+ ("compile-file-pathname-arguments:make-consistent" "iss062.htm")
+ ("compile-file-symbol-handling:new-require-consistency" "iss063.htm")
+ ("compiled-function-requirements:tighten" "iss064.htm")
+ ("compiler-diagnostics:use-handler" "iss065.htm")
+ ("compiler-let-confusion:eliminate" "iss066.htm")
+ ("compiler-verbosity:like-load" "iss067.htm")
+ ("compiler-warning-stream" "iss068.htm")
+ ("complex-atan-branch-cut:tweak" "iss069.htm")
+ ("complex-atanh-bogus-formula:tweak-more" "iss070.htm")
+ ("complex-rational-result:extend" "iss071.htm")
+ ("compute-applicable-methods:generic" "iss072.htm")
+ ("concatenate-sequence:signal-error" "iss073.htm")
+ ("condition-accessors-setfable:no" "iss074.htm")
+ ("condition-restarts:buggy" "iss075.htm")
+ ("condition-restarts:permit-association" "iss076.htm")
+ ("condition-slots:hidden" "iss077.htm")
+ ("cons-type-specifier:add" "iss078.htm")
+ ("constant-circular-compilation:yes" "iss079.htm")
+ ("constant-collapsing:generalize" "iss080.htm")
+ ("constant-compilable-types:specify" "iss081.htm")
+ ("constant-function-compilation:no" "iss082.htm")
+ ("constant-modification:disallow" "iss083.htm")
+ ("constantp-definition:intentional" "iss084.htm")
+ ("constantp-environment:add-arg" "iss085.htm")
+ ("contagion-on-numerical-comparisons:transitive" "iss086.htm")
+ ("copy-symbol-copy-plist:copy-list" "iss087.htm")
+ ("copy-symbol-print-name:equal" "iss088.htm")
+ ("data-io:add-support" "iss089.htm")
+ ("data-types-hierarchy-underspecified" "iss090.htm")
+ ("debugger-hook-vs-break:clarify" "iss091.htm")
+ ("declaration-scope:no-hoisting" "iss092.htm")
+ ("declare-array-type-element-references:restrictive" "iss093.htm")
+ ("declare-function-ambiguity:delete-ftype-abbreviation" "iss094.htm")
+ ("declare-macros:flush" "iss095.htm")
+ ("declare-type-free:lexical" "iss096.htm")
+ ("decls-and-doc" "iss097.htm")
+ ("decode-universal-time-daylight:like-encode" "iss098.htm")
+ ("defconstant-special:no" "iss099.htm")
+ ("defgeneric-declare:allow-multiple" "iss100.htm")
+ ("define-compiler-macro:x3j13-nov89" "iss101.htm")
+ ("define-condition-syntax:incompatibly-more-like-defclass+emphasize-read-only" "iss102.htm")
+ ("define-method-combination-behavior:clarify" "iss103.htm")
+ ("defining-macros-non-top-level:allow" "iss104.htm")
+ ("defmacro-block-scope:excludes-bindings" "iss105.htm")
+ ("defmacro-lambda-list:tighten-description" "iss106.htm")
+ ("defmethod-declaration-scope:corresponds-to-bindings" "iss107.htm")
+ ("defpackage:addition" "iss108.htm")
+ ("defstruct-constructor-key-mixture:allow-key" "iss109.htm")
+ ("defstruct-constructor-options:explicit" "iss110.htm")
+ ("defstruct-constructor-slot-variables:not-bound" "iss111.htm")
+ ("defstruct-copier-argument-type:restrict" "iss112.htm")
+ ("defstruct-copier:argument-type" "iss113.htm")
+ ("defstruct-default-value-evaluation:iff-needed" "iss114.htm")
+ ("defstruct-include-deftype:explicitly-undefined" "iss115.htm")
+ ("defstruct-print-function-again:x3j13-mar-93" "iss116.htm")
+ ("defstruct-print-function-inheritance:yes" "iss117.htm")
+ ("defstruct-redefinition:error" "iss118.htm")
+ ("defstruct-slots-constraints-name:duplicates-error" "iss119.htm")
+ ("defstruct-slots-constraints-number" "iss120.htm")
+ ("deftype-destructuring:yes" "iss121.htm")
+ ("deftype-key:allow" "iss122.htm")
+ ("defvar-documentation:unevaluated" "iss123.htm")
+ ("defvar-init-time:not-delayed" "iss124.htm")
+ ("defvar-initialization:conservative" "iss125.htm")
+ ("deprecation-position:limited" "iss126.htm")
+ ("describe-interactive:no" "iss127.htm")
+ ("describe-underspecified:describe-object" "iss128.htm")
+ ("destructive-operations:specify" "iss129.htm")
+ ("destructuring-bind:new-macro" "iss130.htm")
+ ("disassemble-side-effect:do-not-install" "iss131.htm")
+ ("displaced-array-predicate:add" "iss132.htm")
+ ("do-symbols-block-scope:entire-form" "iss133.htm")
+ ("do-symbols-duplicates" "iss134.htm")
+ ("documentation-function-bugs:fix" "iss135.htm")
+ ("documentation-function-tangled:require-argument" "iss136.htm")
+ ("dotimes-ignore:x3j13-mar91" "iss137.htm")
+ ("dotted-list-arguments:clarify" "iss138.htm")
+ ("dotted-macro-forms:allow" "iss139.htm")
+ ("dribble-technique" "iss140.htm")
+ ("dynamic-extent-function:extend" "iss141.htm")
+ ("dynamic-extent:new-declaration" "iss142.htm")
+ ("equal-structure:maybe-status-quo" "iss143.htm")
+ ("error-terminology-warning:might" "iss144.htm")
+ ("eval-other:self-evaluate" "iss145.htm")
+ ("eval-top-level:load-like-compile-file" "iss146.htm")
+ ("eval-when-non-top-level:generalize-eval-new-keywords" "iss147.htm")
+ ("eval-when-obsolete-keywords:x3j13-mar-1993" "iss148.htm")
+ ("evalhook-step-confusion:fix" "iss149.htm")
+ ("evalhook-step-confusion:x3j13-nov-89" "iss150.htm")
+ ("exit-extent-and-condition-system:like-dynamic-bindings" "iss151.htm")
+ ("exit-extent:minimal" "iss152.htm")
+ ("expt-ratio:p.211" "iss153.htm")
+ ("extensions-position:documentation" "iss154.htm")
+ ("external-format-for-every-file-connection:minimum" "iss155.htm")
+ ("extra-return-values:no" "iss156.htm")
+ ("file-open-error:signal-file-error" "iss157.htm")
+ ("fixnum-non-portable:tighten-definition" "iss158.htm")
+ ("flet-declarations" "iss159.htm")
+ ("flet-declarations:allow" "iss160.htm")
+ ("flet-implicit-block:yes" "iss161.htm")
+ ("float-underflow:add-variables" "iss162.htm")
+ ("floating-point-condition-names:x3j13-nov-89" "iss163.htm")
+ ("format-atsign-colon" "iss164.htm")
+ ("format-colon-uparrow-scope" "iss165.htm")
+ ("format-comma-interval" "iss166.htm")
+ ("format-e-exponent-sign:force-sign" "iss167.htm")
+ ("format-op-c" "iss168.htm")
+ ("format-pretty-print:yes" "iss169.htm")
+ ("format-string-arguments:specify" "iss170.htm")
+ ("function-call-evaluation-order:more-unspecified" "iss171.htm")
+ ("function-composition:jan89-x3j13" "iss172.htm")
+ ("function-definition:jan89-x3j13" "iss173.htm")
+ ("function-name:large" "iss174.htm")
+ ("function-type" "iss175.htm")
+ ("function-type-argument-type-semantics:restrictive" "iss176.htm")
+ ("function-type-key-name:specify-keyword" "iss177.htm")
+ ("function-type-rest-list-element:use-actual-argument-type" "iss178.htm")
+ ("function-type:x3j13-march-88" "iss179.htm")
+ ("generalize-pretty-printer:unify" "iss180.htm")
+ ("generic-flet-poorly-designed:delete" "iss181.htm")
+ ("gensym-name-stickiness:like-teflon" "iss182.htm")
+ ("gentemp-bad-idea:deprecate" "iss183.htm")
+ ("get-macro-character-readtable:nil-standard" "iss184.htm")
+ ("get-setf-method-environment:add-arg" "iss185.htm")
+ ("hash-table-access:x3j13-mar-89" "iss186.htm")
+ ("hash-table-key-modification:specify" "iss187.htm")
+ ("hash-table-package-generators:add-with-wrapper" "iss188.htm")
+ ("hash-table-rehash-size-integer" "iss189.htm")
+ ("hash-table-size:intended-entries" "iss190.htm")
+ ("hash-table-tests:add-equalp" "iss191.htm")
+ ("ieee-atan-branch-cut:split" "iss192.htm")
+ ("ignore-use-terminology:value-only" "iss193.htm")
+ ("import-setf-symbol-package" "iss194.htm")
+ ("in-package-functionality:mar89-x3j13" "iss195.htm")
+ ("in-syntax:minimal" "iss196.htm")
+ ("initialization-function-keyword-checking" "iss197.htm")
+ ("iso-compatibility:add-substrate" "iss198.htm")
+ ("jun90-trivial-issues:11" "iss199.htm")
+ ("jun90-trivial-issues:14" "iss200.htm")
+ ("jun90-trivial-issues:24" "iss201.htm")
+ ("jun90-trivial-issues:25" "iss202.htm")
+ ("jun90-trivial-issues:27" "iss203.htm")
+ ("jun90-trivial-issues:3" "iss204.htm")
+ ("jun90-trivial-issues:4" "iss205.htm")
+ ("jun90-trivial-issues:5" "iss206.htm")
+ ("jun90-trivial-issues:9" "iss207.htm")
+ ("keyword-argument-name-package:any" "iss208.htm")
+ ("last-n" "iss209.htm")
+ ("lcm-no-arguments:1" "iss210.htm")
+ ("lexical-construct-global-definition:undefined" "iss211.htm")
+ ("lisp-package-name:common-lisp" "iss212.htm")
+ ("lisp-symbol-redefinition-again:more-fixes" "iss213.htm")
+ ("lisp-symbol-redefinition:mar89-x3j13" "iss214.htm")
+ ("load-objects:make-load-form" "iss215.htm")
+ ("load-time-eval:r**2-new-special-form" "iss216.htm")
+ ("load-time-eval:r**3-new-special-form" "iss217.htm")
+ ("load-truename:new-pathname-variables" "iss218.htm")
+ ("locally-top-level:special-form" "iss219.htm")
+ ("loop-and-discrepancy:no-reiteration" "iss220.htm")
+ ("loop-for-as-on-typo:fix-typo" "iss221.htm")
+ ("loop-initform-environment:partial-interleaving-vague" "iss222.htm")
+ ("loop-miscellaneous-repairs:fix" "iss223.htm")
+ ("loop-named-block-nil:override" "iss224.htm")
+ ("loop-present-symbols-typo:flush-wrong-words" "iss225.htm")
+ ("loop-syntax-overhaul:repair" "iss226.htm")
+ ("macro-as-function:disallow" "iss227.htm")
+ ("macro-declarations:make-explicit" "iss228.htm")
+ ("macro-environment-extent:dynamic" "iss229.htm")
+ ("macro-function-environment" "iss230.htm")
+ ("macro-function-environment:yes" "iss231.htm")
+ ("macro-subforms-top-level-p:add-constraints" "iss232.htm")
+ ("macroexpand-hook-default:explicitly-vague" "iss233.htm")
+ ("macroexpand-hook-initial-value:implementation-dependent" "iss234.htm")
+ ("macroexpand-return-value:true" "iss235.htm")
+ ("make-load-form-confusion:rewrite" "iss236.htm")
+ ("make-load-form-saving-slots:no-initforms" "iss237.htm")
+ ("make-package-use-default:implementation-dependent" "iss238.htm")
+ ("map-into:add-function" "iss239.htm")
+ ("mapping-destructive-interaction:explicitly-vague" "iss240.htm")
+ ("metaclass-of-system-class:unspecified" "iss241.htm")
+ ("method-combination-arguments:clarify" "iss242.htm")
+ ("method-initform:forbid-call-next-method" "iss243.htm")
+ ("muffle-warning-condition-argument" "iss244.htm")
+ ("multiple-value-setq-order:like-setf-of-values" "iss245.htm")
+ ("multiple-values-limit-on-variables:undefined" "iss246.htm")
+ ("nintersection-destruction" "iss247.htm")
+ ("nintersection-destruction:revert" "iss248.htm")
+ ("not-and-null-return-value:x3j13-mar-93" "iss249.htm")
+ ("nth-value:add" "iss250.htm")
+ ("optimize-debug-info:new-quality" "iss251.htm")
+ ("package-clutter:reduce" "iss252.htm")
+ ("package-deletion:new-function" "iss253.htm")
+ ("package-function-consistency:more-permissive" "iss254.htm")
+ ("parse-error-stream:split-types" "iss255.htm")
+ ("pathname-component-case:keyword-argument" "iss256.htm")
+ ("pathname-component-value:specify" "iss257.htm")
+ ("pathname-host-parsing:recognize-logical-host-names" "iss258.htm")
+ ("pathname-logical:add" "iss259.htm")
+ ("pathname-print-read:sharpsign-p" "iss260.htm")
+ ("pathname-stream" "iss261.htm")
+ ("pathname-stream:files-or-synonym" "iss262.htm")
+ ("pathname-subdirectory-list:new-representation" "iss263.htm")
+ ("pathname-symbol" "iss264.htm")
+ ("pathname-syntax-error-time:explicitly-vague" "iss265.htm")
+ ("pathname-unspecific-component:new-token" "iss266.htm")
+ ("pathname-wild:new-functions" "iss267.htm")
+ ("peek-char-read-char-echo:first-read-char" "iss268.htm")
+ ("plist-duplicates:allow" "iss269.htm")
+ ("pretty-print-interface" "iss270.htm")
+ ("princ-readably:x3j13-dec-91" "iss271.htm")
+ ("print-case-behavior:clarify" "iss272.htm")
+ ("print-case-print-escape-interaction:vertical-bar-rule-no-upcase" "iss273.htm")
+ ("print-circle-shared:respect-print-circle" "iss274.htm")
+ ("print-circle-structure:user-functions-work" "iss275.htm")
+ ("print-readably-behavior:clarify" "iss276.htm")
+ ("printer-whitespace:just-one-space" "iss277.htm")
+ ("proclaim-etc-in-compile-file:new-macro" "iss278.htm")
+ ("push-evaluation-order:first-item" "iss279.htm")
+ ("push-evaluation-order:item-first" "iss280.htm")
+ ("pushnew-store-required:unspecified" "iss281.htm")
+ ("quote-semantics:no-copying" "iss282.htm")
+ ("range-of-count-keyword:nil-or-integer" "iss283.htm")
+ ("range-of-start-and-end-parameters:integer-and-integer-nil" "iss284.htm")
+ ("read-and-write-bytes:new-functions" "iss285.htm")
+ ("read-case-sensitivity:readtable-keywords" "iss286.htm")
+ ("read-modify-write-evaluation-order:delayed-access-stores" "iss287.htm")
+ ("read-suppress-confusing:generalize" "iss288.htm")
+ ("reader-error:new-type" "iss289.htm")
+ ("real-number-type:x3j13-mar-89" "iss290.htm")
+ ("recursive-deftype:explicitly-vague" "iss291.htm")
+ ("reduce-argument-extraction" "iss292.htm")
+ ("remf-destruction-unspecified:x3j13-mar-89" "iss293.htm")
+ ("require-pathname-defaults-again:x3j13-dec-91" "iss294.htm")
+ ("require-pathname-defaults-yet-again:restore-argument" "iss295.htm")
+ ("require-pathname-defaults:eliminate" "iss296.htm")
+ ("rest-list-allocation:may-share" "iss297.htm")
+ ("result-lists-shared:specify" "iss298.htm")
+ ("return-values-unspecified:specify" "iss299.htm")
+ ("room-default-argument:new-value" "iss300.htm")
+ ("self-modifying-code:forbid" "iss301.htm")
+ ("sequence-type-length:must-match" "iss302.htm")
+ ("setf-apply-expansion:ignore-expander" "iss303.htm")
+ ("setf-find-class:allow-nil" "iss304.htm")
+ ("setf-functions-again:minimal-changes" "iss305.htm")
+ ("setf-get-default:evaluated-but-ignored" "iss306.htm")
+ ("setf-macro-expansion:last" "iss307.htm")
+ ("setf-method-vs-setf-method:rename-old-terms" "iss308.htm")
+ ("setf-multiple-store-variables:allow" "iss309.htm")
+ ("setf-of-apply:only-aref-and-friends" "iss310.htm")
+ ("setf-of-values:add" "iss311.htm")
+ ("setf-sub-methods:delayed-access-stores" "iss312.htm")
+ ("shadow-already-present" "iss313.htm")
+ ("shadow-already-present:works" "iss314.htm")
+ ("sharp-comma-confusion:remove" "iss315.htm")
+ ("sharp-o-foobar:consequences-undefined" "iss316.htm")
+ ("sharp-star-delimiter:normal-delimiter" "iss317.htm")
+ ("sharpsign-plus-minus-package:keyword" "iss318.htm")
+ ("slot-missing-values:specify" "iss319.htm")
+ ("slot-value-metaclasses:less-minimal" "iss320.htm")
+ ("special-form-p-misnomer:rename" "iss321.htm")
+ ("special-type-shadowing:clarify" "iss322.htm")
+ ("standard-input-initial-binding:defined-contracts" "iss323.htm")
+ ("standard-repertoire-gratuitous:rename" "iss324.htm")
+ ("step-environment:current" "iss325.htm")
+ ("step-minimal:permit-progn" "iss326.htm")
+ ("stream-access:add-types-accessors" "iss327.htm")
+ ("stream-capabilities:interactive-stream-p" "iss328.htm")
+ ("string-coercion:make-consistent" "iss329.htm")
+ ("string-output-stream-bashing:undefined" "iss330.htm")
+ ("structure-read-print-syntax:keywords" "iss331.htm")
+ ("subseq-out-of-bounds" "iss332.htm")
+ ("subseq-out-of-bounds:is-an-error" "iss333.htm")
+ ("subsetting-position:none" "iss334.htm")
+ ("subtypep-environment:add-arg" "iss335.htm")
+ ("subtypep-too-vague:clarify-more" "iss336.htm")
+ ("sxhash-definition:similar-for-sxhash" "iss337.htm")
+ ("symbol-macrolet-declare:allow" "iss338.htm")
+ ("symbol-macrolet-semantics:special-form" "iss339.htm")
+ ("symbol-macrolet-type-declaration:no" "iss340.htm")
+ ("symbol-macros-and-proclaimed-specials:signals-an-error" "iss341.htm")
+ ("symbol-print-escape-behavior:clarify" "iss342.htm")
+ ("syntactic-environment-access:retracted-mar91" "iss343.htm")
+ ("tagbody-tag-expansion:no" "iss344.htm")
+ ("tailp-nil:t" "iss345.htm")
+ ("test-not-if-not:flush-all" "iss346.htm")
+ ("the-ambiguity:for-declaration" "iss347.htm")
+ ("the-values:return-number-received" "iss348.htm")
+ ("time-zone-non-integer:allow" "iss349.htm")
+ ("type-declaration-abbreviation:allow-all" "iss350.htm")
+ ("type-of-and-predefined-classes:type-of-handles-floats" "iss351.htm")
+ ("type-of-and-predefined-classes:unify-and-extend" "iss352.htm")
+ ("type-of-underconstrained:add-constraints" "iss353.htm")
+ ("type-specifier-abbreviation:x3j13-jun90-guess" "iss354.htm")
+ ("undefined-variables-and-functions:compromise" "iss355.htm")
+ ("uninitialized-elements:consequences-undefined" "iss356.htm")
+ ("unread-char-after-peek-char:dont-allow" "iss357.htm")
+ ("unsolicited-messages:not-to-system-user-streams" "iss358.htm")
+ ("variable-list-asymmetry:symmetrize" "iss359.htm")
+ ("with-added-methods:delete" "iss360.htm")
+ ("with-compilation-unit:new-macro" "iss361.htm")
+ ("with-open-file-does-not-exist:stream-is-nil" "iss362.htm")
+ ("with-open-file-setq:explicitly-vague" "iss363.htm")
+ ("with-open-file-stream-extent:dynamic-extent" "iss364.htm")
+ ("with-output-to-string-append-style:vector-push-extend" "iss365.htm")
+ ("with-standard-io-syntax-readtable:x3j13-mar-91" "iss366.htm"))))
+
+(defun common-lisp-issuex (issue-name)
+ (let ((symbol
+ (intern (downcase issue-name) common-lisp-hyperspec-issuex-symbols)))
+ (concat common-lisp-hyperspec-root "Issues/" (symbol-value symbol))))
+
+(provide 'hyperspec)
+
+;;; hyperspec.el ends here
Added: branches/bos/thirdparty/emacs/slime/metering.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/metering.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,1222 @@
+;;; -*- Mode: LISP; Package: monitor; Syntax: Common-lisp; Base: 10.; -*-
+;;; Tue Jan 25 18:32:28 1994 by Mark Kantrowitz <mkant at GLINDA.OZ.CS.CMU.EDU>
+
+;;; ****************************************************************
+;;; Metering System ************************************************
+;;; ****************************************************************
+;;;
+;;; The Metering System is a portable Common Lisp code profiling tool.
+;;; It gathers timing and consing statistics for specified functions
+;;; while a program is running.
+;;;
+;;; The Metering System is a combination of
+;;; o the Monitor package written by Chris McConnell
+;;; o the Profile package written by Skef Wholey and Rob MacLachlan
+;;; The two systems were merged and extended by Mark Kantrowitz.
+;;;
+;;; Address: Carnegie Mellon University
+;;; School of Computer Science
+;;; Pittsburgh, PA 15213
+;;;
+;;; This code is in the public domain and is distributed without warranty
+;;; of any kind.
+;;;
+;;; This copy is from SLIME, http://www.common-lisp.net/project/slime/
+;;;
+;;;
+
+;;; ********************************
+;;; Change Log *********************
+;;; ********************************
+;;;
+;;; 26-JUN-90 mk Merged functionality of Monitor and Profile packages.
+;;; 26-JUN-90 mk Now handles both inclusive and exclusive statistics
+;;; with respect to nested calls. (Allows it to subtract
+;;; total monitoring overhead for each function, not just
+;;; the time spent monitoring the function itself.)
+;;; 26-JUN-90 mk The table is now saved so that one may manipulate
+;;; the data (sorting it, etc.) even after the original
+;;; source of the data has been cleared.
+;;; 25-SEP-90 mk Added get-cons functions for Lucid 3.0, MACL 1.3.2
+;;; required-arguments functions for Lucid 3.0,
+;;; Franz Allegro CL, and MACL 1.3.2.
+;;; 25-JAN-91 mk Now uses fdefinition if available.
+;;; 25-JAN-91 mk Replaced (and :allegro (not :coral)) with :excl.
+;;; Much better solution for the fact that both call
+;;; themselves :allegro.
+;;; 5-JUL-91 mk Fixed warning to occur only when file is loaded
+;;; uncompiled.
+;;; 5-JUL-91 mk When many unmonitored functions, print out number
+;;; instead of whole list.
+;;; 24-MAR-92 mk Updated for CLtL2 compatibility. space measuring
+;;; doesn't work in MCL, but fixed so that timing
+;;; statistics do.
+;;; 26-MAR-92 mk Updated for Lispworks. Replaced :ccl with
+;;; (and :ccl (not :lispworks)).
+;;; 27-MAR-92 mk Added get-cons for Allegro-V4.0.
+;;; 01-JAN-93 mk v2.0 Support for MCL 2.0, CMU CL 16d, Allegro V3.1/4.0/4.1,
+;;; Lucid 4.0, ibcl
+;;; 25-JAN-94 mk v2.1 Patches for CLISP from Bruno Haible.
+;;; 01-APR-05 lgorrie Removed support for all Lisps except CLISP and OpenMCL.
+;;; Purely to cut down on stale code (e.g. #+cltl2) in this
+;;; version that is bundled with SLIME.
+;;;
+;;;
+
+;;; ********************************
+;;; To Do **************************
+;;; ********************************
+;;;
+;;; - Need get-cons for Allegro, AKCL.
+;;; - Speed up monitoring code. Replace use of hash tables with an embedded
+;;; offset in an array so that it will be faster than using gethash.
+;;; (i.e., svref/closure reference is usually faster than gethash).
+;;; - Beware of (get-internal-run-time) overflowing. Yikes!
+;;; - Check robustness with respect to profiled functions.
+;;; - Check logic of computing inclusive and exclusive time and consing.
+;;; Especially wrt incf/setf comment below. Should be incf, so we
+;;; sum recursive calls.
+;;; - Add option to record caller statistics -- this would list who
+;;; called which functions and how often.
+;;; - switches to turn timing/CONSING statistics collection on/off.
+
+
+;;; ********************************
+;;; Notes **************************
+;;; ********************************
+;;;
+;;; METERING has been tested (successfully) in the following lisps:
+;;; CMU Common Lisp (16d, Python Compiler 1.0 ) :new-compiler
+;;; CMU Common Lisp (M2.9 15-Aug-90, Compiler M1.8 15-Aug-90)
+;;; Macintosh Allegro Common Lisp (1.3.2)
+;;; Macintosh Common Lisp (2.0)
+;;; ExCL (Franz Allegro CL 3.1.12 [DEC 3100] 11/19/90) :allegro-v3.1
+;;; ExCL (Franz Allegro CL 4.0.1 [Sun4] 2/8/91) :allegro-v4.0
+;;; ExCL (Franz Allegro CL 4.1 [SPARC R1] 8/28/92 14:06) :allegro-v4.1
+;;; ExCL (Franz ACL 5.0.1 [Linux/X86] 6/29/99 16:11) :allegro-v5.0.1
+;;; Lucid CL (Version 2.1 6-DEC-87)
+;;; Lucid Common Lisp (3.0)
+;;; Lucid Common Lisp (4.0.1 HP-700 12-Aug-91)
+;;; AKCL (1.86, June 30, 1987 or later)
+;;; Ibuki Common Lisp (Version 2, release 01.027)
+;;; CLISP (January 1994)
+;;;
+;;; METERING needs to be tested in the following lisps:
+;;; Symbolics Common Lisp (8.0)
+;;; KCL (June 3, 1987 or later)
+;;; TI (Release 4.1 or later)
+;;; Golden Common Lisp (3.1 IBM-PC)
+;;; VAXLisp (2.0, 3.1)
+;;; Procyon Common Lisp
+
+
+;;; ****************************************************************
+;;; Documentation **************************************************
+;;; ****************************************************************
+;;;
+;;; This system runs in any valid Common Lisp. Four small
+;;; implementation-dependent changes can be made to improve performance
+;;; and prettiness. In the section labelled "Implementation Dependent
+;;; Changes" below, you should tailor the functions REQUIRED-ARGUMENTS,
+;;; GET-CONS, GET-TIME, and TIME-UNITS-PER-SECOND to your implementation
+;;; for the best results. If GET-CONS is not specified for your
+;;; implementation, no consing information will be reported. The other
+;;; functions will default to working forms, albeit inefficient, in
+;;; non-CMU implementations. If you tailor these functions for a particular
+;;; version of Common Lisp, we'd appreciate receiving the code.
+;;;
+
+;;; ****************************************************************
+;;; Usage Notes ****************************************************
+;;; ****************************************************************
+;;;
+;;; SUGGESTED USAGE:
+;;;
+;;; Start by monitoring big pieces of the program, then carefully choose
+;;; which functions close to, but not in, the inner loop are to be
+;;; monitored next. Don't monitor functions that are called by other
+;;; monitored functions: you will only confuse yourself.
+;;;
+;;; If the per-call time reported is less than 1/10th of a second, then
+;;; consider the clock resolution and profiling overhead before you believe
+;;; the time. It may be that you will need to run your program many times
+;;; in order to average out to a higher resolution.
+;;;
+;;; The easiest way to use this package is to load it and execute either
+;;; (mon:with-monitoring (names*) ()
+;;; your-forms*)
+;;; or
+;;; (mon:monitor-form your-form)
+;;; The former allows you to specify which functions will be monitored; the
+;;; latter monitors all functions in the current package. Both automatically
+;;; produce a table of statistics. Other variants can be constructed from
+;;; the monitoring primitives, which are described below, along with a
+;;; fuller description of these two macros.
+;;;
+;;; For best results, compile this file before using.
+;;;
+;;;
+;;; CLOCK RESOLUTION:
+;;;
+;;; Unless you are very lucky, the length of your machine's clock "tick" is
+;;; probably much longer than the time it takes a simple function to run.
+;;; For example, on the IBM RT, the clock resolution is 1/50th of a second.
+;;; This means that if a function is only called a few times, then only the
+;;; first couple of decimal places are really meaningful.
+;;;
+;;;
+;;; MONITORING OVERHEAD:
+;;;
+;;; The added monitoring code takes time to run every time that the monitored
+;;; function is called, which can disrupt the attempt to collect timing
+;;; information. In order to avoid serious inflation of the times for functions
+;;; that take little time to run, an estimate of the overhead due to monitoring
+;;; is subtracted from the times reported for each function.
+;;;
+;;; Although this correction works fairly well, it is not totally accurate,
+;;; resulting in times that become increasingly meaningless for functions
+;;; with short runtimes. For example, subtracting the estimated overhead
+;;; may result in negative times for some functions. This is only a concern
+;;; when the estimated profiling overhead is many times larger than
+;;; reported total CPU time.
+;;;
+;;; If you monitor functions that are called by monitored functions, in
+;;; :inclusive mode the monitoring overhead for the inner function is
+;;; subtracted from the CPU time for the outer function. [We do this by
+;;; counting for each function not only the number of calls to *this*
+;;; function, but also the number of monitored calls while it was running.]
+;;; In :exclusive mode this is not necessary, since we subtract the
+;;; monitoring time of inner functions, overhead & all.
+;;;
+;;; Otherwise, the estimated monitoring overhead is not represented in the
+;;; reported total CPU time. The sum of total CPU time and the estimated
+;;; monitoring overhead should be close to the total CPU time for the
+;;; entire monitoring run (as determined by TIME).
+;;;
+;;; A timing overhead factor is computed at load time. This will be incorrect
+;;; if the monitoring code is run in a different environment than this file
+;;; was loaded in. For example, saving a core image on a high performance
+;;; machine and running it on a low performance one will result in the use
+;;; of an erroneously small overhead factor.
+;;;
+;;;
+;;; If your times vary widely, possible causes are:
+;;; - Garbage collection. Try turning it off, then running your code.
+;;; Be warned that monitoring code will probably cons when it does
+;;; (get-internal-run-time).
+;;; - Swapping. If you have enough memory, execute your form once
+;;; before monitoring so that it will be swapped into memory. Otherwise,
+;;; get a bigger machine!
+;;; - Resolution of internal-time-units-per-second. If this value is
+;;; too low, then the timings become wild. You can try executing more
+;;; of whatever your test is, but that will only work if some of your
+;;; paths do not match the timer resolution.
+;;; internal-time-units-per-second is so coarse -- on a Symbolics it is
+;;; 977, in MACL it is 60.
+;;;
+;;;
+
+;;; ****************************************************************
+;;; Interface ******************************************************
+;;; ****************************************************************
+;;;
+;;; WITH-MONITORING (&rest functions) [Macro]
+;;; (&optional (nested :exclusive)
+;;; (threshold 0.01)
+;;; (key :percent-time))
+;;; &body body
+;;; The named functions will be set up for monitoring, the body forms executed,
+;;; a table of results printed, and the functions unmonitored. The nested,
+;;; threshold, and key arguments are passed to report-monitoring below.
+;;;
+;;; MONITOR-FORM form [Macro]
+;;; &optional (nested :exclusive)
+;;; (threshold 0.01)
+;;; (key :percent-time)
+;;; All functions in the current package are set up for monitoring while
+;;; the form is executed, and automatically unmonitored after a table of
+;;; results has been printed. The nested, threshold, and key arguments
+;;; are passed to report-monitoring below.
+;;;
+;;; *MONITORED-FUNCTIONS* [Variable]
+;;; This holds a list of all functions that are currently being monitored.
+;;;
+;;; MONITOR &rest names [Macro]
+;;; The named functions will be set up for monitoring by augmenting
+;;; their function definitions with code that gathers statistical information
+;;; about code performance. As with the TRACE macro, the function names are
+;;; not evaluated. Calls the function MON::MONITORING-ENCAPSULATE on each
+;;; function name. If no names are specified, returns a list of all
+;;; monitored functions.
+;;;
+;;; If name is not a symbol, it is evaled to return the appropriate
+;;; closure. This allows you to monitor closures stored anywhere like
+;;; in a variable, array or structure. Most other monitoring packages
+;;; can't handle this.
+;;;
+;;; MONITOR-ALL &optional (package *package*) [Function]
+;;; Monitors all functions in the specified package, which defaults to
+;;; the current package.
+;;;
+;;; UNMONITOR &rest names [Macro]
+;;; Removes monitoring code from the named functions. If no names are
+;;; specified, all currently monitored functions are unmonitored.
+;;;
+;;; RESET-MONITORING-INFO name [Function]
+;;; Resets the monitoring statistics for the specified function.
+;;;
+;;; RESET-ALL-MONITORING [Function]
+;;; Resets the monitoring statistics for all monitored functions.
+;;;
+;;; MONITORED name [Function]
+;;; Predicate to test whether a function is monitored.
+;;;
+;;; REPORT-MONITORING &optional names [Function]
+;;; (nested :exclusive)
+;;; (threshold 0.01)
+;;; (key :percent-time)
+;;; Creates a table of monitoring information for the specified list
+;;; of names, and displays the table using display-monitoring-results.
+;;; If names is :all or nil, uses all currently monitored functions.
+;;; Takes the following arguments:
+;;; - NESTED specifies whether nested calls of monitored functions
+;;; are included in the times for monitored functions.
+;;; o If :inclusive, the per-function information is for the entire
+;;; duration of the monitored function, including any calls to
+;;; other monitored functions. If functions A and B are monitored,
+;;; and A calls B, then the accumulated time and consing for A will
+;;; include the time and consing of B. Note: if a function calls
+;;; itself recursively, the time spent in the inner call(s) may
+;;; be counted several times.
+;;; o If :exclusive, the information excludes time attributed to
+;;; calls to other monitored functions. This is the default.
+;;; - THRESHOLD specifies that only functions which have been executed
+;;; more than threshold percent of the time will be reported. Defaults
+;;; to 1%. If a threshold of 0 is specified, all functions are listed,
+;;; even those with 0 or negative running times (see note on overhead).
+;;; - KEY specifies that the table be sorted by one of the following
+;;; sort keys:
+;;; :function alphabetically by function name
+;;; :percent-time by percent of total execution time
+;;; :percent-cons by percent of total consing
+;;; :calls by number of times the function was called
+;;; :time-per-call by average execution time per function
+;;; :cons-per-call by average consing per function
+;;; :time same as :percent-time
+;;; :cons same as :percent-cons
+;;;
+;;; REPORT &key (names :all) [Function]
+;;; (nested :exclusive)
+;;; (threshold 0.01)
+;;; (sort-key :percent-time)
+;;; (ignore-no-calls nil)
+;;;
+;;; Same as REPORT-MONITORING but we use a nicer keyword interface.
+;;;
+;;; DISPLAY-MONITORING-RESULTS &optional (threshold 0.01) [Function]
+;;; (key :percent-time)
+;;; Prints a table showing for each named function:
+;;; - the total CPU time used in that function for all calls
+;;; - the total number of bytes consed in that function for all calls
+;;; - the total number of calls
+;;; - the average amount of CPU time per call
+;;; - the average amount of consing per call
+;;; - the percent of total execution time spent executing that function
+;;; - the percent of total consing spent consing in that function
+;;; Summary totals of the CPU time, consing, and calls columns are printed.
+;;; An estimate of the monitoring overhead is also printed. May be run
+;;; even after unmonitoring all the functions, to play with the data.
+;;;
+;;; SAMPLE TABLE:
+#|
+ Cons
+ % % Per Total Total
+Function Time Cons Calls Sec/Call Call Time Cons
+----------------------------------------------------------------------
+FIND-ROLE: 0.58 0.00 136 0.003521 0 0.478863 0
+GROUP-ROLE: 0.35 0.00 365 0.000802 0 0.292760 0
+GROUP-PROJECTOR: 0.05 0.00 102 0.000408 0 0.041648 0
+FEATURE-P: 0.02 0.00 570 0.000028 0 0.015680 0
+----------------------------------------------------------------------
+TOTAL: 1173 0.828950 0
+Estimated total monitoring overhead: 0.88 seconds
+|#
+
+;;; ****************************************************************
+;;; METERING *******************************************************
+;;; ****************************************************************
+
+;;; ********************************
+;;; Warn people using the wrong Lisp
+;;; ********************************
+
+#-(or clisp openmcl)
+(warn "metering.lisp does not support your Lisp implementation!")
+
+;;; ********************************
+;;; Packages ***********************
+;;; ********************************
+
+;;; For CLtL2 compatible lisps
+
+(defpackage "MONITOR" (:nicknames "MON") (:use "COMMON-LISP")
+ (:export "*MONITORED-FUNCTIONS*"
+ "MONITOR" "MONITOR-ALL" "UNMONITOR" "MONITOR-FORM"
+ "WITH-MONITORING"
+ "RESET-MONITORING-INFO" "RESET-ALL-MONITORING"
+ "MONITORED"
+ "REPORT-MONITORING"
+ "DISPLAY-MONITORING-RESULTS"
+ "MONITORING-ENCAPSULATE" "MONITORING-UNENCAPSULATE"
+ "REPORT"))
+(in-package "MONITOR")
+
+;;; Warn user if they're loading the source instead of compiling it first.
+(eval-when (eval)
+ (warn "This file should be compiled before loading for best results."))
+
+;;; ********************************
+;;; Version ************************
+;;; ********************************
+
+(defparameter *metering-version* "v2.1 25-JAN-94"
+ "Current version number/date for Metering.")
+
+
+;;; ****************************************************************
+;;; Implementation Dependent Definitions ***************************
+;;; ****************************************************************
+
+;;; ********************************
+;;; Timing Functions ***************
+;;; ********************************
+;;; The get-time function is called to find the total number of ticks since
+;;; the beginning of time. time-units-per-second allows us to convert units
+;;; to seconds.
+
+#-(or clisp openmcl)
+(eval-when (compile eval)
+ (warn
+ "You may want to supply implementation-specific get-time functions."))
+
+(defconstant time-units-per-second internal-time-units-per-second)
+
+(defmacro get-time ()
+ `(the time-type (get-internal-run-time)))
+
+;;; NOTE: In Macintosh Common Lisp, CCL::GCTIME returns the number of
+;;; milliseconds spent during GC. We could subtract this from
+;;; the value returned by get-internal-run-time to eliminate
+;;; the effect of GC on the timing values, but we prefer to let
+;;; the user run without GC on. If the application is so big that
+;;; it requires GC to complete, then the GC times are part of the
+;;; cost of doing business, and will average out in the long run.
+;;; If it seems really important to a user that GC times not be
+;;; counted, then uncomment the following three lines and read-time
+;;; conditionalize the definition of get-time above with #-:openmcl.
+;#+openmcl
+;(defmacro get-time ()
+; `(the time-type (- (get-internal-run-time) (ccl:gctime))))
+
+;;; ********************************
+;;; Consing Functions **************
+;;; ********************************
+;;; The get-cons macro is called to find the total number of bytes
+;;; consed since the beginning of time.
+
+#+clisp
+(defun get-cons ()
+ (multiple-value-bind (real1 real2 run1 run2 gc1 gc2 space1 space2 gccount)
+ (sys::%%time)
+ (declare (ignore real1 real2 run1 run2 gc1 gc2 gccount))
+ (dpb space1 (byte 24 24) space2)))
+
+;;; Macintosh Common Lisp 2.0
+;;; Note that this includes bytes that were allocated during GC.
+;;; We could subtract this out by advising GC like we did under
+;;; MCL 1.3.2, but I'd rather users ran without GC. If they can't
+;;; run without GC, then the bytes consed during GC are a cost of
+;;; running their program. Metering the code a few times will
+;;; avoid the consing values being too lopsided. If a user really really
+;;; wants to subtract out the consing during GC, replace the following
+;;; two lines with the commented out code.
+#+openmcl
+(defmacro get-cons () `(the consing-type (ccl::total-bytes-allocated)))
+;; #+openmcl
+;; (progn
+;; (in-package :ccl)
+;; (defvar *bytes-consed-chkpt* 0)
+;; (defun reset-consing () (setq *bytes-consed-chkpt* 0))
+;; (let ((old-gc (symbol-function 'gc))
+;; (ccl:*warn-if-redefine-kernel* nil))
+;; (setf (symbol-function 'gc)
+;; #'(lambda ()
+;; (let ((old-consing (total-bytes-consed)))
+;; (prog1
+;; (funcall old-gc)
+;; (incf *bytes-consed-chkpt*
+;; (- old-consing (total-bytes-consed))))))))
+;; (defun total-bytes-consed ()
+;; "Returns number of conses (8 bytes each)"
+;; (ccl::total-bytes-allocated))
+;; (in-package "MONITOR")
+;; (defun get-cons ()
+;; (the consing-type (+ (ccl::total-bytes-consed) ccl::*bytes-consed-chkpt*))))
+
+
+#-(or clisp openmcl)
+(progn
+ (eval-when (compile eval)
+ (warn "No consing will be reported unless a get-cons function is ~
+ defined."))
+
+ (defmacro get-cons () '(the consing-type 0)))
+
+;; actually, neither `get-cons' nor `get-time' are used as is,
+;; but only in the following macro `with-time/cons'
+#-:clisp
+(defmacro with-time/cons ((delta-time delta-cons) form &body post-process)
+ (let ((start-cons (gensym "START-CONS-"))
+ (start-time (gensym "START-TIME-")))
+ `(let ((,start-time (get-time)) (,start-cons (get-cons)))
+ (declare (type time-type ,start-time)
+ (type consing-type ,start-cons))
+ (multiple-value-prog1 ,form
+ (let ((,delta-time (- (get-time) ,start-time))
+ (,delta-cons (- (get-cons) ,start-cons)))
+ , at post-process)))))
+
+#+clisp
+(progn
+ (defmacro delta4 (nv1 nv2 ov1 ov2 by)
+ `(- (dpb (- ,nv1 ,ov1) (byte ,by ,by) ,nv2) ,ov2))
+
+ (let ((del (find-symbol "DELTA4" "SYS")))
+ (when del (setf (fdefinition 'delta4) (fdefinition del))))
+
+ (if (< internal-time-units-per-second 1000000)
+ ;; TIME_1: AMIGA, OS/2, UNIX_TIMES
+ (defmacro delta4-time (new-time1 new-time2 old-time1 old-time2)
+ `(delta4 ,new-time1 ,new-time2 ,old-time1 ,old-time2 16))
+ ;; TIME_2: other UNIX, WIN32
+ (defmacro delta4-time (new-time1 new-time2 old-time1 old-time2)
+ `(+ (* (- ,new-time1 ,old-time1) internal-time-units-per-second)
+ (- ,new-time2 ,old-time2))))
+
+ (defmacro delta4-cons (new-cons1 new-cons2 old-cons1 old-cons2)
+ `(delta4 ,new-cons1 ,new-cons2 ,old-cons1 ,old-cons2 24))
+
+ ;; avoid consing: when the application conses a lot,
+ ;; get-cons may return a bignum, so we really should not use it.
+ (defmacro with-time/cons ((delta-time delta-cons) form &body post-process)
+ (let ((beg-cons1 (gensym "BEG-CONS1-")) (end-cons1 (gensym "END-CONS1-"))
+ (beg-cons2 (gensym "BEG-CONS2-")) (end-cons2 (gensym "END-CONS2-"))
+ (beg-time1 (gensym "BEG-TIME1-")) (end-time1 (gensym "END-TIME1-"))
+ (beg-time2 (gensym "BEG-TIME2-")) (end-time2 (gensym "END-TIME2-"))
+ (re1 (gensym)) (re2 (gensym)) (gc1 (gensym)) (gc2 (gensym)))
+ `(multiple-value-bind (,re1 ,re2 ,beg-time1 ,beg-time2
+ ,gc1 ,gc2 ,beg-cons1 ,beg-cons2) (sys::%%time)
+ (declare (ignore ,re1 ,re2 ,gc1 ,gc2))
+ (multiple-value-prog1 ,form
+ (multiple-value-bind (,re1 ,re2 ,end-time1 ,end-time2
+ ,gc1 ,gc2 ,end-cons1 ,end-cons2) (sys::%%time)
+ (declare (ignore ,re1 ,re2 ,gc1 ,gc2))
+ (let ((,delta-time (delta4-time ,end-time1 ,end-time2
+ ,beg-time1 ,beg-time2))
+ (,delta-cons (delta4-cons ,end-cons1 ,end-cons2
+ ,beg-cons1 ,beg-cons2)))
+ , at post-process)))))))
+
+;;; ********************************
+;;; Required Arguments *************
+;;; ********************************
+;;;
+;;; Required (Fixed) vs Optional Args
+;;;
+;;; To avoid unnecessary consing in the "encapsulation" code, we find out the
+;;; number of required arguments, and use &rest to capture only non-required
+;;; arguments. The function Required-Arguments returns two values: the first
+;;; is the number of required arguments, and the second is T iff there are any
+;;; non-required arguments (e.g. &optional, &rest, &key).
+
+;;; Lucid, Allegro, and Macintosh Common Lisp
+#+openmcl
+(defun required-arguments (name)
+ (let* ((function (symbol-function name))
+ (args (ccl:arglist function))
+ (pos (position-if #'(lambda (x)
+ (and (symbolp x)
+ (let ((name (symbol-name x)))
+ (and (>= (length name) 1)
+ (char= (schar name 0)
+ #\&)))))
+ args)))
+ (if pos
+ (values pos t)
+ (values (length args) nil))))
+
+#+clisp
+(defun required-arguments (name)
+ (multiple-value-bind (name req-num opt-num rest-p key-p keywords allow-p)
+ (sys::function-signature name t)
+ (if name ; no error
+ (values req-num (or (/= 0 opt-num) rest-p key-p keywords allow-p))
+ (values 0 t))))
+
+#-(or clisp openmcl)
+(progn
+ (eval-when (compile eval)
+ (warn
+ "You may want to add an implementation-specific Required-Arguments function."))
+ (eval-when (load eval)
+ (defun required-arguments (name)
+ (declare (ignore name))
+ (values 0 t))))
+
+#|
+;;;Examples
+(defun square (x) (* x x))
+(defun square2 (x &optional y) (* x x y))
+(defun test (x y &optional (z 3)) 3)
+(defun test2 (x y &optional (z 3) &rest fred) 3)
+
+(required-arguments 'square) => 1 nil
+(required-arguments 'square2) => 1 t
+(required-arguments 'test) => 2 t
+(required-arguments 'test2) => 2 t
+|#
+
+
+;;; ****************************************************************
+;;; Main METERING Code *********************************************
+;;; ****************************************************************
+
+;;; ********************************
+;;; Global Variables ***************
+;;; ********************************
+(defvar *MONITOR-TIME-OVERHEAD* nil
+ "The amount of time an empty monitored function costs.")
+(defvar *MONITOR-CONS-OVERHEAD* nil
+ "The amount of cons an empty monitored function costs.")
+
+(defvar *TOTAL-TIME* 0
+ "Total amount of time monitored so far.")
+(defvar *TOTAL-CONS* 0
+ "Total amount of consing monitored so far.")
+(defvar *TOTAL-CALLS* 0
+ "Total number of calls monitored so far.")
+(proclaim '(type time-type *total-time*))
+(proclaim '(type consing-type *total-cons*))
+(proclaim '(fixnum *total-calls*))
+
+;;; ********************************
+;;; Accessor Functions *************
+;;; ********************************
+;;; Perhaps the SYMBOLP should be FBOUNDP? I.e., what about variables
+;;; containing closures.
+(defmacro PLACE-FUNCTION (function-place)
+ "Return the function found at FUNCTION-PLACE. Evals FUNCTION-PLACE
+if it isn't a symbol, to allow monitoring of closures located in
+variables/arrays/structures."
+ ;; Note that (fboundp 'fdefinition) returns T even if fdefinition
+ ;; is a macro, which is what we want.
+ (if (fboundp 'fdefinition)
+ `(if (fboundp ,function-place)
+ (fdefinition ,function-place)
+ (eval ,function-place))
+ `(if (symbolp ,function-place)
+ (symbol-function ,function-place)
+ (eval ,function-place))))
+
+(defsetf PLACE-FUNCTION (function-place) (function)
+ "Set the function in FUNCTION-PLACE to FUNCTION."
+ (if (fboundp 'fdefinition)
+ ;; If we're conforming to CLtL2, use fdefinition here.
+ `(if (fboundp ,function-place)
+ (setf (fdefinition ,function-place) ,function)
+ (eval '(setf ,function-place ',function)))
+ `(if (symbolp ,function-place)
+ (setf (symbol-function ,function-place) ,function)
+ (eval '(setf ,function-place ',function)))))
+
+#|
+;;; before using fdefinition
+(defun PLACE-FUNCTION (function-place)
+ "Return the function found at FUNCTION-PLACE. Evals FUNCTION-PLACE
+if it isn't a symbol, to allow monitoring of closures located in
+variables/arrays/structures."
+ (if (symbolp function-place)
+ (symbol-function function-place)
+ (eval function-place)))
+
+(defsetf PLACE-FUNCTION (function-place) (function)
+ "Set the function in FUNCTION-PLACE to FUNCTION."
+ `(if (symbolp ,function-place)
+ (setf (symbol-function ,function-place) ,function)
+ (eval '(setf ,function-place ',function))))
+|#
+
+(defun PLACE-FBOUNDP (function-place)
+ "Test to see if FUNCTION-PLACE is a function."
+ ;; probably should be
+ #|(or (and (symbolp function-place)(fboundp function-place))
+ (functionp (place-function function-place)))|#
+ (if (symbolp function-place)
+ (fboundp function-place)
+ (functionp (place-function function-place))))
+
+(defun PLACE-MACROP (function-place)
+ "Test to see if FUNCTION-PLACE is a macro."
+ (when (symbolp function-place)
+ (macro-function function-place)))
+
+;;; ********************************
+;;; Measurement Tables *************
+;;; ********************************
+(defvar *monitored-functions* nil
+ "List of monitored symbols.")
+
+;;; We associate a METERING-FUNCTIONS structure with each monitored function
+;;; name or other closure. This holds the functions that we call to manipulate
+;;; the closure which implements the encapsulation.
+;;;
+(defstruct metering-functions
+ (name nil)
+ (old-definition nil :type function)
+ (new-definition nil :type function)
+ (read-metering nil :type function)
+ (reset-metering nil :type function))
+
+;;; In general using hash tables in time-critical programs is a bad idea,
+;;; because when one has to grow the table and rehash everything, the
+;;; timing becomes grossly inaccurate. In this case it is not an issue
+;;; because all inserting of entries in the hash table occurs before the
+;;; timing commences. The only circumstance in which this could be a
+;;; problem is if the lisp rehashes on the next reference to the table,
+;;; instead of when the entry which forces a rehash was inserted.
+;;;
+;;; Note that a similar kind of problem can occur with GC, which is why
+;;; one should turn off GC when monitoring code.
+;;;
+(defvar *monitor* (make-hash-table :test #'equal)
+ "Hash table in which METERING-FUNCTIONS structures are stored.")
+(defun get-monitor-info (name)
+ (gethash name *monitor*))
+(defsetf get-monitor-info (name) (info)
+ `(setf (gethash ,name *monitor*) ,info))
+
+(defun MONITORED (function-place)
+ "Test to see if a FUNCTION-PLACE is monitored."
+ (and (place-fboundp function-place) ; this line necessary?
+ (get-monitor-info function-place)))
+
+(defun reset-monitoring-info (name)
+ "Reset the monitoring info for the specified function."
+ (let ((finfo (get-monitor-info name)))
+ (when finfo
+ (funcall (metering-functions-reset-metering finfo)))))
+(defun reset-all-monitoring ()
+ "Reset monitoring info for all functions."
+ (setq *total-time* 0
+ *total-cons* 0
+ *total-calls* 0)
+ (dolist (symbol *monitored-functions*)
+ (when (monitored symbol)
+ (reset-monitoring-info symbol))))
+
+(defun monitor-info-values (name &optional (nested :exclusive) warn)
+ "Returns monitoring information values for the named function,
+adjusted for overhead."
+ (let ((finfo (get-monitor-info name)))
+ (if finfo
+ (multiple-value-bind (inclusive-time inclusive-cons
+ exclusive-time exclusive-cons
+ calls nested-calls)
+ (funcall (metering-functions-read-metering finfo))
+ (unless (or (null warn)
+ (eq (place-function name)
+ (metering-functions-new-definition finfo)))
+ (warn "Funtion ~S has been redefined, so times may be inaccurate.~@
+ MONITOR it again to record calls to the new definition."
+ name))
+ (case nested
+ (:exclusive (values calls
+ nested-calls
+ (- exclusive-time
+ (* calls *monitor-time-overhead*))
+ (- exclusive-cons
+ (* calls *monitor-cons-overhead*))))
+ ;; In :inclusive mode, subtract overhead for all the
+ ;; called functions as well. Nested-calls includes the
+ ;; calls of the function as well. [Necessary 'cause of
+ ;; functions which call themselves recursively.]
+ (:inclusive (values calls
+ nested-calls
+ (- inclusive-time
+ (* nested-calls ;(+ calls)
+ *monitor-time-overhead*))
+ (- inclusive-cons
+ (* nested-calls ;(+ calls)
+ *monitor-cons-overhead*))))))
+ (values 0 0 0 0))))
+
+;;; ********************************
+;;; Encapsulate ********************
+;;; ********************************
+(eval-when (compile load eval)
+;; Returns a lambda expression for a function that, when called with the
+;; function name, will set up that function for metering.
+;;
+;; A function is monitored by replacing its definition with a closure
+;; created by the following function. The closure records the monitoring
+;; data, and updates the data with each call of the function.
+;;
+;; Other closures are used to read and reset the data.
+(defun make-monitoring-encapsulation (min-args optionals-p)
+ (let (required-args)
+ (dotimes (i min-args) (push (gensym) required-args))
+ `(lambda (name)
+ (let ((inclusive-time 0)
+ (inclusive-cons 0)
+ (exclusive-time 0)
+ (exclusive-cons 0)
+ (calls 0)
+ (nested-calls 0)
+ (old-definition (place-function name)))
+ (declare (type time-type inclusive-time)
+ (type time-type exclusive-time)
+ (type consing-type inclusive-cons)
+ (type consing-type exclusive-cons)
+ (fixnum calls)
+ (fixnum nested-calls))
+ (pushnew name *monitored-functions*)
+
+ (setf (place-function name)
+ #'(lambda (, at required-args
+ ,@(when optionals-p
+ `(&rest optional-args)))
+ (let ((prev-total-time *total-time*)
+ (prev-total-cons *total-cons*)
+ (prev-total-calls *total-calls*)
+ ;; (old-time inclusive-time)
+ ;; (old-cons inclusive-cons)
+ ;; (old-nested-calls nested-calls)
+ )
+ (declare (type time-type prev-total-time)
+ (type consing-type prev-total-cons)
+ (fixnum prev-total-calls))
+ (with-time/cons (delta-time delta-cons)
+ ;; form
+ ,(if optionals-p
+ `(apply old-definition
+ , at required-args optional-args)
+ `(funcall old-definition , at required-args))
+ ;; post-processing:
+ ;; Calls
+ (incf calls)
+ (incf *total-calls*)
+ ;; nested-calls includes this call
+ (incf nested-calls (the fixnum
+ (- *total-calls*
+ prev-total-calls)))
+ ;; (setf nested-calls (+ old-nested-calls
+ ;; (- *total-calls*
+ ;; prev-total-calls)))
+ ;; Time
+ ;; Problem with inclusive time is that it
+ ;; currently doesn't add values from recursive
+ ;; calls to the same function. Change the
+ ;; setf to an incf to fix this?
+ (incf inclusive-time (the time-type delta-time))
+ ;; (setf inclusive-time (+ delta-time old-time))
+ (incf exclusive-time (the time-type
+ (+ delta-time
+ (- prev-total-time
+ *total-time*))))
+ (setf *total-time* (the time-type
+ (+ delta-time
+ prev-total-time)))
+ ;; Consing
+ (incf inclusive-cons (the consing-type delta-cons))
+ ;; (setf inclusive-cons (+ delta-cons old-cons))
+ (incf exclusive-cons (the consing-type
+ (+ delta-cons
+ (- prev-total-cons
+ *total-cons*))))
+ (setf *total-cons*
+ (the consing-type
+ (+ delta-cons prev-total-cons)))))))
+ (setf (get-monitor-info name)
+ (make-metering-functions
+ :name name
+ :old-definition old-definition
+ :new-definition (place-function name)
+ :read-metering #'(lambda ()
+ (values inclusive-time
+ inclusive-cons
+ exclusive-time
+ exclusive-cons
+ calls
+ nested-calls))
+ :reset-metering #'(lambda ()
+ (setq inclusive-time 0
+ inclusive-cons 0
+ exclusive-time 0
+ exclusive-cons 0
+ calls 0
+ nested-calls 0)
+ t)))))))
+);; End of EVAL-WHEN
+
+;;; For efficiency reasons, we precompute the encapsulation functions
+;;; for a variety of combinations of argument structures
+;;; (min-args . optional-p). These are stored in the following hash table
+;;; along with any new ones we encounter. Since we're now precomputing
+;;; closure functions for common argument signatures, this eliminates
+;;; the former need to call COMPILE for each monitored function.
+(eval-when (compile eval)
+ (defconstant precomputed-encapsulations 8))
+
+(defvar *existing-encapsulations* (make-hash-table :test #'equal))
+(defun find-encapsulation (min-args optionals-p)
+ (or (gethash (cons min-args optionals-p) *existing-encapsulations*)
+ (setf (gethash (cons min-args optionals-p) *existing-encapsulations*)
+ (compile nil
+ (make-monitoring-encapsulation min-args optionals-p)))))
+
+(macrolet ((frob ()
+ (let ((res ()))
+ (dotimes (i precomputed-encapsulations)
+ (push `(setf (gethash '(,i . nil) *existing-encapsulations*)
+ #',(make-monitoring-encapsulation i nil))
+ res)
+ (push `(setf (gethash '(,i . t) *existing-encapsulations*)
+ #',(make-monitoring-encapsulation i t))
+ res))
+ `(progn , at res))))
+ (frob))
+
+(defun monitoring-encapsulate (name &optional warn)
+ "Monitor the function Name. If already monitored, unmonitor first."
+ ;; Saves the current definition of name and inserts a new function which
+ ;; returns the result of evaluating body.
+ (cond ((not (place-fboundp name)) ; not a function
+ (when warn
+ (warn "Ignoring undefined function ~S." name)))
+ ((place-macrop name) ; a macro
+ (when warn
+ (warn "Ignoring macro ~S." name)))
+ (t ; tis a function
+ (when (get-monitor-info name) ; monitored
+ (when warn
+ (warn "~S already monitored, so unmonitoring it first." name))
+ (monitoring-unencapsulate name))
+ (multiple-value-bind (min-args optionals-p)
+ (required-arguments name)
+ (funcall (find-encapsulation min-args optionals-p) name)))))
+
+(defun monitoring-unencapsulate (name &optional warn)
+ "Removes monitoring encapsulation code from around Name."
+ (let ((finfo (get-monitor-info name)))
+ (when finfo ; monitored
+ (remprop name 'metering-functions)
+ (setq *monitored-functions*
+ (remove name *monitored-functions* :test #'equal))
+ (if (eq (place-function name)
+ (metering-functions-new-definition finfo))
+ (setf (place-function name)
+ (metering-functions-old-definition finfo))
+ (when warn
+ (warn "Preserving current definition of redefined function ~S."
+ name))))))
+
+;;; ********************************
+;;; Main Monitoring Functions ******
+;;; ********************************
+(defmacro MONITOR (&rest names)
+ "Monitor the named functions. As in TRACE, the names are not evaluated.
+ If a function is already monitored, then unmonitor and remonitor (useful
+ to notice function redefinition). If a name is undefined, give a warning
+ and ignore it. See also unmonitor, report-monitoring,
+ display-monitoring-results and reset-time."
+ `(progn
+ ,@(mapcar #'(lambda (name) `(monitoring-encapsulate ',name)) names)
+ *monitored-functions*))
+
+(defmacro UNMONITOR (&rest names)
+ "Remove the monitoring on the named functions.
+ Names defaults to the list of all currently monitored functions."
+ `(dolist (name ,(if names `',names '*monitored-functions*) (values))
+ (monitoring-unencapsulate name)))
+
+(defun MONITOR-ALL (&optional (package *package*))
+ "Monitor all functions in the specified package."
+ (let ((package (if (packagep package)
+ package
+ (find-package package))))
+ (do-symbols (symbol package)
+ (when (eq (symbol-package symbol) package)
+ (monitoring-encapsulate symbol)))))
+
+(defmacro MONITOR-FORM (form
+ &optional (nested :exclusive) (threshold 0.01)
+ (key :percent-time))
+ "Monitor the execution of all functions in the current package
+during the execution of FORM. All functions that are executed above
+THRESHOLD % will be reported."
+ `(unwind-protect
+ (progn
+ (monitor-all)
+ (reset-all-monitoring)
+ (prog1
+ (time ,form)
+ (report-monitoring :all ,nested ,threshold ,key :ignore-no-calls)))
+ (unmonitor)))
+
+(defmacro WITH-MONITORING ((&rest functions)
+ (&optional (nested :exclusive)
+ (threshold 0.01)
+ (key :percent-time))
+ &body body)
+ "Monitor the specified functions during the execution of the body."
+ `(unwind-protect
+ (progn
+ (dolist (fun ',functions)
+ (monitoring-encapsulate fun))
+ (reset-all-monitoring)
+ , at body
+ (report-monitoring :all ,nested ,threshold ,key))
+ (unmonitor)))
+
+;;; ********************************
+;;; Overhead Calculations **********
+;;; ********************************
+(defconstant overhead-iterations 5000
+ "Number of iterations over which the timing overhead is averaged.")
+
+;;; Perhaps this should return something to frustrate clever compilers.
+(defun STUB-FUNCTION (x)
+ (declare (ignore x))
+ nil)
+(proclaim '(notinline stub-function))
+
+(defun SET-MONITOR-OVERHEAD ()
+ "Determines the average overhead of monitoring by monitoring the execution
+of an empty function many times."
+ (setq *monitor-time-overhead* 0
+ *monitor-cons-overhead* 0)
+ (stub-function nil)
+ (monitor stub-function)
+ (reset-all-monitoring)
+ (let ((overhead-function (symbol-function 'stub-function)))
+ (dotimes (x overhead-iterations)
+ (funcall overhead-function overhead-function)))
+; (dotimes (x overhead-iterations)
+; (stub-function nil))
+ (let ((fiter (float overhead-iterations)))
+ (multiple-value-bind (calls nested-calls time cons)
+ (monitor-info-values 'stub-function)
+ (declare (ignore calls nested-calls))
+ (setq *monitor-time-overhead* (/ time fiter)
+ *monitor-cons-overhead* (/ cons fiter))))
+ (unmonitor stub-function))
+(set-monitor-overhead)
+
+;;; ********************************
+;;; Report Data ********************
+;;; ********************************
+(defvar *monitor-results* nil
+ "A table of monitoring statistics is stored here.")
+(defvar *no-calls* nil
+ "A list of monitored functions which weren't called.")
+(defvar *estimated-total-overhead* 0)
+;; (proclaim '(type time-type *estimated-total-overhead*))
+
+(defstruct (monitoring-info
+ (:conc-name m-info-)
+ (:constructor make-monitoring-info
+ (name calls time cons
+ percent-time percent-cons
+ time-per-call cons-per-call)))
+ name
+ calls
+ time
+ cons
+ percent-time
+ percent-cons
+ time-per-call
+ cons-per-call)
+
+(defun REPORT (&key (names :all)
+ (nested :exclusive)
+ (threshold 0.01)
+ (sort-key :percent-time)
+ (ignore-no-calls nil))
+ "Same as REPORT-MONITORING but with a nicer keyword interface"
+ (declare (type (member :function :percent-time :time :percent-cons
+ :cons :calls :time-per-call :cons-per-call)
+ sort-key)
+ (type (member :inclusive :exclusive) nested))
+ (report-monitoring names nested threshold sort-key ignore-no-calls))
+
+(defun REPORT-MONITORING (&optional names
+ (nested :exclusive)
+ (threshold 0.01)
+ (key :percent-time)
+ ignore-no-calls)
+ "Report the current monitoring state.
+The percentage of the total time spent executing unmonitored code
+in each function (:exclusive mode), or total time (:inclusive mode)
+will be printed together with the number of calls and
+the unmonitored time per call. Functions that have been executed
+below THRESHOLD % of the time will not be reported. To report on all
+functions set NAMES to be either NIL or :ALL."
+ (when (or (null names) (eq names :all)) (setq names *monitored-functions*))
+
+ (let ((total-time 0)
+ (total-cons 0)
+ (total-calls 0))
+ ;; Compute overall time and consing.
+ (dolist (name names)
+ (multiple-value-bind (calls nested-calls time cons)
+ (monitor-info-values name nested :warn)
+ (declare (ignore nested-calls))
+ (incf total-calls calls)
+ (incf total-time time)
+ (incf total-cons cons)))
+ ;; Total overhead.
+ (setq *estimated-total-overhead*
+ (/ (* *monitor-time-overhead* total-calls)
+ time-units-per-second))
+ ;; Assemble data for only the specified names (all monitored functions)
+ (if (zerop total-time)
+ (format *trace-output* "Not enough execution time to monitor.")
+ (progn
+ (setq *monitor-results* nil *no-calls* nil)
+ (dolist (name names)
+ (multiple-value-bind (calls nested-calls time cons)
+ (monitor-info-values name nested)
+ (declare (ignore nested-calls))
+ (when (minusp time) (setq time 0.0))
+ (when (minusp cons) (setq cons 0.0))
+ (if (zerop calls)
+ (push (if (symbolp name)
+ (symbol-name name)
+ (format nil "~S" name))
+ *no-calls*)
+ (push (make-monitoring-info
+ (format nil "~S" name) ; name
+ calls ; calls
+ (/ time (float time-units-per-second)) ; time in secs
+ (round cons) ; consing
+ (/ time (float total-time)) ; percent-time
+ (if (zerop total-cons) 0
+ (/ cons (float total-cons))) ; percent-cons
+ (/ (/ time (float calls)) ; time-per-call
+ time-units-per-second) ; sec/call
+ (round (/ cons (float calls)))) ; cons-per-call
+ *monitor-results*))))
+ (display-monitoring-results threshold key ignore-no-calls)))))
+
+(defun display-monitoring-results (&optional (threshold 0.01) (key :percent-time)
+ (ignore-no-calls t))
+ (let ((max-length 8) ; Function header size
+ (max-cons-length 8)
+ (total-time 0.0)
+ (total-consed 0)
+ (total-calls 0)
+ (total-percent-time 0)
+ (total-percent-cons 0))
+ (sort-results key)
+ (dolist (result *monitor-results*)
+ (when (or (zerop threshold)
+ (> (m-info-percent-time result) threshold))
+ (setq max-length
+ (max max-length
+ (length (m-info-name result))))
+ (setq max-cons-length
+ (max max-cons-length
+ (m-info-cons-per-call result)))))
+ (incf max-length 2)
+ (setf max-cons-length (+ 2 (ceiling (log max-cons-length 10))))
+ (format *trace-output*
+ "~%~%~
+ ~VT ~VA~
+ ~% ~VT % % ~VA Total Total~
+ ~%Function~VT Time Cons Calls Sec/Call ~VA Time Cons~
+ ~%~V,,,'-A"
+ max-length
+ max-cons-length "Cons"
+ max-length
+ max-cons-length "Per"
+ max-length
+ max-cons-length "Call"
+ (+ max-length 62 (max 0 (- max-cons-length 5))) "-")
+ (dolist (result *monitor-results*)
+ (when (or (zerop threshold)
+ (> (m-info-percent-time result) threshold))
+ (format *trace-output*
+ "~%~A:~VT~6,2F ~6,2F ~7D ~,6F ~VD ~8,3F ~10D"
+ (m-info-name result)
+ max-length
+ (* 100 (m-info-percent-time result))
+ (* 100 (m-info-percent-cons result))
+ (m-info-calls result)
+ (m-info-time-per-call result)
+ max-cons-length
+ (m-info-cons-per-call result)
+ (m-info-time result)
+ (m-info-cons result))
+ (incf total-time (m-info-time result))
+ (incf total-consed (m-info-cons result))
+ (incf total-calls (m-info-calls result))
+ (incf total-percent-time (m-info-percent-time result))
+ (incf total-percent-cons (m-info-percent-cons result))))
+ (format *trace-output*
+ "~%~V,,,'-A~
+ ~%TOTAL:~VT~6,2F ~6,2F ~7D ~9 at T ~VA ~8,3F ~10D~
+ ~%Estimated monitoring overhead: ~5,2F seconds~
+ ~%Estimated total monitoring overhead: ~5,2F seconds"
+ (+ max-length 62 (max 0 (- max-cons-length 5))) "-"
+ max-length
+ (* 100 total-percent-time)
+ (* 100 total-percent-cons)
+ total-calls
+ max-cons-length " "
+ total-time total-consed
+ (/ (* *monitor-time-overhead* total-calls)
+ time-units-per-second)
+ *estimated-total-overhead*)
+ (when (and (not ignore-no-calls) *no-calls*)
+ (setq *no-calls* (sort *no-calls* #'string<))
+ (let ((num-no-calls (length *no-calls*)))
+ (if (> num-no-calls 20)
+ (format *trace-output*
+ "~%~@(~r~) monitored functions were not called. ~
+ ~%See the variable mon::*no-calls* for a list."
+ num-no-calls)
+ (format *trace-output*
+ "~%The following monitored functions were not called:~
+ ~%~{~<~%~:; ~A~>~}~%"
+ *no-calls*))))
+ (values)))
+
+(defun sort-results (&optional (key :percent-time))
+ (setq *monitor-results*
+ (case key
+ (:function (sort *monitor-results* #'string>
+ :key #'m-info-name))
+ ((:percent-time :time) (sort *monitor-results* #'>
+ :key #'m-info-time))
+ ((:percent-cons :cons) (sort *monitor-results* #'>
+ :key #'m-info-cons))
+ (:calls (sort *monitor-results* #'>
+ :key #'m-info-calls))
+ (:time-per-call (sort *monitor-results* #'>
+ :key #'m-info-time-per-call))
+ (:cons-per-call (sort *monitor-results* #'>
+ :key #'m-info-cons-per-call)))))
+
+;;; *END OF FILE*
+
+
Added: branches/bos/thirdparty/emacs/slime/mkdist.sh
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/mkdist.sh Fri Jan 18 06:05:59 2008
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# This code has been placed in the Public Domain. All warranties
+# are disclaimed.
+
+version="1.2"
+dist="slime-$version"
+
+if [ -d $dist ]; then rm -rf $dist; fi
+
+mkdir $dist
+cp NEWS README HACKING PROBLEMS ChangeLog *.el *.lisp $dist/
+
+mkdir $dist/doc
+cp doc/Makefile doc/slime.texi doc/texinfo-tabulate.awk $dist/doc
+
+tar czf $dist.tar.gz $dist
Added: branches/bos/thirdparty/emacs/slime/nregex.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/nregex.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,523 @@
+;;;
+;;; This code was written by:
+;;;
+;;; Lawrence E. Freil <lef at freil.com>
+;;; National Science Center Foundation
+;;; Augusta, Georgia 30909
+;;;
+;;; This program was released into the public domain on 2005-08-31.
+;;; (See the slime-devel mailing list archive for details.)
+;;;
+;;; nregex.lisp - My 4/8/92 attempt at a Lisp based regular expression
+;;; parser.
+;;;
+;;; This regular expression parser operates by taking a
+;;; regular expression and breaking it down into a list
+;;; consisting of lisp expressions and flags. The list
+;;; of lisp expressions is then taken in turned into a
+;;; lambda expression that can be later applied to a
+;;; string argument for parsing.
+;;;;
+;;;; Modifications made 6 March 2001 By Chris Double (chris at double.co.nz)
+;;;; to get working with Corman Lisp 1.42, add package statement and export
+;;;; relevant functions.
+;;;;
+
+(in-package :cl-user)
+
+;; Renamed to slime-nregex avoid name clashes with other versions of
+;; this file. -- he
+
+;;;; CND - 6/3/2001
+(defpackage slime-nregex
+ (:use #:common-lisp)
+ (:export
+ #:regex
+ #:regex-compile
+ ))
+
+;;;; CND - 6/3/2001
+(in-package :slime-nregex)
+
+;;;
+;;; First we create a copy of macros to help debug the beast
+(eval-when (:compile-toplevel :load-toplevel :execute)
+(defvar *regex-debug* nil) ; Set to nil for no debugging code
+)
+
+(defmacro info (message &rest args)
+ (if *regex-debug*
+ `(format *standard-output* ,message , at args)))
+
+;;;
+;;; Declare the global variables for storing the paren index list.
+;;;
+(defvar *regex-groups* (make-array 10))
+(defvar *regex-groupings* 0)
+
+;;;
+;;; Declare a simple interface for testing. You probably wouldn't want
+;;; to use this interface unless you were just calling this once.
+;;;
+(defun regex (expression string)
+ "Usage: (regex <expression> <string)
+ This function will call regex-compile on the expression and then apply
+ the string to the returned lambda list."
+ (let ((findit (cond ((stringp expression)
+ (regex-compile expression))
+ ((listp expression)
+ expression)))
+ (result nil))
+ (if (not (funcall (if (functionp findit)
+ findit
+ (eval `(function ,findit))) string))
+ (return-from regex nil))
+ (if (= *regex-groupings* 0)
+ (return-from regex t))
+ (dotimes (i *regex-groupings*)
+ (push (funcall 'subseq
+ string
+ (car (aref *regex-groups* i))
+ (cadr (aref *regex-groups* i)))
+ result))
+ (reverse result)))
+
+;;;
+;;; Declare some simple macros to make the code more readable.
+;;;
+(defvar *regex-special-chars* "?*+.()[]\\${}")
+
+(defmacro add-exp (list)
+ "Add an item to the end of expression"
+ `(setf expression (append expression ,list)))
+
+;;;
+;;; Define a function that will take a quoted character and return
+;;; what the real character should be plus how much of the source
+;;; string was used. If the result is a set of characters, return an
+;;; array of bits indicating which characters should be set. If the
+;;; expression is one of the sub-group matches return a
+;;; list-expression that will provide the match.
+;;;
+(defun regex-quoted (char-string &optional (invert nil))
+ "Usage: (regex-quoted <char-string> &optional invert)
+ Returns either the quoted character or a simple bit vector of bits set for
+ the matching values"
+ (let ((first (char char-string 0))
+ (result (char char-string 0))
+ (used-length 1))
+ (cond ((eql first #\n)
+ (setf result #\NewLine))
+ ((eql first #\c)
+ (setf result #\Return))
+ ((eql first #\t)
+ (setf result #\Tab))
+ ((eql first #\d)
+ (setf result #*0000000000000000000000000000000000000000000000001111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
+ ((eql first #\D)
+ (setf result #*1111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
+ ((eql first #\w)
+ (setf result #*0000000000000000000000000000000000000000000000001111111111000000011111111111111111111111111000010111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
+ ((eql first #\W)
+ (setf result #*1111111111111111111111111111111111111111111111110000000000111111100000000000000000000000000111101000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
+ ((eql first #\b)
+ (setf result #*0000000001000000000000000000000011000000000010100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
+ ((eql first #\B)
+ (setf result #*1111111110111111111111111111111100111111111101011111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
+ ((eql first #\s)
+ (setf result #*0000000001100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))
+ ((eql first #\S)
+ (setf result #*1111111110011111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
+ ((and (>= (char-code first) (char-code #\0))
+ (<= (char-code first) (char-code #\9)))
+ (if (and (> (length char-string) 2)
+ (and (>= (char-code (char char-string 1)) (char-code #\0))
+ (<= (char-code (char char-string 1)) (char-code #\9))
+ (>= (char-code (char char-string 2)) (char-code #\0))
+ (<= (char-code (char char-string 2)) (char-code #\9))))
+ ;;
+ ;; It is a single character specified in octal
+ ;;
+ (progn
+ (setf result (do ((x 0 (1+ x))
+ (return 0))
+ ((= x 2) return)
+ (setf return (+ (* return 8)
+ (- (char-code (char char-string x))
+ (char-code #\0))))))
+ (setf used-length 3))
+ ;;
+ ;; We have a group number replacement.
+ ;;
+ (let ((group (- (char-code first) (char-code #\0))))
+ (setf result `((let ((nstring (subseq string (car (aref *regex-groups* ,group))
+ (cadr (aref *regex-groups* ,group)))))
+ (if (< length (+ index (length nstring)))
+ (return-from compare nil))
+ (if (not (string= string nstring
+ :start1 index
+ :end1 (+ index (length nstring))))
+ (return-from compare nil)
+ (incf index (length nstring)))))))))
+ (t
+ (setf result first)))
+ (if (and (vectorp result) invert)
+ (bit-xor result #*1111111110011111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 t))
+ (values result used-length)))
+
+;;;
+;;; Now for the main regex compiler routine.
+;;;
+(defun regex-compile (source &key (anchored nil))
+ "Usage: (regex-compile <expression> [ :anchored (t/nil) ])
+ This function take a regular expression (supplied as source) and
+ compiles this into a lambda list that a string argument can then
+ be applied to. It is also possible to compile this lambda list
+ for better performance or to save it as a named function for later
+ use"
+ (info "Now entering regex-compile with \"~A\"~%" source)
+ ;;
+ ;; This routine works in two parts.
+ ;; The first pass take the regular expression and produces a list of
+ ;; operators and lisp expressions for the entire regular expression.
+ ;; The second pass takes this list and produces the lambda expression.
+ (let ((expression '()) ; holder for expressions
+ (group 1) ; Current group index
+ (group-stack nil) ; Stack of current group endings
+ (result nil) ; holder for built expression.
+ (fast-first nil)) ; holder for quick unanchored scan
+ ;;
+ ;; If the expression was an empty string then it alway
+ ;; matches (so lets leave early)
+ ;;
+ (if (= (length source) 0)
+ (return-from regex-compile
+ '(lambda (&rest args)
+ (declare (ignore args))
+ t)))
+ ;;
+ ;; If the first character is a caret then set the anchored
+ ;; flags and remove if from the expression string.
+ ;;
+ (cond ((eql (char source 0) #\^)
+ (setf source (subseq source 1))
+ (setf anchored t)))
+ ;;
+ ;; If the first sequence is .* then also set the anchored flags.
+ ;; (This is purely for optimization, it will work without this).
+ ;;
+ (if (>= (length source) 2)
+ (if (string= source ".*" :start1 0 :end1 2)
+ (setf anchored t)))
+ ;;
+ ;; Also, If this is not an anchored search and the first character is
+ ;; a literal, then do a quick scan to see if it is even in the string.
+ ;; If not then we can issue a quick nil,
+ ;; otherwise we can start the search at the matching character to skip
+ ;; the checks of the non-matching characters anyway.
+ ;;
+ ;; If I really wanted to speed up this section of code it would be
+ ;; easy to recognize the case of a fairly long multi-character literal
+ ;; and generate a Boyer-Moore search for the entire literal.
+ ;;
+ ;; I generate the code to do a loop because on CMU Lisp this is about
+ ;; twice as fast a calling position.
+ ;;
+ (if (and (not anchored)
+ (not (position (char source 0) *regex-special-chars*))
+ (not (and (> (length source) 1)
+ (position (char source 1) *regex-special-chars*))))
+ (setf fast-first `((if (not (dotimes (i length nil)
+ (if (eql (char string i)
+ ,(char source 0))
+ (return (setf start i)))))
+ (return-from final-return nil)))))
+ ;;
+ ;; Generate the very first expression to save the starting index
+ ;; so that group 0 will be the entire string matched always
+ ;;
+ (add-exp '((setf (aref *regex-groups* 0)
+ (list index nil))))
+ ;;
+ ;; Loop over each character in the regular expression building the
+ ;; expression list as we go.
+ ;;
+ (do ((eindex 0 (1+ eindex)))
+ ((= eindex (length source)))
+ (let ((current (char source eindex)))
+ (info "Now processing character ~A index = ~A~%" current eindex)
+ (case current
+ ((#\.)
+ ;;
+ ;; Generate code for a single wild character
+ ;;
+ (add-exp '((if (>= index length)
+ (return-from compare nil)
+ (incf index)))))
+ ((#\$)
+ ;;
+ ;; If this is the last character of the expression then
+ ;; anchor the end of the expression, otherwise let it slide
+ ;; as a standard character (even though it should be quoted).
+ ;;
+ (if (= eindex (1- (length source)))
+ (add-exp '((if (not (= index length))
+ (return-from compare nil))))
+ (add-exp '((if (not (and (< index length)
+ (eql (char string index) #\$)))
+ (return-from compare nil)
+ (incf index))))))
+ ((#\*)
+ (add-exp '(ASTRISK)))
+
+ ((#\+)
+ (add-exp '(PLUS)))
+
+ ((#\?)
+ (add-exp '(QUESTION)))
+
+ ((#\()
+ ;;
+ ;; Start a grouping.
+ ;;
+ (incf group)
+ (push group group-stack)
+ (add-exp `((setf (aref *regex-groups* ,(1- group))
+ (list index nil))))
+ (add-exp `(,group)))
+ ((#\))
+ ;;
+ ;; End a grouping
+ ;;
+ (let ((group (pop group-stack)))
+ (add-exp `((setf (cadr (aref *regex-groups* ,(1- group)))
+ index)))
+ (add-exp `(,(- group)))))
+ ((#\[)
+ ;;
+ ;; Start of a range operation.
+ ;; Generate a bit-vector that has one bit per possible character
+ ;; and then on each character or range, set the possible bits.
+ ;;
+ ;; If the first character is carat then invert the set.
+ (let* ((invert (eql (char source (1+ eindex)) #\^))
+ (bitstring (make-array 256 :element-type 'bit
+ :initial-element
+ (if invert 1 0)))
+ (set-char (if invert 0 1)))
+ (if invert (incf eindex))
+ (do ((x (1+ eindex) (1+ x)))
+ ((eql (char source x) #\]) (setf eindex x))
+ (info "Building range with character ~A~%" (char source x))
+ (cond ((and (eql (char source (1+ x)) #\-)
+ (not (eql (char source (+ x 2)) #\])))
+ (if (>= (char-code (char source x))
+ (char-code (char source (+ 2 x))))
+ (error "Invalid range \"~A-~A\". Ranges must be in acending order"
+ (char source x) (char source (+ 2 x))))
+ (do ((j (char-code (char source x)) (1+ j)))
+ ((> j (char-code (char source (+ 2 x))))
+ (incf x 2))
+ (info "Setting bit for char ~A code ~A~%" (code-char j) j)
+ (setf (sbit bitstring j) set-char)))
+ (t
+ (cond ((not (eql (char source x) #\]))
+ (let ((char (char source x)))
+ ;;
+ ;; If the character is quoted then find out what
+ ;; it should have been
+ ;;
+ (if (eql (char source x) #\\ )
+ (let ((length))
+ (multiple-value-setq (char length)
+ (regex-quoted (subseq source x) invert))
+ (incf x length)))
+ (info "Setting bit for char ~A code ~A~%" char (char-code char))
+ (if (not (vectorp char))
+ (setf (sbit bitstring (char-code (char source x))) set-char)
+ (bit-ior bitstring char t))))))))
+ (add-exp `((let ((range ,bitstring))
+ (if (>= index length)
+ (return-from compare nil))
+ (if (= 1 (sbit range (char-code (char string index))))
+ (incf index)
+ (return-from compare nil)))))))
+ ((#\\ )
+ ;;
+ ;; Intreprete the next character as a special, range, octal, group or
+ ;; just the character itself.
+ ;;
+ (let ((length)
+ (value))
+ (multiple-value-setq (value length)
+ (regex-quoted (subseq source (1+ eindex)) nil))
+ (cond ((listp value)
+ (add-exp value))
+ ((characterp value)
+ (add-exp `((if (not (and (< index length)
+ (eql (char string index)
+ ,value)))
+ (return-from compare nil)
+ (incf index)))))
+ ((vectorp value)
+ (add-exp `((let ((range ,value))
+ (if (>= index length)
+ (return-from compare nil))
+ (if (= 1 (sbit range (char-code (char string index))))
+ (incf index)
+ (return-from compare nil)))))))
+ (incf eindex length)))
+ (t
+ ;;
+ ;; We have a literal character.
+ ;; Scan to see how many we have and if it is more than one
+ ;; generate a string= verses as single eql.
+ ;;
+ (let* ((lit "")
+ (term (dotimes (litindex (- (length source) eindex) nil)
+ (let ((litchar (char source (+ eindex litindex))))
+ (if (position litchar *regex-special-chars*)
+ (return litchar)
+ (progn
+ (info "Now adding ~A index ~A to lit~%" litchar
+ litindex)
+ (setf lit (concatenate 'string lit
+ (string litchar)))))))))
+ (if (= (length lit) 1)
+ (add-exp `((if (not (and (< index length)
+ (eql (char string index) ,current)))
+ (return-from compare nil)
+ (incf index))))
+ ;;
+ ;; If we have a multi-character literal then we must
+ ;; check to see if the next character (if there is one)
+ ;; is an astrisk or a plus or a question mark. If so then we must not use this
+ ;; character in the big literal.
+ (progn
+ (if (or (eql term #\*)
+ (eql term #\+)
+ (eql term #\?))
+ (setf lit (subseq lit 0 (1- (length lit)))))
+ (add-exp `((if (< length (+ index ,(length lit)))
+ (return-from compare nil))
+ (if (not (string= string ,lit :start1 index
+ :end1 (+ index ,(length lit))))
+ (return-from compare nil)
+ (incf index ,(length lit)))))))
+ (incf eindex (1- (length lit))))))))
+ ;;
+ ;; Plug end of list to return t. If we made it this far then
+ ;; We have matched!
+ (add-exp '((setf (cadr (aref *regex-groups* 0))
+ index)))
+ (add-exp '((return-from final-return t)))
+ ;;
+;;; (print expression)
+ ;;
+ ;; Now take the expression list and turn it into a lambda expression
+ ;; replacing the special flags with lisp code.
+ ;; For example: A BEGIN needs to be replace by an expression that
+ ;; saves the current index, then evaluates everything till it gets to
+ ;; the END then save the new index if it didn't fail.
+ ;; On an ASTRISK I need to take the previous expression and wrap
+ ;; it in a do that will evaluate the expression till an error
+ ;; occurs and then another do that encompases the remainder of the
+ ;; regular expression and iterates decrementing the index by one
+ ;; of the matched expression sizes and then returns nil. After
+ ;; the last expression insert a form that does a return t so that
+ ;; if the entire nested sub-expression succeeds then the loop
+ ;; is broken manually.
+ ;;
+ (setf result (copy-tree nil))
+ ;;
+ ;; Reversing the current expression makes building up the
+ ;; lambda list easier due to the nexting of expressions when
+ ;; and astrisk has been encountered.
+ (setf expression (reverse expression))
+ (do ((elt 0 (1+ elt)))
+ ((>= elt (length expression)))
+ (let ((piece (nth elt expression)))
+ ;;
+ ;; Now check for PLUS, if so then ditto the expression and then let the
+ ;; ASTRISK below handle the rest.
+ ;;
+ (cond ((eql piece 'PLUS)
+ (cond ((listp (nth (1+ elt) expression))
+ (setf result (append (list (nth (1+ elt) expression))
+ result)))
+ ;;
+ ;; duplicate the entire group
+ ;; NOTE: This hasn't been implemented yet!!
+ (t
+ (error "GROUP repeat hasn't been implemented yet~%")))))
+ (cond ((listp piece) ;Just append the list
+ (setf result (append (list piece) result)))
+ ((eql piece 'QUESTION) ; Wrap it in a block that won't fail
+ (cond ((listp (nth (1+ elt) expression))
+ (setf result
+ (append `((progn (block compare
+ ,(nth (1+ elt)
+ expression))
+ t))
+ result))
+ (incf elt))
+ ;;
+ ;; This is a QUESTION on an entire group which
+ ;; hasn't been implemented yet!!!
+ ;;
+ (t
+ (error "Optional groups not implemented yet~%"))))
+ ((or (eql piece 'ASTRISK) ; Do the wild thing!
+ (eql piece 'PLUS))
+ (cond ((listp (nth (1+ elt) expression))
+ ;;
+ ;; This is a single character wild card so
+ ;; do the simple form.
+ ;;
+ (setf result
+ `((let ((oindex index))
+ (block compare
+ (do ()
+ (nil)
+ ,(nth (1+ elt) expression)))
+ (do ((start index (1- start)))
+ ((< start oindex) nil)
+ (let ((index start))
+ (block compare
+ , at result))))))
+ (incf elt))
+ (t
+ ;;
+ ;; This is a subgroup repeated so I must build
+ ;; the loop using several values.
+ ;;
+ ))
+ )
+ (t t)))) ; Just ignore everything else.
+ ;;
+ ;; Now wrap the result in a lambda list that can then be
+ ;; invoked or compiled, however the user wishes.
+ ;;
+ (if anchored
+ (setf result
+ `(lambda (string &key (start 0) (end (length string)))
+ (setf *regex-groupings* ,group)
+ (block final-return
+ (block compare
+ (let ((index start)
+ (length end))
+ , at result)))))
+ (setf result
+ `(lambda (string &key (start 0) (end (length string)))
+ (setf *regex-groupings* ,group)
+ (block final-return
+ (let ((length end))
+ , at fast-first
+ (do ((marker start (1+ marker)))
+ ((> marker end) nil)
+ (let ((index marker))
+ (if (block compare
+ , at result)
+ (return t)))))))))))
+
+;; (provide 'nregex)
Added: branches/bos/thirdparty/emacs/slime/sbcl-pprint-patch.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/sbcl-pprint-patch.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,332 @@
+;; Pretty printer patch for SBCL, which adds the "annotations" feature
+;; required for sending presentations through pretty-printing streams.
+;;
+;; The section marked "Changed functions" and the DEFSTRUCT
+;; PRETTY-STREAM are based on SBCL's pprint.lisp.
+;;
+;; Public domain.
+
+(in-package "SB!PRETTY")
+
+(defstruct (annotation (:include queued-op))
+ (handler (constantly nil) :type function)
+ (record))
+
+
+(defstruct (pretty-stream (:include sb!kernel:ansi-stream
+ (out #'pretty-out)
+ (sout #'pretty-sout)
+ (misc #'pretty-misc))
+ (:constructor make-pretty-stream (target))
+ (:copier nil))
+ ;; Where the output is going to finally go.
+ (target (missing-arg) :type stream)
+ ;; Line length we should format to. Cached here so we don't have to keep
+ ;; extracting it from the target stream.
+ (line-length (or *print-right-margin*
+ (sb!impl::line-length target)
+ default-line-length)
+ :type column)
+ ;; A simple string holding all the text that has been output but not yet
+ ;; printed.
+ (buffer (make-string initial-buffer-size) :type (simple-array character (*)))
+ ;; The index into BUFFER where more text should be put.
+ (buffer-fill-pointer 0 :type index)
+ ;; Whenever we output stuff from the buffer, we shift the remaining noise
+ ;; over. This makes it difficult to keep references to locations in
+ ;; the buffer. Therefore, we have to keep track of the total amount of
+ ;; stuff that has been shifted out of the buffer.
+ (buffer-offset 0 :type posn)
+ ;; The column the first character in the buffer will appear in. Normally
+ ;; zero, but if we end up with a very long line with no breaks in it we
+ ;; might have to output part of it. Then this will no longer be zero.
+ (buffer-start-column (or (sb!impl::charpos target) 0) :type column)
+ ;; The line number we are currently on. Used for *PRINT-LINES*
+ ;; abbreviations and to tell when sections have been split across
+ ;; multiple lines.
+ (line-number 0 :type index)
+ ;; the value of *PRINT-LINES* captured at object creation time. We
+ ;; use this, instead of the dynamic *PRINT-LINES*, to avoid
+ ;; weirdness like
+ ;; (let ((*print-lines* 50))
+ ;; (pprint-logical-block ..
+ ;; (dotimes (i 10)
+ ;; (let ((*print-lines* 8))
+ ;; (print (aref possiblybigthings i) prettystream)))))
+ ;; terminating the output of the entire logical blockafter 8 lines.
+ (print-lines *print-lines* :type (or index null) :read-only t)
+ ;; Stack of logical blocks in effect at the buffer start.
+ (blocks (list (make-logical-block)) :type list)
+ ;; Buffer holding the per-line prefix active at the buffer start.
+ ;; Indentation is included in this. The length of this is stored
+ ;; in the logical block stack.
+ (prefix (make-string initial-buffer-size) :type (simple-array character (*)))
+ ;; Buffer holding the total remaining suffix active at the buffer start.
+ ;; The characters are right-justified in the buffer to make it easier
+ ;; to output the buffer. The length is stored in the logical block
+ ;; stack.
+ (suffix (make-string initial-buffer-size) :type (simple-array character (*)))
+ ;; Queue of pending operations. When empty, HEAD=TAIL=NIL. Otherwise,
+ ;; TAIL holds the first (oldest) cons and HEAD holds the last (newest)
+ ;; cons. Adding things to the queue is basically (setf (cdr head) (list
+ ;; new)) and removing them is basically (pop tail) [except that care must
+ ;; be taken to handle the empty queue case correctly.]
+ (queue-tail nil :type list)
+ (queue-head nil :type list)
+ ;; Block-start queue entries in effect at the queue head.
+ (pending-blocks nil :type list)
+ ;; Queue of annotations to the buffer
+ (annotations-tail nil :type list)
+ (annotations-head nil :type list))
+
+
+(defmacro enqueue (stream type &rest args)
+ (let ((constructor (intern (concatenate 'string
+ "MAKE-"
+ (symbol-name type))
+ "SB-PRETTY")))
+ (once-only ((stream stream)
+ (entry `(,constructor :posn
+ (index-posn
+ (pretty-stream-buffer-fill-pointer
+ ,stream)
+ ,stream)
+ , at args))
+ (op `(list ,entry))
+ (head `(pretty-stream-queue-head ,stream)))
+ `(progn
+ (if ,head
+ (setf (cdr ,head) ,op)
+ (setf (pretty-stream-queue-tail ,stream) ,op))
+ (setf (pretty-stream-queue-head ,stream) ,op)
+ ,entry))))
+
+;;;
+;;; New helper functions
+;;;
+
+(defun enqueue-annotation (stream handler record)
+ (enqueue stream annotation :handler handler
+ :record record))
+
+(defun re-enqueue-annotation (stream annotation)
+ (let* ((annotation-cons (list annotation))
+ (head (pretty-stream-annotations-head stream)))
+ (if head
+ (setf (cdr head) annotation-cons)
+ (setf (pretty-stream-annotations-tail stream) annotation-cons))
+ (setf (pretty-stream-annotations-head stream) annotation-cons)
+ nil))
+
+(defun re-enqueue-annotations (stream end)
+ (loop for tail = (pretty-stream-queue-tail stream) then (cdr tail)
+ while (and tail (not (eql (car tail) end)))
+ when (annotation-p (car tail))
+ do (re-enqueue-annotation stream (car tail))))
+
+(defun dequeue-annotation (stream &key end-posn)
+ (let ((next-annotation (car (pretty-stream-annotations-tail stream))))
+ (when next-annotation
+ (when (or (not end-posn)
+ (<= (annotation-posn next-annotation) end-posn))
+ (pop (pretty-stream-annotations-tail stream))
+ (unless (pretty-stream-annotations-tail stream)
+ (setf (pretty-stream-annotations-head stream) nil))
+ next-annotation))))
+
+(defun invoke-annotation (stream annotation truncatep)
+ (let ((target (pretty-stream-target stream)))
+ (funcall (annotation-handler annotation)
+ (annotation-record annotation)
+ target
+ truncatep)))
+
+(defun output-buffer-with-annotations (stream end)
+ (let ((target (pretty-stream-target stream))
+ (buffer (pretty-stream-buffer stream))
+ (end-posn (index-posn end stream))
+ (start 0))
+ (loop
+ for annotation = (dequeue-annotation stream :end-posn end-posn)
+ while annotation
+ do
+ (let ((annotation-index (posn-index (annotation-posn annotation)
+ stream)))
+ (when (> annotation-index start)
+ (write-string buffer target :start start
+ :end annotation-index)
+ (setf start annotation-index))
+ (invoke-annotation stream annotation nil)))
+ (when (> end start)
+ (write-string buffer target :start start :end end))))
+
+(defun flush-annotations (stream end truncatep)
+ (let ((end-posn (index-posn end stream)))
+ (loop
+ for annotation = (dequeue-annotation stream :end-posn end-posn)
+ while annotation
+ do (invoke-annotation stream annotation truncatep))))
+
+;;;
+;;; Changed functions
+;;;
+
+(defun maybe-output (stream force-newlines-p)
+ (declare (type pretty-stream stream))
+ (let ((tail (pretty-stream-queue-tail stream))
+ (output-anything nil))
+ (loop
+ (unless tail
+ (setf (pretty-stream-queue-head stream) nil)
+ (return))
+ (let ((next (pop tail)))
+ (etypecase next
+ (newline
+ (when (ecase (newline-kind next)
+ ((:literal :mandatory :linear) t)
+ (:miser (misering-p stream))
+ (:fill
+ (or (misering-p stream)
+ (> (pretty-stream-line-number stream)
+ (logical-block-section-start-line
+ (first (pretty-stream-blocks stream))))
+ (ecase (fits-on-line-p stream
+ (newline-section-end next)
+ force-newlines-p)
+ ((t) nil)
+ ((nil) t)
+ (:dont-know
+ (return))))))
+ (setf output-anything t)
+ (output-line stream next)))
+ (indentation
+ (unless (misering-p stream)
+ (set-indentation stream
+ (+ (ecase (indentation-kind next)
+ (:block
+ (logical-block-start-column
+ (car (pretty-stream-blocks stream))))
+ (:current
+ (posn-column
+ (indentation-posn next)
+ stream)))
+ (indentation-amount next)))))
+ (block-start
+ (ecase (fits-on-line-p stream (block-start-section-end next)
+ force-newlines-p)
+ ((t)
+ ;; Just nuke the whole logical block and make it look like one
+ ;; nice long literal. (But don't nuke annotations.)
+ (let ((end (block-start-block-end next)))
+ (expand-tabs stream end)
+ (re-enqueue-annotations stream end)
+ (setf tail (cdr (member end tail)))))
+ ((nil)
+ (really-start-logical-block
+ stream
+ (posn-column (block-start-posn next) stream)
+ (block-start-prefix next)
+ (block-start-suffix next)))
+ (:dont-know
+ (return))))
+ (block-end
+ (really-end-logical-block stream))
+ (tab
+ (expand-tabs stream next))
+ (annotation
+ (re-enqueue-annotation stream next))))
+ (setf (pretty-stream-queue-tail stream) tail))
+ output-anything))
+
+(defun output-line (stream until)
+ (declare (type pretty-stream stream)
+ (type newline until))
+ (let* ((target (pretty-stream-target stream))
+ (buffer (pretty-stream-buffer stream))
+ (kind (newline-kind until))
+ (literal-p (eq kind :literal))
+ (amount-to-consume (posn-index (newline-posn until) stream))
+ (amount-to-print
+ (if literal-p
+ amount-to-consume
+ (let ((last-non-blank
+ (position #\space buffer :end amount-to-consume
+ :from-end t :test #'char/=)))
+ (if last-non-blank
+ (1+ last-non-blank)
+ 0)))))
+ (output-buffer-with-annotations stream amount-to-print)
+ (flush-annotations stream amount-to-consume nil)
+ (let ((line-number (pretty-stream-line-number stream)))
+ (incf line-number)
+ (when (and (not *print-readably*)
+ (pretty-stream-print-lines stream)
+ (>= line-number (pretty-stream-print-lines stream)))
+ (write-string " .." target)
+ (flush-annotations stream
+ (pretty-stream-buffer-fill-pointer stream)
+ t)
+ (let ((suffix-length (logical-block-suffix-length
+ (car (pretty-stream-blocks stream)))))
+ (unless (zerop suffix-length)
+ (let* ((suffix (pretty-stream-suffix stream))
+ (len (length suffix)))
+ (write-string suffix target
+ :start (- len suffix-length)
+ :end len))))
+ (throw 'line-limit-abbreviation-happened t))
+ (setf (pretty-stream-line-number stream) line-number)
+ (write-char #\newline target)
+ (setf (pretty-stream-buffer-start-column stream) 0)
+ (let* ((fill-ptr (pretty-stream-buffer-fill-pointer stream))
+ (block (first (pretty-stream-blocks stream)))
+ (prefix-len
+ (if literal-p
+ (logical-block-per-line-prefix-end block)
+ (logical-block-prefix-length block)))
+ (shift (- amount-to-consume prefix-len))
+ (new-fill-ptr (- fill-ptr shift))
+ (new-buffer buffer)
+ (buffer-length (length buffer)))
+ (when (> new-fill-ptr buffer-length)
+ (setf new-buffer
+ (make-string (max (* buffer-length 2)
+ (+ buffer-length
+ (floor (* (- new-fill-ptr buffer-length)
+ 5)
+ 4)))))
+ (setf (pretty-stream-buffer stream) new-buffer))
+ (replace new-buffer buffer
+ :start1 prefix-len :start2 amount-to-consume :end2 fill-ptr)
+ (replace new-buffer (pretty-stream-prefix stream)
+ :end1 prefix-len)
+ (setf (pretty-stream-buffer-fill-pointer stream) new-fill-ptr)
+ (incf (pretty-stream-buffer-offset stream) shift)
+ (unless literal-p
+ (setf (logical-block-section-column block) prefix-len)
+ (setf (logical-block-section-start-line block) line-number))))))
+
+(defun output-partial-line (stream)
+ (let* ((fill-ptr (pretty-stream-buffer-fill-pointer stream))
+ (tail (pretty-stream-queue-tail stream))
+ (count
+ (if tail
+ (posn-index (queued-op-posn (car tail)) stream)
+ fill-ptr))
+ (new-fill-ptr (- fill-ptr count))
+ (buffer (pretty-stream-buffer stream)))
+ (when (zerop count)
+ (error "Output-partial-line called when nothing can be output."))
+ (output-buffer-with-annotations stream count)
+ (incf (pretty-stream-buffer-start-column stream) count)
+ (replace buffer buffer :end1 new-fill-ptr :start2 count :end2 fill-ptr)
+ (setf (pretty-stream-buffer-fill-pointer stream) new-fill-ptr)
+ (incf (pretty-stream-buffer-offset stream) count)))
+
+(defun force-pretty-output (stream)
+ (maybe-output stream nil)
+ (expand-tabs stream nil)
+ (re-enqueue-annotations stream nil)
+ (output-buffer-with-annotations stream
+ (pretty-stream-buffer-fill-pointer stream)))
+
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/slime-autoloads.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/slime-autoloads.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,50 @@
+;;; slime-autoloads.el --- autoload definitions for SLIME
+
+;; Copyright (C) 2007 Helmut Eller
+
+;; This file is protected by the GNU GPLv2 (or later), as distributed
+;; with GNU Emacs.
+
+;;; Commentary:
+
+;; This code defines the necessary autoloads, so that we don't need to
+;; load everything from .emacs.
+
+;;; Code:
+
+(autoload 'slime "slime"
+ "Start a Lisp subprocess and connect to its Swank server." t)
+
+(autoload 'slime-mode "slime"
+ "SLIME: The Superior Lisp Interaction (Minor) Mode for Emacs." t)
+
+(autoload 'slime-connect "slime"
+ "Connect to a running Swank server." t)
+
+(autoload 'hyperspec-lookup "hyperspec" nil t)
+
+(autoload 'slime-lisp-mode-hook "slime")
+(autoload 'slime-scheme-mode-hook "slime")
+
+(defvar slime-lisp-modes '(lisp-mode))
+
+(defun slime-setup (&optional contribs)
+ "Setup Emacs so that lisp-mode buffers always use SLIME.
+CONTRIBS is a list of contrib packages to load."
+ (when (member 'lisp-mode slime-lisp-modes)
+ (add-hook 'lisp-mode-hook 'slime-lisp-mode-hook))
+ (setq slime-setup-contribs contribs)
+ (add-hook 'slime-load-hook 'slime-setup-contribs))
+
+(defvar slime-setup-contribs nil)
+
+(defun slime-setup-contribs ()
+ (dolist (c slime-setup-contribs)
+ (require c)
+ (let ((init (intern (format "%s-init" c))))
+ (when (fboundp init)
+ (funcall init)))))
+
+(provide 'slime-autoloads)
+
+;;; slime-autoloads.el ends here
Added: branches/bos/thirdparty/emacs/slime/slime.el
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/slime.el Fri Jan 18 06:05:59 2008
@@ -0,0 +1,9602 @@
+;;; slime.el --- Superior Lisp Interaction Mode for Emacs
+;;
+;;;; License
+;; Copyright (C) 2003 Eric Marsden, Luke Gorrie, Helmut Eller
+;; Copyright (C) 2004,2005,2006 Luke Gorrie, Helmut Eller
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of
+;; the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+
+;;;; Commentary
+;;
+;; This file contains extensions for programming in Common Lisp. The
+;; main features are:
+;;
+;; A socket-based communication/RPC interface between Emacs and
+;; Lisp.
+;;
+;; The `slime-mode' minor-mode complementing `lisp-mode'. This new
+;; mode includes many commands for interacting with the Common Lisp
+;; process.
+;;
+;; Common Lisp REPL (Read-Eval-Print Loop) written in Emacs Lisp,
+;; similar to `ielm'.
+;;
+;; Common Lisp debugger written in Emacs Lisp. The debugger pops up
+;; an Emacs buffer similar to the Emacs/Elisp debugger.
+;;
+;; Trapping compiler messages and creating annotations in the source
+;; file on the appropriate forms.
+;;
+;; SLIME is compatible with GNU Emacs 20 and 21 and XEmacs 21. In
+;; order to run SLIME requires a supporting Lisp server called
+;; Swank. Swank is distributed with slime.el and will automatically be
+;; started in a normal installation.
+
+
+;;;; Dependencies and setup
+
+(eval-and-compile
+ (require 'cl)
+ (unless (fboundp 'define-minor-mode)
+ (require 'easy-mmode)
+ (defalias 'define-minor-mode 'easy-mmode-define-minor-mode)))
+(require 'comint)
+(require 'timer)
+(require 'pp)
+(require 'hideshow)
+(require 'hyperspec)
+(require 'font-lock)
+(when (featurep 'xemacs)
+ (require 'overlay))
+(require 'easymenu)
+
+(defvar slime-lisp-modes '(lisp-mode))
+
+(defun slime-setup (&optional contribs)
+ "Setup Emacs so that lisp-mode buffers always use SLIME.
+CONTRIBS is a list of contrib packages to load."
+ (when (member 'lisp-mode slime-lisp-modes)
+ (add-hook 'lisp-mode-hook 'slime-lisp-mode-hook))
+ (dolist (c contribs)
+ (require c)
+ (let ((init (intern (format "%s-init" c))))
+ (when (fboundp init)
+ (funcall init)))))
+
+(defun slime-lisp-mode-hook ()
+ (slime-mode 1)
+ (set (make-local-variable 'lisp-indent-function)
+ 'common-lisp-indent-function))
+
+(eval-and-compile
+ (defvar slime-path
+ (let ((path (or (locate-library "slime") load-file-name)))
+ (and path (file-name-directory path)))
+ "Directory containing the Slime package.
+This is used to load the supporting Common Lisp library, Swank.
+The default value is automatically computed from the location of the
+Emacs Lisp package."))
+
+(eval-and-compile
+ (defun slime-changelog-date ()
+ "Return the datestring of the latest entry in the ChangeLog file.
+Return nil if the ChangeLog file cannot be found."
+ (let ((changelog (concat slime-path "ChangeLog")))
+ (if (file-exists-p changelog)
+ (with-temp-buffer
+ (insert-file-contents changelog nil 0 100)
+ (goto-char (point-min))
+ (symbol-name (read (current-buffer))))
+ nil))))
+
+(defvar slime-protocol-version nil)
+(setq slime-protocol-version
+ (eval-when-compile (slime-changelog-date)))
+
+
+;;;; Customize groups
+;;
+;;;;; slime
+
+(defgroup slime nil
+ "Interaction with the Superior Lisp Environment."
+ :prefix "slime-"
+ :group 'applications)
+
+;;;;; slime-ui
+
+(defgroup slime-ui nil
+ "Interaction with the Superior Lisp Environment."
+ :prefix "slime-"
+ :group 'slime)
+
+(defcustom slime-truncate-lines t
+ "Set `truncate-lines' in popup buffers.
+This applies to buffers that present lines as rows of data, such as
+debugger backtraces and apropos listings."
+ :type 'boolean
+ :group 'slime-ui)
+
+(defcustom slime-update-modeline-package t
+ "Automatically update the Lisp package name in the minibuffer.
+This is done with a text-search that runs on an idle timer."
+ :type 'boolean
+ :group 'slime-ui)
+
+(defcustom slime-kill-without-query-p nil
+ "If non-nil, kill SLIME processes without query when quitting Emacs.
+This applies to the *inferior-lisp* buffer and the network connections."
+ :type 'boolean
+ :group 'slime-ui)
+
+;;;;; slime-lisp
+
+(defgroup slime-lisp nil
+ "Lisp server configuration."
+ :prefix "slime-"
+ :group 'slime)
+
+(defcustom slime-backend "swank-loader.lisp"
+ "The name of the Lisp file that loads the Swank server.
+This name is interpreted relative to the directory containing
+slime.el, but could also be set to an absolute filename."
+ :type 'string
+ :group 'slime-lisp)
+
+(defcustom slime-connected-hook nil
+ "List of functions to call when SLIME connects to Lisp."
+ :type 'hook
+ :group 'slime-lisp)
+
+(defcustom slime-filename-translations nil
+ "Assoc list of hostnames and filename translation functions.
+Each element is of the form (HOSTNAME-REGEXP TO-LISP FROM-LISP).
+
+HOSTNAME-REGEXP is a regexp which is applied to the connection's
+slime-machine-instance. If HOSTNAME-REGEXP maches then the
+corresponding TO-LISP and FROM-LISP functions will be used to
+translate emacs filenames and lisp filenames.
+
+TO-LISP will be passed the filename of an emacs buffer and must
+return a string which the underlying lisp understandas as a
+pathname. FROM-LISP will be passed a pathname as returned by the
+underlying lisp and must return something that emacs will
+understand as a filename (this string will be passed to
+find-file).
+
+This list will be traversed in order, so multiple matching
+regexps are possible.
+
+Example:
+
+Assuming you run emacs locally and connect to slime running on
+the machine 'soren' and you can connect with the username
+'animaliter':
+
+ (push (list \"^soren$\"
+ (lambda (emacs-filename)
+ (subseq emacs-filename (length \"/ssh:animaliter at soren:\")))
+ (lambda (lisp-filename)
+ (concat \"/ssh:animaliter at soren:\" lisp-filename)))
+ slime-filename-translations)
+
+See also `slime-create-filename-translator'."
+ :type '(repeat (list :tag "Host description"
+ (regexp :tag "Hostname regexp")
+ (function :tag "To lisp function")
+ (function :tag "From lisp function")))
+ :group 'slime-lisp)
+
+(defcustom slime-enable-evaluate-in-emacs nil
+ "*If non-nil, the inferior Lisp can evaluate arbitrary forms in Emacs.
+The default is nil, as this feature can be a security risk."
+ :type '(boolean)
+ :group 'slime-lisp)
+
+;;;;; slime-mode
+
+(defgroup slime-mode nil
+ "Settings for slime-mode Lisp source buffers."
+ :prefix "slime-"
+ :group 'slime)
+
+(defcustom slime-edit-definition-fallback-function nil
+ "Function to call when edit-definition fails to find the source itself.
+The function is called with the definition name, a string, as its argument.
+
+If you want to fallback on TAGS you can set this to `find-tag',
+`slime-find-tag-if-tags-table-visited', or
+`slime-edit-definition-with-etags'."
+ :type 'symbol
+ :group 'slime-mode-mode
+ :options '(nil
+ slime-edit-definition-with-etags
+ slime-find-tag-if-tags-table-visited
+ find-tag))
+
+(defcustom slime-complete-symbol-function 'slime-simple-complete-symbol
+ "*Function to perform symbol completion."
+ :group 'slime-mode
+ :type '(choice (const :tag "Simple" slime-simple-complete-symbol)
+ (const :tag "Compound" slime-complete-symbol*)
+ (const :tag "Fuzzy" slime-fuzzy-complete-symbol)))
+
+(defcustom slime-when-complete-filename-expand nil
+ "Use comint-replace-by-expanded-filename instead of comint-dynamic-complete-as-filename to complete file names"
+ :group 'slime-mode
+ :type 'boolean)
+
+(defcustom slime-space-information-p t
+ "Have the SPC key offer arglist information."
+ :type 'boolean
+ :group 'slime-mode)
+
+;;;;; slime-mode-faces
+
+(defgroup slime-mode-faces nil
+ "Faces in slime-mode source code buffers."
+ :prefix "slime-"
+ :group 'slime-mode)
+
+(defun slime-underline-color (color)
+ "Return a legal value for the :underline face attribute based on COLOR."
+ ;; In XEmacs the :underline attribute can only be a boolean.
+ ;; In GNU it can be the name of a colour.
+ (if (featurep 'xemacs)
+ (if color t nil)
+ color))
+
+(defface slime-error-face
+ `((((class color) (background light))
+ (:underline ,(slime-underline-color "red")))
+ (((class color) (background dark))
+ (:underline ,(slime-underline-color "red")))
+ (t (:underline t)))
+ "Face for errors from the compiler."
+ :group 'slime-mode-faces)
+
+(defface slime-warning-face
+ `((((class color) (background light))
+ (:underline ,(slime-underline-color "orange")))
+ (((class color) (background dark))
+ (:underline ,(slime-underline-color "coral")))
+ (t (:underline t)))
+ "Face for warnings from the compiler."
+ :group 'slime-mode-faces)
+
+(defface slime-style-warning-face
+ `((((class color) (background light))
+ (:underline ,(slime-underline-color "brown")))
+ (((class color) (background dark))
+ (:underline ,(slime-underline-color "gold")))
+ (t (:underline t)))
+ "Face for style-warnings from the compiler."
+ :group 'slime-mode-faces)
+
+(defface slime-note-face
+ `((((class color) (background light))
+ (:underline ,(slime-underline-color "brown4")))
+ (((class color) (background dark))
+ (:underline ,(slime-underline-color "light goldenrod")))
+ (t (:underline t)))
+ "Face for notes from the compiler."
+ :group 'slime-mode-faces)
+
+(defun slime-face-inheritance-possible-p ()
+ "Return true if the :inherit face attribute is supported."
+ (assq :inherit custom-face-attributes))
+
+(defface slime-highlight-face
+ (if (slime-face-inheritance-possible-p)
+ '((t (:inherit highlight :underline nil)))
+ '((((class color) (background light))
+ (:background "darkseagreen2"))
+ (((class color) (background dark))
+ (:background "darkolivegreen"))
+ (t (:inverse-video t))))
+ "Face for compiler notes while selected."
+ :group 'slime-mode-faces)
+
+;;;;; sldb
+
+(defgroup slime-debugger nil
+ "Backtrace options and fontification."
+ :prefix "sldb-"
+ :group 'slime)
+
+(defmacro define-sldb-faces (&rest faces)
+ "Define the set of SLDB faces.
+Each face specifiation is (NAME DESCRIPTION &optional PROPERTIES).
+NAME is a symbol; the face will be called sldb-NAME-face.
+DESCRIPTION is a one-liner for the customization buffer.
+PROPERTIES specifies any default face properties."
+ `(progn ,@(loop for face in faces
+ collect `(define-sldb-face , at face))))
+
+(defmacro define-sldb-face (name description &optional default)
+ (let ((facename (intern (format "sldb-%s-face" (symbol-name name)))))
+ `(defface ,facename
+ (list (list t ,default))
+ ,(format "Face for %s." description)
+ :group 'slime-debugger)))
+
+(define-sldb-faces
+ (topline "the top line describing the error")
+ (condition "the condition class")
+ (section "the labels of major sections in the debugger buffer")
+ (frame-label "backtrace frame numbers")
+ (restart-type "restart names."
+ (if (slime-face-inheritance-possible-p)
+ '(:inherit font-lock-keyword-face)))
+ (restart "restart descriptions")
+ (restart-number "restart numbers (correspond to keystrokes to invoke)"
+ '(:bold t))
+ (frame-line "function names and arguments in the backtrace")
+ (detailed-frame-line
+ "function names and arguments in a detailed (expanded) frame")
+ (local-name "local variable names")
+ (local-value "local variable values")
+ (catch-tag "catch tags"))
+
+;;;;; slime-repl
+
+(defgroup slime-repl nil
+ "The Read-Eval-Print Loop (*slime-repl* buffer)."
+ :prefix "slime-repl-"
+ :group 'slime)
+
+(defcustom slime-repl-shortcut-dispatch-char ?\,
+ "Character used to distinguish repl commands from lisp forms."
+ :type '(character)
+ :group 'slime-repl)
+
+(defcustom slime-repl-only-save-lisp-buffers t
+ "When T we only attempt to save lisp-mode file buffers. When
+ NIL slime will attempt to save all buffers (as per
+ save-some-buffers). This applies to all ASDF related repl
+ shortcuts."
+ :type '(boolean)
+ :group 'slime-repl)
+
+(defcustom slime-repl-return-behaviour :send-if-complete
+ "Keyword specifying how slime-repl-return behaves when the
+ point is on a lisp expression (as opposed to being on a
+ previous output).
+
+Currently only two values are supported:
+
+:send-if-complete - If the current expression is complete, as per
+slime-input-complete-p, it is sent to the underlying lisp,
+otherwise a newline is inserted. The current value of (point) has
+no effect.
+
+:send-only-if-after-complete - If the current expression is complete
+and point is after the expression it is sent, otherwise a newline
+is inserted."
+ :type '(choice (const :tag "Send if complete" :value :send-if-complete)
+ (const :tag "Send only if after complete" :value :send-only-if-after-complete))
+ :group 'slime-repl)
+
+
+(defface slime-repl-prompt-face
+ (if (slime-face-inheritance-possible-p)
+ '((t (:inherit font-lock-keyword-face)))
+ '((((class color) (background light)) (:foreground "Purple"))
+ (((class color) (background dark)) (:foreground "Cyan"))
+ (t (:weight bold))))
+ "Face for the prompt in the SLIME REPL."
+ :group 'slime-repl)
+
+(defface slime-repl-output-face
+ (if (slime-face-inheritance-possible-p)
+ '((t (:inherit font-lock-string-face)))
+ '((((class color) (background light)) (:foreground "RosyBrown"))
+ (((class color) (background dark)) (:foreground "LightSalmon"))
+ (t (:slant italic))))
+ "Face for Lisp output in the SLIME REPL."
+ :group 'slime-repl)
+
+(defface slime-repl-input-face
+ '((t (:bold t)))
+ "Face for previous input in the SLIME REPL."
+ :group 'slime-repl)
+
+(defface slime-repl-result-face
+ '((t ()))
+ "Face for the result of an evaluation in the SLIME REPL."
+ :group 'slime-repl)
+
+(defcustom slime-repl-history-file "~/.slime-history.eld"
+ "File to save the persistent REPL history to."
+ :type 'string
+ :group 'slime-repl)
+
+(defcustom slime-repl-history-size 200
+ "*Maximum number of lines for persistent REPL history."
+ :type 'integer
+ :group 'slime-repl)
+
+
+;;;; Minor modes
+
+;;;;; slime-mode
+
+(define-minor-mode slime-mode
+ "\\<slime-mode-map>\
+SLIME: The Superior Lisp Interaction Mode for Emacs (minor-mode).
+
+Commands to compile the current buffer's source file and visually
+highlight any resulting compiler notes and warnings:
+\\[slime-compile-and-load-file] - Compile and load the current buffer's file.
+\\[slime-compile-file] - Compile (but not load) the current buffer's file.
+\\[slime-compile-defun] - Compile the top-level form at point.
+
+Commands for visiting compiler notes:
+\\[slime-next-note] - Goto the next form with a compiler note.
+\\[slime-previous-note] - Goto the previous form with a compiler note.
+\\[slime-remove-notes] - Remove compiler-note annotations in buffer.
+
+Finding definitions:
+\\[slime-edit-definition] - Edit the definition of the function called at point.
+\\[slime-pop-find-definition-stack] - Pop the definition stack to go back from a definition.
+
+Documentation commands:
+\\[slime-describe-symbol] - Describe symbol.
+\\[slime-apropos] - Apropos search.
+\\[slime-disassemble-symbol] - Disassemble a function.
+
+Evaluation commands:
+\\[slime-eval-defun] - Evaluate top-level from containing point.
+\\[slime-eval-last-expression] - Evaluate sexp before point.
+\\[slime-pprint-eval-last-expression] - Evaluate sexp before point, pretty-print result.
+
+Full set of commands:
+\\{slime-mode-map}"
+ nil
+ nil
+ ;; Fake binding to coax `define-minor-mode' to create the keymap
+ '((" " 'undefined)))
+
+(make-variable-buffer-local
+ (defvar slime-modeline-package nil
+ "The Lisp package to show in the modeline.
+This is automatically updated based on the buffer/point."))
+
+(defun slime-update-modeline-package ()
+ (ignore-errors
+ (when (and slime-update-modeline-package
+ (memq major-mode slime-lisp-modes)
+ slime-mode)
+ (let ((package (slime-current-package)))
+ (when package
+ (setq slime-modeline-package
+ (slime-pretty-package-name package)))))))
+
+(defun slime-pretty-package-name (name)
+ "Return a pretty version of a package name NAME."
+ (let ((name (cond ((string-match "^#?:\\(.*\\)$" name)
+ (match-string 1 name))
+ ((string-match "^\"\\(.*\\)\"$" name)
+ (match-string 1 name))
+ (t name))))
+ (format "%s" (read name))))
+
+(defun slime-pretty-find-buffer-package ()
+ "Return a prettied version of `slime-find-buffer-package'."
+ (let ((p (slime-find-buffer-package)))
+ (and p (slime-pretty-package-name p))))
+
+(when slime-update-modeline-package
+ (run-with-idle-timer 0.2 0.2 'slime-update-modeline-package))
+
+;; Setup the mode-line to say when we're in slime-mode, and which CL
+;; package we think the current buffer belongs to.
+(add-to-list 'minor-mode-alist
+ '(slime-mode
+ (" Slime"
+ ((slime-modeline-package (":" slime-modeline-package) "")
+ slime-state-name))))
+
+(defun slime-input-complete-p (start end)
+ "Return t if the region from START to END contains a complete sexp."
+ (save-excursion
+ (goto-char start)
+ (cond ((looking-at "\\s *['`#]?[(\"]")
+ (ignore-errors
+ (save-restriction
+ (narrow-to-region start end)
+ ;; Keep stepping over blanks and sexps until the end of
+ ;; buffer is reached or an error occurs. Tolerate extra
+ ;; close parens.
+ (loop do (skip-chars-forward " \t\r\n)")
+ until (eobp)
+ do (forward-sexp))
+ t)))
+ (t t))))
+
+
+;;;;; Key bindings
+
+;; See `slime-define-key' below for keyword meanings.
+(defvar slime-keys
+ '(;; Compiler notes
+ ("\M-p" slime-previous-note)
+ ("\M-n" slime-next-note)
+ ("\M-c" slime-remove-notes :prefixed t)
+ ("\C-k" slime-compile-and-load-file :prefixed t)
+ ("\M-k" slime-compile-file :prefixed t)
+ ("\C-c" slime-compile-defun :prefixed t)
+ ("\C-l" slime-load-file :prefixed t)
+ ;; Editing/navigating
+ ("\M-\C-i" slime-complete-symbol :inferior t)
+ ("\C-i" slime-complete-symbol :prefixed t :inferior t)
+ ("\M-." slime-edit-definition :inferior t :sldb t)
+ ("\C-x4." slime-edit-definition-other-window :inferior t :sldb t)
+ ("\C-x5." slime-edit-definition-other-frame :inferior t :sldb t)
+ ("\M-," slime-pop-find-definition-stack :inferior t :sldb t)
+ ;; Evaluating
+ ("\C-x\C-e" slime-eval-last-expression :inferior t)
+ ("\C-x\M-e" slime-eval-last-expression-display-output :inferior t)
+ ("\C-p" slime-pprint-eval-last-expression :prefixed t :inferior t)
+ ("\C-r" slime-eval-region :prefixed t :inferior t)
+ ("\C-\M-x" slime-eval-defun)
+ (":" slime-interactive-eval :prefixed t :sldb t)
+ ("\C-e" slime-interactive-eval :prefixed t :sldb t :inferior t)
+ ("\C-y" slime-call-defun :prefixed t)
+ ("E" slime-edit-value :prefixed t :sldb t :inferior t)
+ ("\C-z" slime-switch-to-output-buffer :prefixed t :sldb t)
+ ("\C-b" slime-interrupt :prefixed t :inferior t :sldb t)
+ ("\M-g" slime-quit :prefixed t :inferior t :sldb t)
+ ;; Documentation
+ (" " slime-space :inferior t)
+ ("\C-f" slime-describe-function :prefixed t :inferior t :sldb t)
+ ("\M-d" slime-disassemble-symbol :prefixed t :inferior t :sldb t)
+ ("\C-t" slime-toggle-trace-fdefinition :prefixed t :sldb t)
+ ("\C-u" slime-undefine-function :prefixed t)
+ ("\C-m" slime-macroexpand-1 :prefixed t :inferior t)
+ ("\M-m" slime-macroexpand-all :prefixed t :inferior t)
+ ("\M-0" slime-restore-window-configuration :prefixed t :inferior t)
+ ([(control meta ?\.)] slime-next-location :inferior t)
+ ("~" slime-sync-package-and-default-directory :prefixed t :inferior t)
+ ("\M-p" slime-repl-set-package :prefixed t :inferior t)
+ ;; Cross reference
+ ("<" slime-list-callers :prefixed t :inferior t :sldb t)
+ (">" slime-list-callees :prefixed t :inferior t :sldb t)
+ ;; "Other"
+ ("\I" slime-inspect :prefixed t :inferior t :sldb t)
+ ("\C-]" slime-close-all-parens-in-sexp :prefixed t :inferior t :sldb t)
+ ("\C-xt" slime-list-threads :prefixed t :inferior t :sldb t)
+ ("\C-xc" slime-list-connections :prefixed t :inferior t :sldb t)
+ ;; ;; Shadow unwanted bindings from inf-lisp
+ ;; ("\C-a" slime-nop :prefixed t :inferior t :sldb t)
+ ;; ("\C-v" slime-nop :prefixed t :inferior t :sldb t)
+ ))
+
+(defun slime-nop ()
+ "The null command. Used to shadow currently-unused keybindings."
+ (interactive)
+ (call-interactively 'undefined))
+
+(defvar slime-doc-map (make-sparse-keymap)
+ "Keymap for documentation commands. Bound to a prefix key.")
+
+(defvar slime-doc-bindings
+ '((?a slime-apropos)
+ (?z slime-apropos-all)
+ (?p slime-apropos-package)
+ (?d slime-describe-symbol)
+ (?f slime-describe-function)
+ (?h slime-hyperspec-lookup)
+ (?~ common-lisp-hyperspec-format)))
+
+(defvar slime-who-map (make-sparse-keymap)
+ "Keymap for who-xref commands. Bound to a prefix key.")
+
+(defvar slime-who-bindings
+ '((?c slime-who-calls)
+ (?w slime-calls-who)
+ (?r slime-who-references)
+ (?b slime-who-binds)
+ (?s slime-who-sets)
+ (?m slime-who-macroexpands)
+ (?a slime-who-specializes)))
+
+;; Maybe a good idea, maybe not..
+(defvar slime-prefix-key "\C-c"
+ "The prefix key to use in SLIME keybinding sequences.")
+
+(defun* slime-define-key (key command &key prefixed inferior)
+ "Define a keybinding of KEY for COMMAND.
+If PREFIXED is non-nil, `slime-prefix-key' is prepended to KEY."
+ (when prefixed
+ (setq key (concat slime-prefix-key key)))
+ (define-key slime-mode-map key command))
+
+(defun slime-init-keymaps ()
+ "(Re)initialize the keymaps for `slime-mode'."
+ (interactive)
+ (loop for (key command . keys) in slime-keys
+ do (apply #'slime-define-key key command :allow-other-keys t keys))
+ ;; Documentation
+ (setq slime-doc-map (make-sparse-keymap))
+ (loop for (key command) in slime-doc-bindings
+ do (progn
+ ;; We bind both unmodified and with control.
+ (define-key slime-doc-map (vector key) command)
+ (unless (equal key ?h) ; But don't bind C-h
+ (let ((modified (slime-control-modified-char key)))
+ (define-key slime-doc-map (vector modified) command)))))
+ ;; C-c C-d is the prefix for the doc map.
+ (slime-define-key "\C-d" slime-doc-map :prefixed t :inferior t)
+ ;; Who-xref
+ (setq slime-who-map (make-sparse-keymap))
+ (loop for (key command) in slime-who-bindings
+ do (progn
+ ;; We bind both unmodified and with control.
+ (define-key slime-who-map (vector key) command)
+ (let ((modified (slime-control-modified-char key)))
+ (define-key slime-who-map (vector modified) command))))
+ ;; C-c C-w is the prefix for the who-xref map.
+ (slime-define-key "\C-w" slime-who-map :prefixed t :inferior t))
+
+(defun slime-control-modified-char (char)
+ "Return the control-modified version of CHAR."
+ ;; Maybe better to just bitmask it?
+ (read (format "?\\C-%c" char)))
+
+(slime-init-keymaps)
+
+
+;;;; Setup initial `slime-mode' hooks
+
+(make-variable-buffer-local
+ (defvar slime-pre-command-actions nil
+ "List of functions to execute before the next Emacs command.
+This list of flushed between commands."))
+
+(defun slime-pre-command-hook ()
+ "Execute all functions in `slime-pre-command-actions', then NIL it."
+ (dolist (undo-fn slime-pre-command-actions)
+ (ignore-errors (funcall undo-fn)))
+ (setq slime-pre-command-actions nil))
+
+(defun slime-post-command-hook ()
+ (when (null pre-command-hook) ; sometimes this is lost
+ (add-hook 'pre-command-hook 'slime-pre-command-hook)))
+
+(defun slime-setup-command-hooks ()
+ "Setup a buffer-local `pre-command-hook' to call `slime-pre-command-hook'."
+ (add-local-hook 'pre-command-hook 'slime-pre-command-hook)
+ (add-local-hook 'post-command-hook 'slime-post-command-hook))
+
+
+;;;; Framework'ey bits
+;;;
+;;; This section contains some standard SLIME idioms: basic macros,
+;;; ways of showing messages to the user, etc. All the code in this
+;;; file should use these functions when applicable.
+;;;
+;;;;; Syntactic sugar
+
+(defmacro* when-let ((var value) &rest body)
+ "Evaluate VALUE, and if the result is non-nil bind it to VAR and
+evaluate BODY.
+
+\(fn (VAR VALUE) &rest BODY)"
+ `(let ((,var ,value))
+ (when ,var , at body)))
+
+(put 'when-let 'lisp-indent-function 1)
+
+(defmacro with-lexical-bindings (variables &rest body)
+ "Execute BODY with VARIABLES in lexical scope."
+ `(lexical-let ,(mapcar (lambda (variable) (list variable variable))
+ variables)
+ , at body))
+
+(put 'with-lexical-bindings 'lisp-indent-function 1)
+
+(defmacro destructure-case (value &rest patterns)
+ "Dispatch VALUE to one of PATTERNS.
+A cross between `case' and `destructuring-bind'.
+The pattern syntax is:
+ ((HEAD . ARGS) . BODY)
+The list of patterns is searched for a HEAD `eq' to the car of
+VALUE. If one is found, the BODY is executed with ARGS bound to the
+corresponding values in the CDR of VALUE."
+ (let ((operator (gensym "op-"))
+ (operands (gensym "rand-"))
+ (tmp (gensym "tmp-")))
+ `(let* ((,tmp ,value)
+ (,operator (car ,tmp))
+ (,operands (cdr ,tmp)))
+ (case ,operator
+ ,@(mapcar (lambda (clause)
+ (if (eq (car clause) t)
+ `(t ,@(cdr clause))
+ (destructuring-bind ((op &rest rands) &rest body) clause
+ `(,op (destructuring-bind ,rands ,operands
+ . ,body)))))
+ patterns)
+ ,@(if (eq (caar (last patterns)) t)
+ '()
+ `((t (error "Elisp destructure-case failed: %S" ,tmp))))))))
+
+(put 'destructure-case 'lisp-indent-function 1)
+
+(defmacro slime-define-keys (keymap &rest key-command)
+ "Define keys in KEYMAP. Each KEY-COMMAND is a list of (KEY COMMAND)."
+ `(progn . ,(mapcar (lambda (k-c) `(define-key ,keymap . ,k-c))
+ key-command)))
+
+(put 'slime-define-keys 'lisp-indent-function 1)
+
+(defmacro* with-struct ((conc-name &rest slots) struct &body body)
+ "Like with-slots but works only for structs.
+\(fn (CONC-NAME &rest SLOTS) STRUCT &body BODY)"
+ (flet ((reader (slot) (intern (concat (symbol-name conc-name)
+ (symbol-name slot)))))
+ (let ((struct-var (gensym "struct")))
+ `(let ((,struct-var ,struct))
+ (symbol-macrolet
+ ,(mapcar (lambda (slot)
+ (etypecase slot
+ (symbol `(,slot (,(reader slot) ,struct-var)))
+ (cons `(,(first slot) (,(reader (second slot))
+ ,struct-var)))))
+ slots)
+ . ,body)))))
+
+(put 'with-struct 'lisp-indent-function 2)
+
+;;;;; Very-commonly-used functions
+
+(defvar slime-message-function 'message)
+
+;; Interface
+(defun slime-message (format &rest args)
+ "Like `message' but with special support for multi-line messages.
+Single-line messages use the echo area."
+ (apply slime-message-function format args))
+
+(when (or (featurep 'xemacs)
+ (= emacs-major-version 20))
+ (setq slime-message-function 'slime-format-display-message))
+
+(defun slime-format-display-message (format &rest args)
+ (slime-display-message (apply #'format format args) "*SLIME Note*"))
+
+(defun slime-display-message (message buffer-name)
+ "Display MESSAGE in the echo area or in BUFFER-NAME.
+Use the echo area if MESSAGE needs only a single line. If the MESSAGE
+requires more than one line display it in BUFFER-NAME and add a hook
+to `slime-pre-command-actions' to remove the window before the next
+command."
+ (when (get-buffer-window buffer-name) (delete-windows-on buffer-name))
+ (cond ((or (string-match "\n" message)
+ (> (length message) (1- (frame-width))))
+ (lexical-let ((buffer (get-buffer-create buffer-name)))
+ (with-current-buffer buffer
+ (erase-buffer)
+ (insert message)
+ (goto-char (point-min))
+ (let ((win (slime-create-message-window)))
+ (set-window-buffer win (current-buffer))
+ (shrink-window-if-larger-than-buffer
+ (display-buffer (current-buffer)))))
+ (push (lambda () (delete-windows-on buffer) (bury-buffer buffer))
+ slime-pre-command-actions)))
+ (t (message "%s" message))))
+
+(defun slime-create-message-window ()
+ "Create a window at the bottom of the frame, above the minibuffer."
+ (let ((previous (previous-window (minibuffer-window))))
+ (when (<= (window-height previous) (* 2 window-min-height))
+ (save-selected-window
+ (select-window previous)
+ (enlarge-window (- (1+ (* 2 window-min-height))
+ (window-height previous)))))
+ (split-window previous)))
+
+(defvar slime-background-message-function 'slime-display-oneliner)
+
+;; Interface
+(defun slime-background-message (format-string &rest format-args)
+ "Display a message in passing.
+This is like `slime-message', but less distracting because it
+will never pop up a buffer or display multi-line messages.
+It should be used for \"background\" messages such as argument lists."
+ (apply slime-background-message-function format-string format-args))
+
+(defun slime-display-oneliner (format-string &rest format-args)
+ (let* ((msg (apply #'format format-string format-args)))
+ (unless (minibuffer-window-active-p (minibuffer-window))
+ (message "%s" (slime-oneliner msg)))))
+
+(defun slime-oneliner (string)
+ "Return STRING truncated to fit in a single echo-area line."
+ (substring string 0 (min (length string)
+ (or (position ?\n string) most-positive-fixnum)
+ (1- (frame-width)))))
+
+;; Interface
+(defun slime-set-truncate-lines ()
+ "Apply `slime-truncate-lines' to the current buffer."
+ (when slime-truncate-lines
+ (set (make-local-variable 'truncate-lines) t)))
+
+;; Interface
+(defun slime-read-package-name (prompt &optional initial-value)
+ "Read a package name from the minibuffer, prompting with PROMPT."
+ (let ((completion-ignore-case t))
+ (completing-read prompt (slime-bogus-completion-alist
+ (slime-eval
+ `(swank:list-all-package-names t)))
+ nil t initial-value)))
+
+;; Interface
+(defun slime-read-symbol-name (prompt &optional query)
+ "Either read a symbol name or choose the one at point.
+The user is prompted if a prefix argument is in effect, if there is no
+symbol at point, or if QUERY is non-nil.
+
+This function avoids mistaking the REPL prompt for a symbol."
+ (cond ((or current-prefix-arg query (not (slime-symbol-name-at-point)))
+ (slime-read-from-minibuffer prompt (slime-symbol-name-at-point)))
+ (t (slime-symbol-name-at-point))))
+
+;; Interface
+(defmacro slime-propertize-region (props &rest body)
+ "Execute BODY and add PROPS to all the text it inserts.
+More precisely, PROPS are added to the region between the point's
+positions before and after executing BODY."
+ (let ((start (gensym)))
+ `(let ((,start (point)))
+ (prog1 (progn , at body)
+ (add-text-properties ,start (point) ,props)))))
+
+(put 'slime-propertize-region 'lisp-indent-function 1)
+
+;; Interface
+(defsubst slime-insert-propertized (props &rest args)
+ "Insert all ARGS and then add text-PROPS to the inserted text."
+ (slime-propertize-region props (apply #'insert args)))
+
+(defmacro slime-with-rigid-indentation (level &rest body)
+ "Execute BODY and then rigidly indent its text insertions.
+Assumes all insertions are made at point."
+ (let ((start (gensym)) (l (gensym)))
+ `(let ((,start (point)) (,l ,(or level '(current-column))))
+ (prog1 (progn , at body)
+ (slime-indent-rigidly ,start (point) ,l)))))
+
+(put 'slime-with-rigid-indentation 'lisp-indent-function 1)
+
+(defun slime-indent-rigidly (start end column)
+ ;; Similar to `indent-rigidly' but doesn't inherit text props.
+ (save-excursion
+ (goto-char end)
+ (beginning-of-line)
+ (while (and (<= start (point))
+ (progn
+ (save-excursion (insert-char ?\ column))
+ (zerop (forward-line -1)))))))
+
+(defun slime-insert-indented (&rest strings)
+ "Insert all arguments rigidly indented."
+ (slime-with-rigid-indentation nil
+ (apply #'insert strings)))
+
+(defun slime-curry (fun &rest args)
+ `(lambda (&rest more) (apply ',fun (append ',args more))))
+
+(defun slime-rcurry (fun &rest args)
+ `(lambda (&rest more) (apply ',fun (append more ',args))))
+
+;;;;; Snapshots of current Emacs state
+
+;;; Window configurations do not save (and hence not restore)
+;;; any narrowing that could be applied to a buffer.
+;;;
+;;; For this purpose, we introduce a superset of a window
+;;; configuration that does include the necessary information to
+;;; properly restore narrowing.
+;;;
+;;; We call this superset an Emacs Snapshot.
+
+(defstruct (slime-narrowing-configuration
+ (:conc-name slime-narrowing-configuration.))
+ narrowedp beg end)
+
+(defstruct (slime-emacs-snapshot (:conc-name slime-emacs-snapshot.))
+ window-configuration narrowing-configuration)
+
+(defun slime-current-narrowing-configuration (&optional buffer)
+ (with-current-buffer (or buffer (current-buffer))
+ (make-slime-narrowing-configuration :narrowedp (slime-buffer-narrowed-p)
+ :beg (point-min-marker)
+ :end (point-max-marker))))
+
+(defun slime-set-narrowing-configuration (narrowing-cfg)
+ (when (slime-narrowing-configuration.narrowedp narrowing-cfg)
+ (narrow-to-region (slime-narrowing-configuration.beg narrowing-cfg)
+ (slime-narrowing-configuration.end narrowing-cfg))))
+
+(defun slime-current-emacs-snapshot (&optional frame)
+ "Returns a snapshot of the current state of FRAME, or the
+currently active frame if FRAME is not given respectively."
+ (with-current-buffer
+ (if frame
+ (window-buffer (frame-selected-window (selected-frame)))
+ (current-buffer))
+ (make-slime-emacs-snapshot
+ :window-configuration (current-window-configuration frame)
+ :narrowing-configuration (slime-current-narrowing-configuration))))
+
+(defun slime-set-emacs-snapshot (snapshot)
+ "Restores the state of Emacs according to the information saved
+in SNAPSHOT."
+ (let ((window-cfg (slime-emacs-snapshot.window-configuration snapshot))
+ (narrowing-cfg (slime-emacs-snapshot.narrowing-configuration snapshot)))
+ (set-window-configuration window-cfg) ; restores previously current buffer.
+ (slime-set-narrowing-configuration narrowing-cfg)))
+
+(defun slime-current-emacs-snapshot-fingerprint (&optional frame)
+ "Return a fingerprint of the current emacs snapshot.
+Fingerprints are `equalp' if and only if they represent window
+configurations that are very similar (same windows and buffers.)
+
+Unlike real window-configuration objects, fingerprints are not
+sensitive to the point moving and they can't be restored."
+ (mapcar (lambda (window) (list window (window-buffer window)))
+ (slime-frame-windows frame)))
+
+(defun slime-frame-windows (&optional frame)
+ "Return the list of windows in FRAME."
+ (loop with last-window = (previous-window (frame-first-window frame))
+ for window = (frame-first-window frame) then (next-window window)
+ collect window
+ until (eq window last-window)))
+
+
+(defmacro save-restriction-if-possible (&rest body)
+ "Very similiarly to `save-restriction'. The only difference is
+that it's not enforcing the restriction as strictly: It's only
+enforced if `point' was not moved outside of the restriction
+after executing BODY.
+
+Example:
+
+ (progn (goto-line 1000)
+ (narrow-to-page)
+ (save-restriction-if-possible (widen) (goto-line 999)))
+
+ In this case, the buffer is narrowed to the current page, and
+ point is on line 999.
+
+ (progn (goto-char 1000)
+ (narrow-to-page)
+ (save-restriction-if-possible (widen) (goto-line 1)))
+
+ Whereas in this case, the buffer is widened and point is on
+ line 1."
+ (let ((gcfg (gensym "NARROWING-CFG+"))
+ (gbeg (gensym "OLDBEG+"))
+ (gend (gensym "OLDEND+")))
+ `(let ((,gcfg (slime-current-narrowing-configuration)))
+ (unwind-protect (progn , at body)
+ (let ((,gbeg (slime-narrowing-configuration.beg ,gcfg))
+ (,gend (slime-narrowing-configuration.end ,gcfg)))
+ (when (and (>= (point) ,gbeg) (<= (point) ,gend))
+ (slime-set-narrowing-configuration ,gcfg)))))))
+
+(put 'save-restriction-if-possible 'lisp-indent-function 0)
+
+;;;;; Temporary popup buffers
+
+(make-variable-buffer-local
+ (defvar slime-temp-buffer-saved-emacs-snapshot nil
+ "The snapshot of the current state in Emacs before the temp-buffer
+was displayed, so that this state can be restored later on.
+Buffer local in temp-buffers."))
+
+(make-variable-buffer-local
+ (defvar slime-temp-buffer-saved-fingerprint nil
+ "The emacs snapshot \"fingerprint\" after displaying the buffer."))
+
+;; Interface
+(defun* slime-get-temp-buffer-create (name &key mode noselectp reusep
+ emacs-snapshot)
+ "Return a fresh temporary buffer called NAME in MODE.
+The buffer also uses the minor-mode `slime-temp-buffer-mode'. Pressing
+`q' in the buffer will restore the window configuration to the way it
+is when the buffer was created, i.e. when this function was called.
+
+If NOSELECTP is true, then the buffer is shown by `display-buffer',
+otherwise it is shown and selected by `pop-to-buffer'.
+
+If REUSEP is true and a buffer does already exist with name NAME,
+then the buffer will be reused instead of being killed.
+
+If EMACS-SNAPSHOT is non-NIL, it's used to restore the previous
+state of Emacs after closing the temporary buffer. Otherwise, the
+current state will be saved and later restored.
+"
+ (let ((snapshot (or emacs-snapshot (slime-current-emacs-snapshot)))
+ (buffer (get-buffer name)))
+ (when (and buffer (not reusep))
+ (kill-buffer name)
+ (setq buffer nil))
+ (with-current-buffer (or buffer (get-buffer-create name))
+ (when mode
+ (let ((original-configuration slime-temp-buffer-saved-emacs-snapshot)
+ (original-fingerprint slime-temp-buffer-saved-fingerprint))
+ (funcall mode)
+ (setq slime-temp-buffer-saved-emacs-snapshot original-configuration)
+ (setq slime-temp-buffer-saved-fingerprint original-fingerprint)))
+ (slime-temp-buffer-mode 1)
+ (let ((window (get-buffer-window (current-buffer))))
+ (if window
+ (unless noselectp
+ (select-window window))
+ (progn
+ (if noselectp
+ (display-buffer (current-buffer) t)
+ (pop-to-buffer (current-buffer))
+ (selected-window))
+ (setq slime-temp-buffer-saved-emacs-snapshot snapshot)
+ (setq slime-temp-buffer-saved-fingerprint
+ (slime-current-emacs-snapshot-fingerprint)))))
+ (current-buffer))))
+
+;; Interface
+(defmacro* slime-with-output-to-temp-buffer ((name &key mode reusep)
+ package &rest body)
+ "Similar to `with-output-to-temp-buffer'.
+Also saves the current state of Emacs (window configuration &c),
+and inherits the current `slime-connection' in a buffer-local
+variable. Cf. `slime-get-temp-buffer-create'"
+ `(let ((connection (slime-connection))
+ (standard-output (slime-get-temp-buffer-create ,name :mode ',mode
+ :reusep ,reusep)))
+ (prog1 (with-current-buffer standard-output
+ ;; set explicitely to NIL in case the buffer got reused. (REUSEP)
+ (let ((buffer-read-only nil)) , at body))
+ (with-current-buffer standard-output
+ (setq slime-buffer-connection connection)
+ (setq slime-buffer-package ,package)
+ (goto-char (point-min))
+ (slime-mode 1)
+ (set-syntax-table lisp-mode-syntax-table)
+ (setq buffer-read-only t)))))
+
+(put 'slime-with-output-to-temp-buffer 'lisp-indent-function 2)
+
+(define-minor-mode slime-temp-buffer-mode
+ "Mode for displaying read only stuff"
+ nil
+ " temp"
+ '(("q" . slime-temp-buffer-quit)))
+
+;; Interface
+(defun slime-temp-buffer-quit (&optional kill-buffer-p)
+ "Get rid of the current (temp) buffer without asking. Restore the
+window configuration unless it was changed since we last activated the buffer."
+ (interactive)
+ (let ((snapshot slime-temp-buffer-saved-emacs-snapshot)
+ (temp-buffer (current-buffer)))
+ (setq slime-temp-buffer-saved-emacs-snapshot nil)
+ (if (and snapshot (equalp (slime-current-emacs-snapshot-fingerprint)
+ slime-temp-buffer-saved-fingerprint))
+ (slime-set-emacs-snapshot snapshot)
+ (bury-buffer))
+ (when kill-buffer-p
+ (kill-buffer temp-buffer))))
+
+;;;;; Filename translation
+;;;
+;;; Filenames passed between Emacs and Lisp should be translated using
+;;; these functions. This way users who run Emacs and Lisp on separate
+;;; machines have a chance to integrate file operations somehow.
+
+(defun slime-to-lisp-filename (filename)
+ "Translate the string FILENAME to a Lisp filename.
+See `slime-filename-translations'."
+ (funcall (first (slime-find-filename-translators (slime-machine-instance)))
+ (expand-file-name filename)))
+
+(defun slime-from-lisp-filename (filename)
+ "Translate the Lisp filename FILENAME to an Emacs filename.
+See `slime-filename-translations'."
+ (funcall (second (slime-find-filename-translators (slime-machine-instance)))
+ filename))
+
+(defun slime-find-filename-translators (hostname)
+ (cond ((and hostname slime-filename-translations)
+ (or (cdr (assoc-if (lambda (regexp) (string-match regexp hostname))
+ slime-filename-translations))
+ (error "No filename-translations for hostname: %s" hostname)))
+ (t (list #'identity #'identity))))
+
+
+;;;; Starting SLIME
+;;;
+;;; This section covers starting an inferior-lisp, compiling and
+;;; starting the server, initiating a network connection.
+
+;;;;; Entry points
+
+;; We no longer load inf-lisp, but we use this variable for backward
+;; compatibility.
+(defvar inferior-lisp-program "lisp"
+ "*Program name for invoking an inferior Lisp with for Inferior Lisp mode.")
+
+(defvar slime-lisp-implementations nil
+ "*A list of known Lisp implementations.
+The list should have the form:
+ ((NAME (PROGRAM PROGRAM-ARGS...) &key INIT CODING-SYSTEM) ...)
+
+NAME is a symbol for the implementation.
+PROGRAM and PROGRAM-ARGS are strings used to start the Lisp process.
+INIT is a function that should return a string to load and start
+ Swank. The function will be called with the PORT-FILENAME and ENCODING as
+ arguments. INIT defaults to `slime-init-command'.
+CODING-SYSTEM a symbol for the coding system. The default is
+ slime-net-coding-system
+
+Here's an example:
+ ((cmucl (\"/opt/cmucl/bin/lisp\" \"-quiet\") :init slime-init-command)
+ (acl (\"acl7\") :coding-system emacs-mule))")
+
+(defvar slime-default-lisp nil
+ "*The name of the default Lisp implementation.
+See `slime-lisp-implementations'")
+
+(defvar slime-lisp-host "127.0.0.1"
+ "The default hostname (or IP address) to connect to.")
+
+;; dummy definitions for the compiler
+(defvar slime-net-coding-system)
+(defvar slime-net-processes)
+(defvar slime-default-connection)
+
+(defun slime (&optional command coding-system)
+ "Start an inferior^_superior Lisp and connect to its Swank server."
+ (interactive)
+ (let ((inferior-lisp-program (or command inferior-lisp-program))
+ (slime-net-coding-system (or coding-system slime-net-coding-system)))
+ (slime-start* (slime-read-interactive-args))))
+
+(defvar slime-inferior-lisp-program-history '()
+ "History list of command strings. Used by `slime'.")
+
+(defun slime-read-interactive-args ()
+ "Return the list of args which should be passed to `slime-start'.
+
+The rules for selecting the arguments are rather complicated:
+
+- In the most common case, i.e. if there's no prefix-arg in
+ effect and if `slime-lisp-implementations' is nil, use
+ `inferior-lisp-program' as fallback.
+
+- If the table `slime-lisp-implementations' is non-nil use the
+ implementation with name `slime-default-lisp' or if that's nil
+ the first entry in the table.
+
+- If the prefix-arg is `-', prompt for one of the registered
+ lisps.
+
+- If the prefix-arg is positive, read the command to start the
+ process."
+ (let ((table slime-lisp-implementations))
+ (cond ((not current-prefix-arg) (slime-lisp-options))
+ ((eq current-prefix-arg '-)
+ (let ((key (completing-read
+ "Lisp name: " (mapcar (lambda (x)
+ (list (symbol-name (car x))))
+ table)
+ nil t)))
+ (slime-lookup-lisp-implementation table (intern key))))
+ (t
+ (destructuring-bind (program &rest program-args)
+ (split-string (read-string
+ "Run lisp: " inferior-lisp-program
+ 'slime-inferior-lisp-program-history))
+ (let ((coding-system
+ (if (eq 16 (prefix-numeric-value current-prefix-arg))
+ (read-coding-system "set slime-coding-system: "
+ slime-net-coding-system)
+ slime-net-coding-system)))
+ (list :program program :program-args program-args
+ :coding-system coding-system)))))))
+
+(defun slime-lisp-options (&optional name)
+ (let ((table slime-lisp-implementations))
+ (assert (or (not name) table))
+ (cond (table (slime-lookup-lisp-implementation slime-lisp-implementations
+ (or name slime-default-lisp
+ (car (car table)))))
+ (t (destructuring-bind (program &rest args)
+ (split-string inferior-lisp-program)
+ (list :program program :program-args args))))))
+
+(defun slime-lookup-lisp-implementation (table name)
+ (destructuring-bind (name (prog &rest args) &rest keys) (assoc name table)
+ (list* :name name :program prog :program-args args keys)))
+
+(defun* slime-start (&key (program inferior-lisp-program) program-args
+ directory
+ (coding-system slime-net-coding-system)
+ (init 'slime-init-command)
+ name
+ (buffer "*inferior-lisp*")
+ init-function)
+ (let ((args (list :program program :program-args program-args :buffer buffer
+ :coding-system coding-system :init init :name name
+ :init-function init-function)))
+ (slime-check-coding-system coding-system)
+ (when (slime-bytecode-stale-p)
+ (slime-urge-bytecode-recompile))
+ (let ((proc (slime-maybe-start-lisp program program-args
+ directory buffer)))
+ (slime-inferior-connect proc args)
+ (pop-to-buffer (process-buffer proc)))))
+
+(defun slime-start* (options)
+ (apply #'slime-start options))
+
+(defun slime-connect (host port &optional coding-system)
+ "Connect to a running Swank server."
+ (interactive (list (read-from-minibuffer "Host: " slime-lisp-host)
+ (read-from-minibuffer "Port: " "4005" nil t)))
+ (when (and (interactive-p) slime-net-processes
+ (y-or-n-p "Close old connections first? "))
+ (slime-disconnect))
+ (message "Connecting to Swank on port %S.." port)
+ (let ((coding-system (or coding-system slime-net-coding-system)))
+ (slime-check-coding-system coding-system)
+ (message "Connecting to Swank on port %S.." port)
+ (let* ((process (slime-net-connect host port coding-system))
+ (slime-dispatching-connection process))
+ (slime-setup-connection process))))
+
+(defun slime-start-and-load (filename &optional package)
+ "Start Slime, if needed, load the current file and set the package."
+ (interactive (list (expand-file-name (buffer-file-name))
+ (slime-find-buffer-package)))
+ (cond ((slime-connected-p)
+ (slime-load-file-set-package filename package))
+ (t
+ (slime-start-and-init (slime-lisp-options)
+ (slime-curry #'slime-start-and-load
+ filename package)))))
+
+(defun slime-start-and-init (options fun)
+ (let* ((rest (plist-get options :init-function))
+ (init (cond (rest `(lambda () (funcall ',rest) (funcall ',fun)))
+ (t fun))))
+ (slime-start* (plist-put (copy-list options) :init-function init))))
+
+(defun slime-load-file-set-package (filename package)
+ (let ((filename (slime-to-lisp-filename filename)))
+ (slime-eval-async `(swank:load-file-set-package ,filename ,package)
+ (lambda (package)
+ (when package
+ (slime-repl-set-package (second package)))))))
+
+;;;;; Start inferior lisp
+;;;
+;;; Here is the protocol for starting SLIME:
+;;;
+;;; 0. Emacs recompiles/reloads slime.elc if it exists and is stale.
+;;; 1. Emacs starts an inferior Lisp process.
+;;; 2. Emacs tells Lisp (via stdio) to load and start Swank.
+;;; 3. Lisp recompiles the Swank if needed.
+;;; 4. Lisp starts the Swank server and writes its TCP port to a temp file.
+;;; 5. Emacs reads the temp file to get the port and then connects.
+;;; 6. Emacs prints a message of warm encouragement for the hacking ahead.
+;;;
+;;; Between steps 2-5 Emacs polls for the creation of the temp file so
+;;; that it can make the connection. This polling may continue for a
+;;; fair while if Swank needs recompilation.
+
+(defvar slime-connect-retry-timer nil
+ "Timer object while waiting for an inferior-lisp to start.")
+
+;;; Recompiling bytecode:
+
+(defun slime-bytecode-stale-p ()
+ "Return true if slime.elc is older than slime.el."
+ (when-let (libfile (locate-library "slime"))
+ (let* ((basename (file-name-sans-extension libfile))
+ (sourcefile (concat basename ".el"))
+ (bytefile (concat basename ".elc")))
+ (and (file-exists-p bytefile)
+ (file-newer-than-file-p sourcefile bytefile)))))
+
+(defun slime-recompile-bytecode ()
+ "Recompile and reload slime.
+Warning: don't use this in XEmacs, it seems to crash it!"
+ (interactive)
+ (let ((sourcefile (concat (file-name-sans-extension (locate-library "slime"))
+ ".el")))
+ (byte-compile-file sourcefile t)))
+
+(defun slime-urge-bytecode-recompile ()
+ "Urge the user to recompile slime.elc.
+Return true if we have been given permission to continue."
+ (cond ((featurep 'xemacs)
+ ;; My XEmacs crashes and burns if I recompile/reload an elisp
+ ;; file from itself. So they have to do it themself.
+ (or (y-or-n-p "slime.elc is older than source. Continue? ")
+ (signal 'quit nil)))
+ ((y-or-n-p "slime.elc is older than source. Recompile first? ")
+ (slime-recompile-bytecode))
+ (t)))
+
+(defun slime-abort-connection ()
+ "Abort connection the current connection attempt."
+ (interactive)
+ (cond (slime-connect-retry-timer
+ (slime-cancel-connect-retry-timer)
+ (message "Cancelled connection attempt."))
+ (t (error "Not connecting"))))
+
+;;; Starting the inferior Lisp and loading Swank:
+
+(defun slime-maybe-start-lisp (program program-args directory buffer)
+ "Return a new or existing inferior lisp process."
+ (cond ((not (comint-check-proc buffer))
+ (slime-start-lisp program program-args directory buffer))
+ ((slime-reinitialize-inferior-lisp-p program program-args buffer)
+ (when-let (conn (find (get-buffer-process buffer) slime-net-processes
+ :key #'slime-inferior-process))
+ (slime-net-close conn))
+ (get-buffer-process buffer))
+ (t (slime-start-lisp program program-args
+ directory
+ (generate-new-buffer-name buffer)))))
+
+(defun slime-reinitialize-inferior-lisp-p (program program-args buffer)
+ (let ((args (slime-inferior-lisp-args (get-buffer-process buffer))))
+ (and (equal (plist-get args :program) program)
+ (equal (plist-get args :program-args) program-args)
+ (not (y-or-n-p "Create an additional *inferior-lisp*? ")))))
+
+(defun slime-start-lisp (program program-args directory buffer)
+ "Does the same as `inferior-lisp' but less ugly.
+Return the created process."
+ (with-current-buffer (get-buffer-create buffer)
+ (when directory
+ (cd (expand-file-name directory)))
+ (comint-mode)
+ (comint-exec (current-buffer) "inferior-lisp" program nil program-args)
+ (lisp-mode-variables t)
+ (let ((proc (get-buffer-process (current-buffer))))
+ (slime-set-query-on-exit-flag proc)
+ proc)))
+
+(defun slime-inferior-connect (process args)
+ "Start a Swank server in the inferior Lisp and connect."
+ (slime-delete-swank-port-file 'quiet)
+ (slime-start-swank-server process args)
+ (slime-read-port-and-connect process nil))
+
+(defvar slime-inferior-lisp-args nil
+ "A buffer local variable in the inferior proccess.")
+
+(defun slime-start-swank-server (process args)
+ "Start a Swank server on the inferior lisp."
+ (destructuring-bind (&key coding-system init &allow-other-keys) args
+ (with-current-buffer (process-buffer process)
+ (make-local-variable 'slime-inferior-lisp-args)
+ (setq slime-inferior-lisp-args args)
+ (let ((str (funcall init (slime-swank-port-file) coding-system)))
+ (goto-char (process-mark process))
+ (insert-before-markers str)
+ (process-send-string process str)))))
+
+(defun slime-inferior-lisp-args (process)
+ (with-current-buffer (process-buffer process)
+ slime-inferior-lisp-args))
+
+;; XXX load-server & start-server used to be separated. maybe that was better.
+(defun slime-init-command (port-filename coding-system)
+ "Return a string to initialize Lisp."
+ (let ((loader (if (file-name-absolute-p slime-backend)
+ slime-backend
+ (concat slime-path slime-backend)))
+ (encoding (slime-coding-system-cl-name coding-system)))
+ ;; Return a single form to avoid problems with buffered input.
+ (format "%S\n\n"
+ `(progn
+ (load ,(expand-file-name loader) :verbose t)
+ (funcall (read-from-string "swank:start-server")
+ ,port-filename
+ :coding-system ,encoding)))))
+
+(defun slime-swank-port-file ()
+ "Filename where the SWANK server writes its TCP port number."
+ (concat (file-name-as-directory
+ (cond ((fboundp 'temp-directory) (temp-directory))
+ ((boundp 'temporary-file-directory) temporary-file-directory)
+ (t "/tmp/")))
+ (format "slime.%S" (emacs-pid))))
+
+(defun slime-delete-swank-port-file (&optional quiet)
+ (condition-case data
+ (delete-file (slime-swank-port-file))
+ (error
+ (ecase quiet
+ ((nil) (signal (car data) (cdr data)))
+ (quiet)
+ (message (message "Unable to delete swank port file %S"
+ (slime-swank-port-file)))))))
+
+(defun slime-read-port-and-connect (inferior-process retries)
+ (slime-cancel-connect-retry-timer)
+ (slime-attempt-connection inferior-process retries 1))
+
+(defun slime-attempt-connection (process retries attempt)
+ ;; A small one-state machine to attempt a connection with
+ ;; timer-based retries.
+ (let ((file (slime-swank-port-file)))
+ (unless (active-minibuffer-window)
+ (message "Polling %S.. (Abort with `M-x slime-abort-connection'.)" file))
+ (unless (slime-connected-p)
+ (slime-set-state (format "[polling:%S]" attempt)))
+ (slime-cancel-connect-retry-timer)
+ (cond ((and (file-exists-p file)
+ (> (nth 7 (file-attributes file)) 0)) ; file size
+ (let ((port (slime-read-swank-port))
+ (args (slime-inferior-lisp-args process)))
+ (slime-delete-swank-port-file 'message)
+ (let ((c (slime-connect slime-lisp-host port
+ (plist-get args :coding-system))))
+ (slime-set-inferior-process c process))))
+ ((and retries (zerop retries))
+ (message "Failed to connect to Swank."))
+ (t
+ (when (and (file-exists-p file)
+ (zerop (nth 7 (file-attributes file))))
+ (message "(Zero length port file)")
+ ;; the file may be in the filesystem but not yet written
+ (unless retries (setq retries 3)))
+ (setq slime-connect-retry-timer
+ (run-with-timer 0.3 nil
+ #'slime-timer-call #'slime-attempt-connection
+ process (and retries (1- retries))
+ (1+ attempt)))))))
+
+(defun slime-timer-call (fun &rest args)
+ "Call function FUN with ARGS, reporting all errors.
+
+The default condition handler for timer functions (see
+`timer-event-handler') ignores errors."
+ (condition-case data
+ (apply fun args)
+ (error (debug nil (list "Error in timer" fun args data)))))
+
+(defun slime-cancel-connect-retry-timer ()
+ (when slime-connect-retry-timer
+ (cancel-timer slime-connect-retry-timer)
+ (setq slime-connect-retry-timer nil)))
+
+(defun slime-read-swank-port ()
+ "Read the Swank server port number from the `slime-swank-port-file'."
+ (save-excursion
+ (with-temp-buffer
+ (insert-file-contents (slime-swank-port-file))
+ (goto-char (point-min))
+ (let ((port (read (current-buffer))))
+ (assert (integerp port))
+ port))))
+
+(defun slime-hide-inferior-lisp-buffer ()
+ "Display the REPL buffer instead of the *inferior-lisp* buffer."
+ (let* ((buffer (if (slime-process)
+ (process-buffer (slime-process))))
+ (window (if buffer (get-buffer-window buffer)))
+ (repl-buffer (slime-output-buffer t))
+ (repl-window (get-buffer-window repl-buffer)))
+ (when buffer
+ (bury-buffer buffer))
+ (cond (repl-window
+ (when window
+ (delete-window window)))
+ (window
+ (set-window-buffer window repl-buffer))
+ (t
+ (pop-to-buffer repl-buffer)
+ (goto-char (point-max))))))
+
+;;; Words of encouragement
+
+(defun slime-user-first-name ()
+ (let ((name (if (string= (user-full-name) "")
+ (user-login-name)
+ (user-full-name))))
+ (string-match "^[^ ]*" name)
+ (capitalize (match-string 0 name))))
+
+(defvar slime-words-of-encouragement
+ `("Let the hacking commence!"
+ "Hacks and glory await!"
+ "Hack and be merry!"
+ "Your hacking starts... NOW!"
+ "May the source be with you!"
+ "Take this REPL, brother, and may it serve you well."
+ "Lemonodor-fame is but a hack away!"
+ ,(format "%s, this could be the start of a beautiful program."
+ (slime-user-first-name)))
+ "Scientifically-proven optimal words of hackerish encouragement.")
+
+(defun slime-random-words-of-encouragement ()
+ "Return a string of hackerish encouragement."
+ (eval (nth (random (length slime-words-of-encouragement))
+ slime-words-of-encouragement)))
+
+
+;;;; Networking
+;;;
+;;; This section covers the low-level networking: establishing
+;;; connections and encoding/decoding protocol messages.
+;;;
+;;; Each SLIME protocol message beings with a 3-byte length header
+;;; followed by an S-expression as text. The sexp must be readable
+;;; both by Emacs and by Common Lisp, so if it contains any embedded
+;;; code fragments they should be sent as strings.
+;;;
+;;; The set of meaningful protocol messages are not specified
+;;; here. They are defined elsewhere by the event-dispatching
+;;; functions in this file and in swank.lisp.
+
+(defvar slime-net-processes nil
+ "List of processes (sockets) connected to Lisps.")
+
+(defvar slime-net-process-close-hooks '()
+ "List of functions called when a slime network connection closes.
+The functions are called with the process as their argument.")
+
+(defun slime-secret ()
+ "Finds the magic secret from the user's home directory.
+Returns nil if the file doesn't exist or is empty; otherwise the first
+line of the file."
+ (condition-case err
+ (with-temp-buffer
+ (insert-file-contents "~/.slime-secret")
+ (goto-char (point-min))
+ (buffer-substring (point-min) (line-end-position)))
+ (file-error nil)))
+
+;;; Interface
+(defun slime-net-connect (host port coding-system)
+ "Establish a connection with a CL."
+ (let* ((inhibit-quit nil)
+ (proc (open-network-stream "SLIME Lisp" nil host port))
+ (buffer (slime-make-net-buffer " *cl-connection*")))
+ (push proc slime-net-processes)
+ (set-process-buffer proc buffer)
+ (set-process-filter proc 'slime-net-filter)
+ (set-process-sentinel proc 'slime-net-sentinel)
+ (slime-set-query-on-exit-flag proc)
+ (when (fboundp 'set-process-coding-system)
+ (slime-check-coding-system coding-system)
+ (set-process-coding-system proc coding-system coding-system))
+ (when-let (secret (slime-secret))
+ (slime-net-send secret proc))
+ proc))
+
+(defun slime-make-net-buffer (name)
+ "Make a buffer suitable for a network process."
+ (let ((buffer (generate-new-buffer name)))
+ (with-current-buffer buffer
+ (buffer-disable-undo))
+ buffer))
+
+(defun slime-set-query-on-exit-flag (process)
+ "Set PROCESS's query-on-exit-flag to `slime-kill-without-query-p'."
+ (when slime-kill-without-query-p
+ ;; avoid byte-compiler warnings
+ (let ((fun (if (fboundp 'set-process-query-on-exit-flag)
+ 'set-process-query-on-exit-flag
+ 'process-kill-without-query)))
+ (funcall fun process nil))))
+
+;;;;; Coding system madness
+
+(defvar slime-net-valid-coding-systems
+ '((iso-latin-1-unix nil "iso-latin-1-unix")
+ (iso-8859-1-unix nil "iso-latin-1-unix")
+ (binary nil "iso-latin-1-unix")
+ (utf-8-unix t "utf-8-unix")
+ (emacs-mule-unix t "emacs-mule-unix")
+ (euc-jp-unix t "euc-jp-unix"))
+ "A list of valid coding systems.
+Each element is of the form: (NAME MULTIBYTEP CL-NAME)")
+
+(defun slime-find-coding-system (name)
+ "Return the coding system for the symbol NAME.
+The result is either an element in `slime-net-valid-coding-systems'
+of nil."
+ (let* ((probe (assq name slime-net-valid-coding-systems)))
+ (if (and probe (if (fboundp 'check-coding-system)
+ (ignore-errors (check-coding-system (car probe)))
+ (eq (car probe) 'binary)))
+ probe)))
+
+(defvar slime-net-coding-system
+ (find-if 'slime-find-coding-system
+ '(iso-latin-1-unix iso-8859-1-unix binary))
+ "*Coding system used for network connections.
+See also `slime-net-valid-coding-systems'.")
+
+(defun slime-check-coding-system (coding-system)
+ "Signal an error if CODING-SYSTEM isn't a valid coding system."
+ (interactive)
+ (let ((props (slime-find-coding-system coding-system)))
+ (unless props
+ (error "Invalid slime-net-coding-system: %s. %s"
+ coding-system (mapcar #'car slime-net-valid-coding-systems)))
+ (when (and (second props) (boundp 'default-enable-multibyte-characters))
+ (assert default-enable-multibyte-characters))
+ t))
+
+(defcustom slime-repl-history-file-coding-system
+ (cond ((slime-find-coding-system 'utf-8-unix) 'utf-8-unix)
+ (t slime-net-coding-system))
+ "*The coding system for the history file."
+ :type 'symbol
+ :group 'slime-repl)
+
+(defun slime-coding-system-mulibyte-p (coding-system)
+ (second (slime-find-coding-system coding-system)))
+
+(defun slime-coding-system-cl-name (coding-system)
+ (third (slime-find-coding-system coding-system)))
+
+;;; Interface
+(defun slime-net-send (sexp proc)
+ "Send a SEXP to Lisp over the socket PROC.
+This is the lowest level of communication. The sexp will be READ and
+EVAL'd by Lisp."
+ (let* ((msg (concat (slime-prin1-to-string sexp) "\n"))
+ (string (concat (slime-net-encode-length (length msg)) msg))
+ (coding-system (cdr (process-coding-system proc))))
+ (slime-log-event sexp)
+ (cond ((slime-safe-encoding-p coding-system string)
+ (process-send-string proc string))
+ (t (error "Coding system %s not suitable for %S"
+ coding-system string)))))
+
+(defun slime-safe-encoding-p (coding-system string)
+ "Return true iff CODING-SYSTEM can safely encode STRING."
+ (if (featurep 'xemacs)
+ ;; FIXME: XEmacs encodes non-encodeable chars as ?~ automatically
+ t
+ (or (let ((candidates (find-coding-systems-string string))
+ (base (coding-system-base coding-system)))
+ (or (equal candidates '(undecided))
+ (memq base candidates)))
+ (and (not (multibyte-string-p string))
+ (not (slime-coding-system-mulibyte-p coding-system))))))
+
+(defun slime-net-close (process &optional debug)
+ (setq slime-net-processes (remove process slime-net-processes))
+ (when (eq process slime-default-connection)
+ (setq slime-default-connection nil))
+ (cond (debug
+ (set-process-sentinel process 'ignore)
+ (set-process-filter process 'ignore)
+ (delete-process process))
+ (t
+ (run-hook-with-args 'slime-net-process-close-hooks process)
+ ;; killing the buffer also closes the socket
+ (kill-buffer (process-buffer process)))))
+
+(defun slime-net-sentinel (process message)
+ (message "Lisp connection closed unexpectedly: %s" message)
+ (slime-net-close process)
+ (slime-set-state "[not connected]" process))
+
+;;; Socket input is handled by `slime-net-filter', which decodes any
+;;; complete messages and hands them off to the event dispatcher.
+
+(defun slime-net-filter (process string)
+ "Accept output from the socket and process all complete messages."
+ (with-current-buffer (process-buffer process)
+ (goto-char (point-max))
+ (insert string))
+ (slime-process-available-input process))
+
+(defun slime-run-when-idle (function &rest args)
+ "Call FUNCTION as soon as Emacs is idle."
+ (apply #'run-at-time
+ (if (featurep 'xemacs) itimer-short-interval 0)
+ nil function args))
+
+(defun slime-process-available-input (process)
+ "Process all complete messages that have arrived from Lisp."
+ (with-current-buffer (process-buffer process)
+ (while (slime-net-have-input-p)
+ (let ((event (slime-net-read-or-lose process))
+ (ok nil))
+ (slime-log-event event)
+ (unwind-protect
+ (save-current-buffer
+ (slime-dispatch-event event process)
+ (setq ok t))
+ (unless ok
+ (slime-run-when-idle 'slime-process-available-input process)))))))
+
+(defun slime-net-have-input-p ()
+ "Return true if a complete message is available."
+ (goto-char (point-min))
+ (and (>= (buffer-size) 6)
+ (>= (- (buffer-size) 6) (slime-net-decode-length))))
+
+(defun slime-net-read-or-lose (process)
+ (condition-case error
+ (slime-net-read)
+ (error
+ (debug)
+ (slime-net-close process t)
+ (error "net-read error: %S" error))))
+
+(defun slime-net-read ()
+ "Read a message from the network buffer."
+ (goto-char (point-min))
+ (let* ((length (slime-net-decode-length))
+ (start (+ 6 (point)))
+ (end (+ start length)))
+ (assert (plusp length))
+ (let ((string (buffer-substring-no-properties start end)))
+ (prog1 (read string)
+ (delete-region (point-min) end)))))
+
+(defun slime-net-decode-length ()
+ "Read a 24-bit hex-encoded integer from buffer."
+ (string-to-number (buffer-substring-no-properties (point) (+ (point) 6)) 16))
+
+(defun slime-net-encode-length (n)
+ "Encode an integer into a 24-bit hex string."
+ (format "%06x" n))
+
+(defun slime-prin1-to-string (sexp)
+ "Like `prin1-to-string' but don't octal-escape non-ascii characters.
+This is more compatible with the CL reader."
+ (with-temp-buffer
+ (let ((print-escape-nonascii nil)
+ (print-escape-newlines nil))
+ (prin1 sexp (current-buffer))
+ (buffer-string))))
+
+
+;;;; Connections
+;;;
+;;; "Connections" are the high-level Emacs<->Lisp networking concept.
+;;;
+;;; Emacs has a connection to each Lisp process that it's interacting
+;;; with. Typically there would only be one, but a user can choose to
+;;; connect to many Lisps simultaneously.
+;;;
+;;; A connection consists of a control socket, optionally an extra
+;;; socket dedicated to receiving Lisp output (an optimization), and a
+;;; set of connection-local state variables.
+;;;
+;;; The state variables are stored as buffer-local variables in the
+;;; control socket's process-buffer and are used via accessor
+;;; functions. These variables include things like the *FEATURES* list
+;;; and Unix Pid of the Lisp process.
+;;;
+;;; One connection is "current" at any given time. This is:
+;;; `slime-dispatching-connection' if dynamically bound, or
+;;; `slime-buffer-connection' if this is set buffer-local, or
+;;; `slime-default-connection' otherwise.
+;;;
+;;; When you're invoking commands in your source files you'll be using
+;;; `slime-default-connection'. This connection can be interactively
+;;; reassigned via the connection-list buffer.
+;;;
+;;; When a command creates a new buffer it will set
+;;; `slime-buffer-connection' so that commands in the new buffer will
+;;; use the connection that the buffer originated from. For example,
+;;; the apropos command creates the *Apropos* buffer and any command
+;;; in that buffer (e.g. `M-.') will go to the same Lisp that did the
+;;; apropos search. REPL buffers are similarly tied to their
+;;; respective connections.
+;;;
+;;; When Emacs is dispatching some network message that arrived from a
+;;; connection it will dynamically bind `slime-dispatching-connection'
+;;; so that the event will be processed in the context of that
+;;; connection.
+;;;
+;;; This is mostly transparent. The user should be aware that he can
+;;; set the default connection to pick which Lisp handles commands in
+;;; Lisp-mode source buffers, and slime hackers should be aware that
+;;; they can tie a buffer to a specific connection. The rest takes
+;;; care of itself.
+
+(defvar slime-dispatching-connection nil
+ "Network process currently executing.
+This is dynamically bound while handling messages from Lisp; it
+overrides `slime-buffer-connection' and `slime-default-connection'.")
+
+(make-variable-buffer-local
+ (defvar slime-buffer-connection nil
+ "Network connection to use in the current buffer.
+This overrides `slime-default-connection'."))
+
+(defvar slime-default-connection nil
+ "Network connection to use by default.
+Used for all Lisp communication, except when overridden by
+`slime-dispatching-connection' or `slime-buffer-connection'.")
+
+(defun slime-current-connection ()
+ "Return the connection to use for Lisp interaction.
+Return nil if there's no connection."
+ (or slime-dispatching-connection
+ slime-buffer-connection
+ slime-default-connection))
+
+(defun slime-connection ()
+ "Return the connection to use for Lisp interaction.
+Signal an error if there's no connection."
+ (let ((conn (slime-current-connection)))
+ (cond ((and (not conn) slime-net-processes)
+ (error "No default connection selected."))
+ ((not conn)
+ (error "Not connected."))
+ ((not (eq (process-status conn) 'open))
+ (error "Connection closed."))
+ (t conn))))
+
+(defun slime-select-connection (process)
+ "Make PROCESS the default connection."
+ (setq slime-default-connection process))
+
+(defmacro* slime-with-connection-buffer ((&optional process) &rest body)
+ "Execute BODY in the process-buffer of PROCESS.
+If PROCESS is not specified, `slime-connection' is used.
+
+\(fn (&optional PROCESS) &body BODY))"
+ `(with-current-buffer
+ (process-buffer (or ,process (slime-connection)
+ (error "No connection")))
+ , at body))
+
+(put 'slime-with-connection-buffer 'lisp-indent-function 1)
+
+(defvar slime-state-name "[??]"
+ "Name of the current state of `slime-default-connection'.
+Just used for informational display in the mode-line.")
+
+(defun slime-set-state (name &optional connection)
+ "Set the current connection's informational state name.
+If this is the default connection then the state will be displayed in
+the modeline."
+ (when (or (not (slime-connected-p))
+ (eq (or connection (slime-connection)) slime-default-connection))
+ (setq slime-state-name name)
+ (force-mode-line-update)))
+
+;;; Connection-local variables:
+
+(defmacro slime-def-connection-var (varname &rest initial-value-and-doc)
+ "Define a connection-local variable.
+The value of the variable can be read by calling the function of the
+same name (it must not be accessed directly). The accessor function is
+setf-able.
+
+The actual variable bindings are stored buffer-local in the
+process-buffers of connections. The accessor function refers to
+the binding for `slime-connection'."
+ (let ((real-var (intern (format "%s:connlocal" varname))))
+ `(progn
+ ;; Variable
+ (make-variable-buffer-local
+ (defvar ,real-var , at initial-value-and-doc))
+ ;; Accessor
+ (defun ,varname (&optional process)
+ (slime-with-connection-buffer (process) ,real-var))
+ ;; Setf
+ (defsetf ,varname (&optional process) (store)
+ `(slime-with-connection-buffer (,process)
+ (setq (\, (quote (\, real-var))) (\, store))
+ (\, store)))
+ '(\, varname))))
+
+(put 'slime-def-connection-var 'lisp-indent-function 2)
+
+;; Let's indulge in some pretty colours.
+(unless (featurep 'xemacs)
+ (font-lock-add-keywords
+ 'emacs-lisp-mode
+ '(("(\\(slime-def-connection-var\\)\\s +\\(\\(\\w\\|\\s_\\)+\\)"
+ (1 font-lock-keyword-face)
+ (2 font-lock-variable-name-face)))))
+
+(slime-def-connection-var slime-connection-number nil
+ "Serial number of a connection.
+Bound in the connection's process-buffer.")
+
+(slime-def-connection-var slime-lisp-features '()
+ "The symbol-names of Lisp's *FEATURES*.
+This is automatically synchronized from Lisp.")
+
+(slime-def-connection-var slime-lisp-modules '()
+ "The strings of Lisp's *MODULES*.")
+
+(slime-def-connection-var slime-lisp-package
+ "COMMON-LISP-USER"
+ "The current package name of the Superior lisp.
+This is automatically synchronized from Lisp.")
+
+(slime-def-connection-var slime-lisp-package-prompt-string
+ "CL-USER"
+ "The current package name of the Superior lisp.
+This is automatically synchronized from Lisp.")
+
+(slime-def-connection-var slime-pid nil
+ "The process id of the Lisp process.")
+
+(slime-def-connection-var slime-lisp-implementation-type nil
+ "The implementation type of the Lisp process.")
+
+(slime-def-connection-var slime-lisp-implementation-version nil
+ "The implementation type of the Lisp process.")
+
+(slime-def-connection-var slime-lisp-implementation-name nil
+ "The short name for the Lisp implementation.")
+
+(slime-def-connection-var slime-connection-name nil
+ "The short name for connection.")
+
+(slime-def-connection-var slime-inferior-process nil
+ "The inferior process for the connection if any.")
+
+(slime-def-connection-var slime-communication-style nil
+ "The communication style.")
+
+(slime-def-connection-var slime-machine-instance nil
+ "The name of the (remote) machine running the Lisp process.")
+
+;;;;; Connection setup
+
+(defvar slime-connection-counter 0
+ "The number of SLIME connections made. For generating serial numbers.")
+
+;;; Interface
+(defun slime-setup-connection (process)
+ "Make a connection out of PROCESS."
+ (let ((slime-dispatching-connection process))
+ (slime-init-connection-state process)
+ (slime-select-connection process)
+ process))
+
+(defun slime-init-connection-state (proc)
+ "Initialize connection state in the process-buffer of PROC."
+ ;; To make life simpler for the user: if this is the only open
+ ;; connection then reset the connection counter.
+ (when (equal slime-net-processes (list proc))
+ (setq slime-connection-counter 0))
+ (slime-with-connection-buffer ()
+ (setq slime-buffer-connection proc))
+ (setf (slime-connection-number proc) (incf slime-connection-counter))
+ ;; We do the rest of our initialization asynchronously. The current
+ ;; function may be called from a timer, and if we setup the REPL
+ ;; from a timer then it mysteriously uses the wrong keymap for the
+ ;; first command.
+ (slime-eval-async '(swank:connection-info)
+ (with-lexical-bindings (proc)
+ (lambda (info)
+ (slime-set-connection-info proc info)))))
+
+(defun slime-set-connection-info (connection info)
+ "Initialize CONNECTION with INFO received from Lisp."
+ (let ((slime-dispatching-connection connection))
+ (destructuring-bind (&key pid style lisp-implementation machine
+ features package version modules
+ &allow-other-keys) info
+ (or (equal version slime-protocol-version)
+ (yes-or-no-p "Protocol version mismatch. Continue anyway? ")
+ (slime-net-close connection)
+ (top-level))
+ (setf (slime-pid) pid
+ (slime-communication-style) style
+ (slime-lisp-features) features
+ (slime-lisp-modules) modules)
+ (destructuring-bind (&key name prompt) package
+ (setf (slime-lisp-package) name
+ (slime-lisp-package-prompt-string) prompt))
+ (destructuring-bind (&key type name version) lisp-implementation
+ (setf (slime-lisp-implementation-type) type
+ (slime-lisp-implementation-version) version
+ (slime-lisp-implementation-name) name
+ (slime-connection-name) (slime-generate-connection-name name)))
+ (destructuring-bind (&key instance type version) machine
+ (setf (slime-machine-instance) instance)))
+ (setq slime-state-name "") ; FIXME
+ (let ((args (when-let (p (slime-inferior-process))
+ (slime-inferior-lisp-args p))))
+ (when-let (name (plist-get args ':name))
+ (unless (string= (slime-lisp-implementation-name) name)
+ (setf (slime-connection-name)
+ (slime-generate-connection-name (symbol-name name)))))
+ (slime-hide-inferior-lisp-buffer)
+ (slime-init-output-buffer connection)
+ (slime-load-contribs)
+ (run-hooks 'slime-connected-hook)
+ (when-let (fun (plist-get args ':init-function))
+ (funcall fun)))
+ (message "Connected. %s" (slime-random-words-of-encouragement))))
+
+(defun slime-generate-connection-name (lisp-name)
+ (loop for i from 1
+ for name = lisp-name then (format "%s<%d>" lisp-name i)
+ while (find name slime-net-processes
+ :key #'slime-connection-name :test #'equal)
+ finally (return name)))
+
+(defun slime-connection-close-hook (process)
+ (when (eq process slime-default-connection)
+ (when slime-net-processes
+ (slime-select-connection (car slime-net-processes))
+ (message "Default connection closed; switched to #%S (%S)"
+ (slime-connection-number)
+ (slime-connection-name)))))
+
+(add-hook 'slime-net-process-close-hooks 'slime-connection-close-hook)
+
+;;;;; Commands on connections
+
+(defun slime-disconnect ()
+ "Disconnect all connections."
+ (interactive)
+ (mapc #'slime-net-close slime-net-processes))
+
+(defun slime-make-default-connection ()
+ "Make the current connection the default connection."
+ (interactive)
+ (slime-select-connection (slime-connection))
+ (message "Connection #%S (%s) now default SLIME connection."
+ (slime-connection-number)
+ (slime-connection-name)))
+
+(defun slime-choose-connection ()
+ "Return an established connection chosen by the user."
+ (let ((default (slime-connection-name)))
+ (slime-find-connection-by-name
+ (completing-read (format "Connection name (default %s): " default)
+ (slime-bogus-completion-alist
+ (mapcar #'slime-connection-name slime-net-processes))
+ nil
+ t
+ nil
+ nil
+ default))))
+
+(defun slime-find-connection-by-name (name)
+ (find name slime-net-processes
+ :test #'string= :key #'slime-connection-name))
+
+(defun slime-connection-port (connection)
+ "Return the remote port number of CONNECTION."
+ (if (featurep 'xemacs)
+ (car (process-id connection))
+ (cadr (process-contact connection))))
+
+(defun slime-process (&optional connection)
+ "Return the Lisp process for CONNECTION (default `slime-connection').
+Can return nil if there's no process object for the connection."
+ (let ((proc (slime-inferior-process connection)))
+ (if (and proc
+ (memq (process-status proc) '(run stop)))
+ proc)))
+
+;; Non-macro version to keep the file byte-compilable.
+(defun slime-set-inferior-process (connection process)
+ (setf (slime-inferior-process connection) process))
+
+(defun slime-use-sigint-for-interrupt (&optional connection)
+ (let ((c (or connection (slime-connection))))
+ (ecase (slime-communication-style c)
+ ((:fd-handler nil) t)
+ ((:spawn :sigio) nil))))
+
+(defvar slime-inhibit-pipelining t
+ "*If true, don't send background requests if Lisp is already busy.")
+
+(defun slime-background-activities-enabled-p ()
+ (and (or slime-mode
+ (eq major-mode 'sldb-mode)
+ (eq major-mode 'slime-repl-mode))
+ (let ((con (slime-current-connection)))
+ (and con
+ (eq (process-status con) 'open)))
+ (or (not (slime-busy-p))
+ (not slime-inhibit-pipelining))))
+
+
+;;;; Communication protocol
+
+;;;;; Emacs Lisp programming interface
+;;;
+;;; The programming interface for writing Emacs commands is based on
+;;; remote procedure calls (RPCs). The basic operation is to ask Lisp
+;;; to apply a named Lisp function to some arguments, then to do
+;;; something with the result.
+;;;
+;;; Requests can be either synchronous (blocking) or asynchronous
+;;; (with the result passed to a callback/continuation function). If
+;;; an error occurs during the request then the debugger is entered
+;;; before the result arrives -- for synchronous evaluations this
+;;; requires a recursive edit.
+;;;
+;;; You should use asynchronous evaluations (`slime-eval-async') for
+;;; most things. Reserve synchronous evaluations (`slime-eval') for
+;;; the cases where blocking Emacs is really appropriate (like
+;;; completion) and that shouldn't trigger errors (e.g. not evaluate
+;;; user-entered code).
+;;;
+;;; We have the concept of the "current Lisp package". RPC requests
+;;; always say what package the user is making them from and the Lisp
+;;; side binds that package to *BUFFER-PACKAGE* to use as it sees
+;;; fit. The current package is defined as the buffer-local value of
+;;; `slime-buffer-package' if set, and otherwise the package named by
+;;; the nearest IN-PACKAGE as found by text search (first backwards,
+;;; then forwards).
+;;;
+;;; Similarly we have the concept of the current thread, i.e. which
+;;; thread in the Lisp process should handle the request. The current
+;;; thread is determined solely by the buffer-local value of
+;;; `slime-current-thread'. This is usually bound to t meaning "no
+;;; particular thread", but can also be used to nominate a specific
+;;; thread. The REPL and the debugger both use this feature to deal
+;;; with specific threads.
+
+(make-variable-buffer-local
+ (defvar slime-current-thread t
+ "The id of the current thread on the Lisp side.
+t means the \"current\" thread;
+:repl-thread the thread that executes REPL requests;
+fixnum a specific thread."))
+
+(make-variable-buffer-local
+ (defvar slime-buffer-package nil
+ "The Lisp package associated with the current buffer.
+This is set only in buffers bound to specific packages."))
+
+;;; `slime-rex' is the RPC primitive which is used to implement both
+;;; `slime-eval' and `slime-eval-async'. You can use it directly if
+;;; you need to, but the others are usually more convenient.
+
+(defmacro* slime-rex ((&rest saved-vars)
+ (sexp &optional
+ (package '(slime-current-package))
+ (thread 'slime-current-thread))
+ &rest continuations)
+ "(slime-rex (VAR ...) (SEXP &optional PACKAGE THREAD) CLAUSES ...)
+
+Remote EXecute SEXP.
+
+VARs are a list of saved variables visible in the other forms. Each
+VAR is either a symbol or a list (VAR INIT-VALUE).
+
+SEXP is evaluated and the princed version is sent to Lisp.
+
+PACKAGE is evaluated and Lisp binds *BUFFER-PACKAGE* to this package.
+The default value is (slime-current-package).
+
+CLAUSES is a list of patterns with same syntax as
+`destructure-case'. The result of the evaluation of SEXP is
+dispatched on CLAUSES. The result is either a sexp of the
+form (:ok VALUE) or (:abort). CLAUSES is executed
+asynchronously.
+
+Note: don't use backquote syntax for SEXP, because Emacs20 cannot
+deal with that."
+ (let ((result (gensym)))
+ `(lexical-let ,(loop for var in saved-vars
+ collect (etypecase var
+ (symbol (list var var))
+ (cons var)))
+ (slime-dispatch-event
+ (list :emacs-rex ,sexp ,package ,thread
+ (lambda (,result)
+ (destructure-case ,result
+ , at continuations)))))))
+
+(put 'slime-rex 'lisp-indent-function 2)
+
+;;; Interface
+(defun slime-current-package ()
+ "Return the Common Lisp package in the current context.
+If `slime-buffer-package' has a value then return that, otherwise
+search for and read an `in-package' form.
+
+The REPL buffer is a special case: it's package is `slime-lisp-package'."
+ (cond ((eq major-mode 'slime-repl-mode)
+ (slime-lisp-package))
+ (slime-buffer-package)
+ (t (save-restriction
+ (widen)
+ (slime-find-buffer-package)))))
+
+(defvar slime-find-buffer-package-function 'slime-search-buffer-package
+ "*Function to use for `slime-find-buffer-package'.
+The result should be the package-name (a string)
+or nil if nothing suitable can be found.")
+
+(defun slime-find-buffer-package ()
+ "Figure out which Lisp package the current buffer is associated with."
+ (funcall slime-find-buffer-package-function))
+
+;; When modifing this code consider cases like:
+;; (in-package #.*foo*)
+;; (in-package #:cl)
+;; (in-package :cl)
+;; (in-package "CL")
+;; (in-package |CL|)
+;; (in-package #+ansi-cl :cl #-ansi-cl 'lisp)
+(defun slime-search-buffer-package ()
+ (let ((case-fold-search t)
+ (regexp (concat "^(\\(cl:\\|common-lisp:\\)?in-package\\>[ \t']*"
+ "\\([^)]+\\)[ \t]*)")))
+ (save-excursion
+ (when (or (re-search-backward regexp nil t)
+ (re-search-forward regexp nil t))
+ (match-string-no-properties 2)))))
+
+;;; Synchronous requests are implemented in terms of asynchronous
+;;; ones. We make an asynchronous request with a continuation function
+;;; that `throw's its result up to a `catch' and then enter a loop of
+;;; handling I/O until that happens.
+
+(defvar slime-stack-eval-tags nil
+ "List of stack-tags of continuations waiting on the stack.")
+
+(defun slime-eval (sexp &optional package)
+ "Evaluate EXPR on the superior Lisp and return the result."
+ (when (null package) (setq package (slime-current-package)))
+ (let* ((tag (gensym (format "slime-result-%d-"
+ (1+ (slime-continuation-counter)))))
+ (slime-stack-eval-tags (cons tag slime-stack-eval-tags)))
+ (apply
+ #'funcall
+ (catch tag
+ (slime-rex (tag sexp)
+ (sexp package)
+ ((:ok value)
+ (unless (member tag slime-stack-eval-tags)
+ (error "tag = %S eval-tags = %S sexp = %S"
+ tag slime-stack-eval-tags sexp))
+ (throw tag (list #'identity value)))
+ ((:abort)
+ (throw tag (list #'error "Synchronous Lisp Evaluation aborted."))))
+ (let ((debug-on-quit t)
+ (inhibit-quit nil)
+ (conn (slime-connection)))
+ (while t
+ (unless (eq (process-status conn) 'open)
+ (error "Lisp connection closed unexpectedly"))
+ (slime-accept-process-output nil 0.01)))))))
+
+(defun slime-eval-async (sexp &optional cont package)
+ "Evaluate EXPR on the superior Lisp and call CONT with the result."
+ (slime-rex (cont (buffer (current-buffer)))
+ (sexp (or package (slime-current-package)))
+ ((:ok result)
+ (when cont
+ (set-buffer buffer)
+ (funcall cont result)))
+ ((:abort)
+ (message "Evaluation aborted."))))
+
+;;; These functions can be handy too:
+
+(defun slime-connected-p ()
+ "Return true if the Swank connection is open."
+ (not (null slime-net-processes)))
+
+(defun slime-check-connected ()
+ "Signal an error if we are not connected to Lisp."
+ (unless (slime-connected-p)
+ (error "Not connected. Use `%s' to start a Lisp."
+ (substitute-command-keys "\\[slime]"))))
+
+(defun slime-busy-p ()
+ "True if Lisp has outstanding requests.
+Debugged requests are ignored."
+ (let ((debugged (sldb-debugged-continuations (slime-connection))))
+ (remove-if (lambda (id)
+ (memq id debugged))
+ (slime-rex-continuations)
+ :key #'car)))
+
+;; dummy defvar for compiler
+(defvar slime-repl-read-mode)
+
+(defun slime-reading-p ()
+ "True if Lisp is currently reading input from the REPL."
+ (with-current-buffer (slime-output-buffer)
+ slime-repl-read-mode))
+
+(defun slime-sync ()
+ "Block until the most recent request has finished."
+ (when (slime-rex-continuations)
+ (let ((tag (caar (slime-rex-continuations))))
+ (while (find tag (slime-rex-continuations) :key #'car)
+ (slime-accept-process-output nil 0.1)))))
+
+(defun slime-ping ()
+ "Check that communication works."
+ (interactive)
+ (message "%s" (slime-eval "PONG")))
+
+;;;;; Protocol event handler (the guts)
+;;;
+;;; This is the protocol in all its glory. The input to this function
+;;; is a protocol event that either originates within Emacs or arrived
+;;; over the network from Lisp.
+;;;
+;;; Each event is a list beginning with a keyword and followed by
+;;; arguments. The keyword identifies the type of event. Events
+;;; originating from Emacs have names starting with :emacs- and events
+;;; from Lisp don't.
+
+(slime-def-connection-var slime-rex-continuations '()
+ "List of (ID . FUNCTION) continuations waiting for RPC results.")
+
+(slime-def-connection-var slime-continuation-counter 0
+ "Continuation serial number counter.")
+
+(defvar slime-event-hooks)
+
+(defun slime-dispatch-event (event &optional process)
+ (let ((slime-dispatching-connection (or process (slime-connection))))
+ (or (run-hook-with-args-until-success 'slime-event-hooks event)
+ (destructure-case event
+ ((:write-string output &optional target)
+ (slime-write-string output target))
+ ((:emacs-rex form package thread continuation)
+ (slime-set-state "|eval...")
+ (when (and (slime-use-sigint-for-interrupt) (slime-busy-p))
+ (message "; pipelined request... %S" form))
+ (let ((id (incf (slime-continuation-counter))))
+ (push (cons id continuation) (slime-rex-continuations))
+ (slime-send `(:emacs-rex ,form ,package ,thread ,id))))
+ ((:return value id)
+ (let ((rec (assq id (slime-rex-continuations))))
+ (cond (rec (setf (slime-rex-continuations)
+ (remove rec (slime-rex-continuations)))
+ (when (null (slime-rex-continuations))
+ (slime-set-state ""))
+ (funcall (cdr rec) value))
+ (t
+ (error "Unexpected reply: %S %S" id value)))))
+ ((:debug-activate thread level)
+ (assert thread)
+ (sldb-activate thread level))
+ ((:debug thread level condition restarts frames conts)
+ (assert thread)
+ (sldb-setup thread level condition restarts frames conts))
+ ((:debug-return thread level stepping)
+ (assert thread)
+ (sldb-exit thread level stepping))
+ ((:emacs-interrupt thread)
+ (slime-send `(:emacs-interrupt ,thread)))
+ ((:read-string thread tag)
+ (assert thread)
+ (slime-repl-read-string thread tag))
+ ((:y-or-n-p thread tag question)
+ (slime-y-or-n-p thread tag question))
+ ((:read-aborted thread tag)
+ (assert thread)
+ (slime-repl-abort-read thread tag))
+ ((:emacs-return-string thread tag string)
+ (slime-send `(:emacs-return-string ,thread ,tag ,string)))
+ ;;
+ ((:new-package package prompt-string)
+ (setf (slime-lisp-package) package)
+ (setf (slime-lisp-package-prompt-string) prompt-string))
+ ((:new-features features)
+ (setf (slime-lisp-features) features))
+ ((:indentation-update info)
+ (slime-handle-indentation-update info))
+ ((:open-dedicated-output-stream port)
+ (slime-open-stream-to-lisp port))
+ ((:eval-no-wait fun args)
+ (apply (intern fun) args))
+ ((:eval thread tag form-string)
+ (slime-check-eval-in-emacs-enabled)
+ (slime-eval-for-lisp thread tag form-string))
+ ((:emacs-return thread tag value)
+ (slime-send `(:emacs-return ,thread ,tag ,value)))
+ ((:ed what)
+ (slime-ed what))
+ ((:inspect what)
+ (slime-open-inspector what))
+ ((:background-message message)
+ (slime-background-message "%s" message))
+ ((:debug-condition thread message)
+ (assert thread)
+ (message "%s" message))))))
+
+(defun slime-send (sexp)
+ "Send SEXP directly over the wire on the current connection."
+ (slime-net-send sexp (slime-connection)))
+
+(defun slime-reset ()
+ "Clear all pending continuations."
+ (interactive)
+ (setf (slime-rex-continuations) '())
+ (mapc #'kill-buffer (sldb-buffers)))
+
+(defun slime-send-sigint ()
+ (interactive)
+ (signal-process (slime-pid) 'SIGINT))
+
+;;;;; Event logging to *slime-events*
+;;;
+;;; The *slime-events* buffer logs all protocol messages for debugging
+;;; purposes. Optionally you can enable outline-mode in that buffer,
+;;; which is convenient but slows things down significantly.
+
+(defvar slime-log-events t
+ "*Log protocol events to the *slime-events* buffer.")
+
+(defvar slime-outline-mode-in-events-buffer nil
+ "*Non-nil means use outline-mode in *slime-events*.")
+
+(defvar slime-event-buffer-name "*slime-events*"
+ "The name of the slime event buffer.")
+
+(defun slime-log-event (event)
+ "Record the fact that EVENT occurred."
+ (when slime-log-events
+ (with-current-buffer (slime-events-buffer)
+ ;; trim?
+ (when (> (buffer-size) 100000)
+ (goto-char (/ (buffer-size) 2))
+ (re-search-forward "^(" nil t)
+ (delete-region (point-min) (point)))
+ (goto-char (point-max))
+ (save-excursion
+ (slime-pprint-event event (current-buffer)))
+ (when (and (boundp 'outline-minor-mode)
+ outline-minor-mode)
+ (hide-entry))
+ (goto-char (point-max)))))
+
+(defun slime-pprint-event (event buffer)
+ "Pretty print EVENT in BUFFER with limited depth and width."
+ (let ((print-length 20)
+ (print-level 6)
+ (pp-escape-newlines t))
+ (pp event buffer)))
+
+(defun slime-events-buffer ()
+ (or (get-buffer slime-event-buffer-name)
+ (let ((buffer (get-buffer-create slime-event-buffer-name)))
+ (with-current-buffer buffer
+ (buffer-disable-undo)
+ (set (make-local-variable 'outline-regexp) "^(")
+ (set (make-local-variable 'comment-start) ";")
+ (set (make-local-variable 'comment-end) "")
+ (when slime-outline-mode-in-events-buffer
+ (outline-minor-mode)))
+ buffer)))
+
+
+;;;; Stream output
+
+(slime-def-connection-var slime-connection-output-buffer nil
+ "The buffer for the REPL. May be nil or a dead buffer.")
+
+(make-variable-buffer-local
+ (defvar slime-output-start nil
+ "Marker for the start of the output for the evaluation."))
+
+(make-variable-buffer-local
+ (defvar slime-output-end nil
+ "Marker for end of output. New output is inserted at this mark."))
+
+;; dummy definitions for the compiler
+(defvar slime-repl-package-stack)
+(defvar slime-repl-directory-stack)
+(defvar slime-repl-input-start-mark)
+(defvar slime-repl-prompt-start-mark)
+
+
+(defun slime-output-buffer (&optional noprompt)
+ "Return the output buffer, create it if necessary."
+ (let ((buffer (slime-connection-output-buffer)))
+ (or (if (buffer-live-p buffer) buffer)
+ (setf (slime-connection-output-buffer)
+ (let ((connection (slime-connection)))
+ (with-current-buffer (slime-repl-buffer t connection)
+ (unless (eq major-mode 'slime-repl-mode)
+ (slime-repl-mode))
+ (setq slime-buffer-connection connection)
+ (slime-reset-repl-markers)
+ (unless noprompt
+ (slime-repl-insert-prompt))
+ (current-buffer)))))))
+
+(defvar slime-repl-banner-function 'slime-repl-insert-banner)
+
+(defun slime-repl-update-banner ()
+ (funcall slime-repl-banner-function)
+ (goto-char (point-max))
+ (slime-mark-output-start)
+ (slime-mark-input-start)
+ (slime-repl-insert-prompt)
+ (pop-to-buffer (current-buffer)))
+
+(defun slime-repl-insert-banner ()
+ (when (zerop (buffer-size))
+ (let ((welcome (concat "; SLIME " (or (slime-changelog-date)
+ "- ChangeLog file not found"))))
+ (insert welcome))))
+
+(defun slime-init-output-buffer (connection)
+ (with-current-buffer (slime-output-buffer t)
+ (setq slime-buffer-connection connection
+ slime-repl-directory-stack '()
+ slime-repl-package-stack '())
+ (slime-repl-update-banner)))
+
+(defvar slime-show-last-output-function
+ 'slime-maybe-display-output-buffer
+ "*This function is called when a evaluation request is finished.
+It is called in the slime-output buffer and receives the region of the
+output as arguments.")
+
+(defun slime-show-last-output-region (start end)
+ (when (< start end)
+ (slime-display-buffer-region (current-buffer) (1- start)
+ slime-repl-input-start-mark)))
+
+(defun slime-maybe-display-output-buffer (start end)
+ (when (and (< start end)
+ (not (get-buffer-window (current-buffer) t)))
+ (display-buffer (current-buffer)))
+ (when (eobp)
+ (slime-repl-show-maximum-output t)))
+
+(defun slime-show-last-output ()
+ "Show the output from the last Lisp evaluation."
+ (with-current-buffer (slime-output-buffer)
+ (let ((start slime-output-start)
+ (end slime-output-end))
+ (funcall slime-show-last-output-function start end))))
+
+(defun slime-display-output-buffer ()
+ "Display the output buffer and scroll to bottom."
+ (with-current-buffer (slime-output-buffer)
+ (goto-char (point-max))
+ (unless (get-buffer-window (current-buffer) t)
+ (display-buffer (current-buffer) t))
+ (slime-repl-show-maximum-output)))
+
+(defmacro slime-with-output-end-mark (&rest body)
+ "Execute BODY at `slime-output-end'.
+
+If point is initially at `slime-output-end' and the buffer is visible
+update window-point afterwards. If point is initially not at
+`slime-output-end, execute body inside a `save-excursion' block."
+ `(let ((body.. (lambda () , at body))
+ (updatep.. (and (eobp) (pos-visible-in-window-p))))
+ (cond ((= (point) slime-output-end)
+ (let ((start.. (point)))
+ (funcall body..)
+ (set-marker slime-output-end (point))
+ (when (= start.. slime-repl-input-start-mark)
+ (set-marker slime-repl-input-start-mark (point)))))
+ (t
+ (save-excursion
+ (goto-char slime-output-end)
+ (funcall body..))))
+ (when updatep..
+ (slime-repl-show-maximum-output
+ (> (- slime-output-end slime-output-start) 1000)))))
+
+(defun slime-output-filter (process string)
+ (with-current-buffer (process-buffer process)
+ (when (and (plusp (length string))
+ (eq (process-status slime-buffer-connection) 'open))
+ (slime-write-string string))))
+
+(defvar slime-open-stream-hooks)
+
+(defun slime-open-stream-to-lisp (port)
+ (let ((stream (open-network-stream "*lisp-output-stream*"
+ (slime-with-connection-buffer ()
+ (current-buffer))
+ slime-lisp-host port)))
+ (slime-set-query-on-exit-flag stream)
+ (set-process-filter stream 'slime-output-filter)
+ (let ((pcs (process-coding-system (slime-current-connection))))
+ (set-process-coding-system stream (car pcs) (cdr pcs)))
+ (when-let (secret (slime-secret))
+ (slime-net-send secret stream))
+ (run-hook-with-args 'slime-open-stream-hooks stream)
+ stream))
+
+(defun slime-io-speed-test (&optional profile)
+ "A simple minded benchmark for stream performance.
+If a prefix argument is given, instrument the slime package for
+profiling before running the benchmark."
+ (interactive "P")
+ (eval-and-compile
+ (require 'elp))
+ (elp-reset-all)
+ (elp-restore-all)
+ (load "slime.el")
+ ;;(byte-compile-file "slime-net.el" t)
+ ;;(setq slime-log-events nil)
+ (setq slime-enable-evaluate-in-emacs t)
+ ;;(setq slime-repl-enable-presentations nil)
+ (when profile
+ (elp-instrument-package "slime-"))
+ (kill-buffer (slime-output-buffer))
+ ;;(display-buffer (slime-output-buffer))
+ (delete-other-windows)
+ (sit-for 0)
+ (slime-repl-send-string "(swank:io-speed-test 5000 1)")
+ (let ((proc (slime-inferior-process)))
+ (when proc
+ (switch-to-buffer (process-buffer proc))
+ (goto-char (point-max)))))
+
+(defvar slime-write-string-function 'slime-repl-write-string)
+
+(defun slime-write-string (string &optional target)
+ "Insert STRING in the REPL buffer or some other TARGET.
+If TARGET is nil, insert STRING as regular process
+output. If TARGET is :repl-result, insert STRING as the result of the
+evaluation. Other values of TARGET map to an Emacs marker via the
+hashtable `slime-output-target-to-marker'; output is inserted at this marker."
+ (funcall slime-write-string-function string target))
+
+(defun slime-repl-write-string (string &optional target)
+ (case target
+ ((nil) (slime-repl-emit string))
+ (:repl-result (slime-repl-emit-result string))
+ (t (slime-emit-string string target))))
+
+(defun slime-repl-emit (string)
+ ;; insert the string STRING in the output buffer
+ (with-current-buffer (slime-output-buffer)
+ (slime-with-output-end-mark
+ (slime-insert-propertized '(face slime-repl-output-face
+ rear-nonsticky (face))
+ string)
+ (set-marker slime-output-end (point))
+ (when (and (= (point) slime-repl-prompt-start-mark)
+ (not (bolp)))
+ (insert "\n")
+ (set-marker slime-output-end (1- (point))))
+ (when (< slime-repl-input-start-mark (point))
+ (set-marker slime-repl-input-start-mark (point))))))
+
+(defun slime-repl-emit-result (string &optional bol)
+ ;; insert STRING and mark it as evaluation result
+ (with-current-buffer (slime-output-buffer)
+ (goto-char slime-repl-input-start-mark)
+ (when (and bol (not (bolp))) (insert "\n"))
+ (slime-insert-propertized `(face slime-repl-result-face
+ rear-nonsticky (face))
+ string)
+ (set-marker slime-repl-input-start-mark (point))))
+
+(defvar slime-last-output-target-id 0
+ "The last integer we used as a TARGET id.")
+
+(defvar slime-output-target-to-marker
+ (make-hash-table)
+ "Map from TARGET ids to Emacs markers.
+The markers indicate where output should be inserted.")
+
+(defun slime-output-target-marker (target)
+ "Return the marker where output for TARGET should be inserted."
+ (case target
+ ((nil)
+ (with-current-buffer (slime-output-buffer)
+ slime-output-end))
+ (:repl-result
+ (with-current-buffer (slime-output-buffer)
+ slime-repl-input-start-mark))
+ (t
+ (gethash target slime-output-target-to-marker))))
+
+(defun slime-emit-string (string target)
+ "Insert STRING at target TARGET.
+See `slime-output-target-to-marker'."
+ (let* ((marker (slime-output-target-marker target))
+ (buffer (and marker (marker-buffer marker))))
+ (when buffer
+ (with-current-buffer buffer
+ (save-excursion
+ ;; Insert STRING at MARKER, then move MARKER behind
+ ;; the insertion.
+ (goto-char marker)
+ (insert-before-markers string)
+ (set-marker marker (point)))))))
+
+(defun slime-switch-to-output-buffer (&optional connection)
+ "Select the output buffer, preferably in a different window."
+ (interactive (list (if prefix-arg (slime-choose-connection))))
+ (let ((slime-dispatching-connection (or connection
+ slime-dispatching-connection)))
+ (set-buffer (slime-output-buffer))
+ (unless (eq (current-buffer) (window-buffer))
+ (pop-to-buffer (current-buffer) t))
+ (goto-char (point-max))))
+
+
+;;;; REPL
+;;
+;; The REPL uses some markers to separate input from output. The
+;; usual configuration is as follows:
+;;
+;; ... output ... ... result ... prompt> ... input ...
+;; ^ ^ ^ ^ ^
+;; output-start output-end prompt-start input-start input-end
+;;
+;; output-start and input-start are right inserting markers;
+;; output-end and input-end left inserting.
+;;
+;; We maintain the following invariant:
+;;
+;; output-start <= output-end <= input-start <= input-end.
+;;
+;; This invariant is important, because we must be prepared for
+;; asynchronous output and asynchronous reads. ("Asynchronous" means,
+;; triggered by Lisp and not by Emacs.)
+;;
+;; All output is inserted at the output-end marker. Some care must be
+;; taken when output-end and input-start are at the same position: if
+;; we blindly insert at that point, we break the invariant stated
+;; above, because the output-end marker is left inserting. The macro
+;; `slime-with-output-end-mark' handles this complication by moving
+;; the input-start marker to an appropriate place. The macro also
+;; updates window-point if necessary, and tries to keep the prompt in
+;; the first column by inserting a newline.
+;;
+;; A "synchronous" evaluation request proceeds as follows: the user
+;; inserts some text between input-start and input-end and then hits
+;; return. We send the text between the input markers to Lisp, move
+;; the output and input makers to the line after the input and wait.
+;; When we receive the result, we insert it together with a prompt
+;; between the output-end and input-start mark.
+;; `slime-repl-insert-prompt' does this.
+;;
+;; It is possible that some output for such an evaluation request
+;; arrives after the result. This output is inserted before the
+;; result (and before the prompt). Output that doesn't belong the
+;; evaluation request should not be inserted before the result, but
+;; immediately before the prompt. To achieve this, we move the
+;; output-end mark to prompt-start after a short delay (by starting a
+;; timer in `slime-repl-insert-prompt'). In summary: synchronous
+;; output should go before the result, asynchronous before the prompt.
+;;
+;; If we are in "reading" state, e.g., during a call to Y-OR-N-P,
+;; there is no prompt between output-end and input-start.
+;;
+
+;; Small helper.
+(defun slime-make-variables-buffer-local (&rest variables)
+ (mapcar #'make-variable-buffer-local variables))
+
+(slime-make-variables-buffer-local
+ (defvar slime-repl-package-stack nil
+ "The stack of packages visited in this repl.")
+
+ (defvar slime-repl-directory-stack nil
+ "The stack of default directories associated with this repl.")
+
+ (defvar slime-repl-prompt-start-mark)
+ (defvar slime-repl-input-start-mark)
+ (defvar slime-repl-input-end-mark)
+ (defvar slime-repl-last-input-start-mark)
+ (defvar slime-repl-old-input-counter 0
+ "Counter used to generate unique `slime-repl-old-input' properties.
+This property value must be unique to avoid having adjacent inputs be
+joined together."))
+
+(defun slime-reset-repl-markers ()
+ (dolist (markname '(slime-output-start
+ slime-output-end
+ slime-repl-prompt-start-mark
+ slime-repl-input-start-mark
+ slime-repl-input-end-mark
+ slime-repl-last-input-start-mark))
+ (set markname (make-marker))
+ (set-marker (symbol-value markname) (point)))
+ ;; (set-marker-insertion-type slime-output-end t)
+ (set-marker-insertion-type slime-repl-input-end-mark t)
+ (set-marker-insertion-type slime-repl-prompt-start-mark t))
+
+;;;;; REPL mode setup
+
+(defvar slime-repl-mode-map)
+
+(setq slime-repl-mode-map (make-sparse-keymap))
+(set-keymap-parent slime-repl-mode-map lisp-mode-map)
+
+(dolist (spec slime-keys)
+ (destructuring-bind (key command &key inferior prefixed
+ &allow-other-keys) spec
+ (when inferior
+ (let ((key (if prefixed (concat slime-prefix-key key) key)))
+ (define-key slime-repl-mode-map key command)))))
+
+(slime-define-keys slime-repl-mode-map
+ ("\C-m" 'slime-repl-return)
+ ([return] 'slime-repl-return)
+ ("\C-j" 'slime-repl-newline-and-indent)
+ ("\C-\M-m" 'slime-repl-closing-return)
+ ([(control return)] 'slime-repl-closing-return)
+ ("\C-a" 'slime-repl-bol)
+ ([home] 'slime-repl-bol)
+ ("\C-e" 'slime-repl-eol)
+ ("\M-p" 'slime-repl-previous-input)
+ ((kbd "C-<up>") 'slime-repl-backward-input)
+ ("\M-n" 'slime-repl-next-input)
+ ((kbd "C-<down>") 'slime-repl-forward-input)
+ ("\M-r" 'slime-repl-previous-matching-input)
+ ("\M-s" 'slime-repl-next-matching-input)
+ ("\C-c\C-c" 'slime-interrupt)
+ ("\C-c\C-b" 'slime-interrupt)
+ ("\C-c:" 'slime-interactive-eval)
+ ("\C-c\C-e" 'slime-interactive-eval)
+ ("\C-cE" 'slime-edit-value)
+ ;("\t" 'slime-complete-symbol)
+ ("\t" 'slime-indent-and-complete-symbol)
+ (" " 'slime-space)
+ ("\C-c\C-d" slime-doc-map)
+ ("\C-c\C-w" slime-who-map)
+ ("\C-\M-x" 'slime-eval-defun)
+ ("\C-c\C-o" 'slime-repl-clear-output)
+ ("\C-c\M-o" 'slime-repl-clear-buffer)
+ ("\C-c\C-t" 'slime-toggle-trace-fdefinition)
+ ("\C-c\C-u" 'slime-repl-kill-input)
+ ("\C-c\C-n" 'slime-repl-next-prompt)
+ ("\C-c\C-p" 'slime-repl-previous-prompt)
+ ("\C-c\C-l" 'slime-load-file)
+ ("\C-c\C-k" 'slime-compile-and-load-file)
+ ("\C-c\C-z" 'slime-nop))
+
+(defun slime-repl-mode ()
+ "Major mode for interacting with a superior Lisp.
+\\{slime-repl-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (setq major-mode 'slime-repl-mode)
+ (use-local-map slime-repl-mode-map)
+ (lisp-mode-variables t)
+ (set (make-local-variable 'lisp-indent-function)
+ 'common-lisp-indent-function)
+ (setq font-lock-defaults nil)
+ (setq mode-name "REPL")
+ (setq slime-current-thread :repl-thread)
+ (set (make-local-variable 'scroll-conservatively) 20)
+ (set (make-local-variable 'scroll-margin) 0)
+ (slime-repl-safe-load-history)
+ (add-local-hook 'kill-buffer-hook 'slime-repl-safe-save-merged-history)
+ (add-hook 'kill-emacs-hook 'slime-repl-save-all-histories)
+ (slime-setup-command-hooks)
+ ;; At the REPL, we define beginning-of-defun and end-of-defun to be
+ ;; the start of the previous prompt or next prompt respectively.
+ ;; Notice the interplay with SLIME-REPL-BEGINNING-OF-DEFUN.
+ (set (make-local-variable 'beginning-of-defun-function)
+ 'slime-repl-mode-beginning-of-defun)
+ (set (make-local-variable 'end-of-defun-function)
+ 'slime-repl-mode-end-of-defun)
+ (run-hooks 'slime-repl-mode-hook))
+
+(defun slime-repl-buffer (&optional create connection)
+ "Get the REPL buffer for the current connection; optionally create."
+ (funcall (if create #'get-buffer-create #'get-buffer)
+ (format "*slime-repl %s*" (slime-connection-name connection))))
+
+(defun slime-repl ()
+ (interactive)
+ (slime-switch-to-output-buffer))
+
+(defun slime-repl-mode-beginning-of-defun ()
+ (slime-repl-previous-prompt)
+ t)
+
+(defun slime-repl-mode-end-of-defun ()
+ (slime-repl-next-prompt)
+ t)
+
+(defun slime-repl-send-string (string &optional command-string)
+ (cond (slime-repl-read-mode
+ (slime-repl-return-string string))
+ (t (slime-repl-eval-string string))))
+
+(defun slime-repl-eval-string (string)
+ (slime-rex ()
+ ((list 'swank:listener-eval string) (slime-lisp-package))
+ ((:ok result)
+ (slime-repl-insert-result result))
+ ((:abort)
+ (slime-repl-show-abort))))
+
+(defun slime-repl-insert-result (result)
+ (with-current-buffer (slime-output-buffer)
+ (goto-char (point-max))
+ (when result
+ (destructure-case result
+ ((:values &rest strings)
+ (cond ((null strings)
+ (slime-repl-emit-result "; No value\n" t))
+ (t
+ (dolist (s strings)
+ (slime-repl-emit-result s t)))))))
+ (slime-repl-insert-prompt)))
+
+(defun slime-repl-show-abort ()
+ (with-current-buffer (slime-output-buffer)
+ (slime-with-output-end-mark
+ (unless (bolp) (insert-before-markers "\n"))
+ (insert-before-markers "; Evaluation aborted.\n"))
+ (slime-repl-insert-prompt)))
+
+(defun slime-repl-insert-prompt ()
+ "Goto to point max, and insert the prompt."
+ (goto-char slime-repl-input-start-mark)
+ (assert (= slime-repl-input-end-mark (point-max)))
+ (unless (bolp) (insert "\n"))
+ (let ((prompt-start (point))
+ (prompt (format "%s> " (slime-lisp-package-prompt-string))))
+ (slime-propertize-region
+ '(face slime-repl-prompt-face read-only t intangible t
+ slime-repl-prompt t
+ ;; emacs stuff
+ rear-nonsticky (slime-repl-prompt read-only face intangible)
+ ;; xemacs stuff
+ start-open t end-open t)
+ (insert-before-markers prompt))
+ (slime-mark-input-start)
+ (set-marker slime-repl-input-end-mark (point-max))
+ (set-marker slime-repl-prompt-start-mark prompt-start)
+ (goto-char slime-repl-prompt-start-mark)
+ (slime-mark-output-start)
+ (goto-char (point-max)))
+ (slime-repl-show-maximum-output))
+
+(defun slime-repl-show-maximum-output (&optional force)
+ "Put the end of the buffer at the bottom of the window."
+ (assert (eobp))
+ (let ((win (get-buffer-window (current-buffer))))
+ (when win
+ (with-selected-window win
+ (recenter -1)))))
+
+(defvar slime-repl-current-input-hooks)
+
+(defun slime-repl-current-input (&optional until-point-p)
+ "Return the current input as string.
+The input is the region from after the last prompt to the end of
+buffer."
+ (or (run-hook-with-args-until-success 'slime-repl-current-input-hooks
+ until-point-p)
+ (buffer-substring-no-properties
+ slime-repl-input-start-mark
+ (if (and until-point-p (<= (point) slime-repl-input-end-mark))
+ (point)
+ slime-repl-input-end-mark))))
+
+(defun slime-property-position (text-property &optional object)
+ "Return the first position of TEXT-PROPERTY, or nil."
+ (if (get-text-property 0 text-property object)
+ 0
+ (next-single-property-change 0 text-property object)))
+
+(defun slime-mark-input-start ()
+ (set-marker slime-repl-last-input-start-mark
+ (marker-position slime-repl-input-start-mark))
+ (set-marker slime-repl-input-start-mark (point) (current-buffer))
+ (set-marker slime-repl-input-end-mark (point) (current-buffer)))
+
+(defun slime-mark-output-start (&optional position)
+ (let ((position (or position (point))))
+ (set-marker slime-output-start position)
+ (set-marker slime-output-end position)))
+
+(defun slime-mark-output-end ()
+ ;; Don't put slime-repl-output-face again; it would remove the
+ ;; special presentation face, for instance in the SBCL inspector.
+ (add-text-properties slime-output-start slime-output-end
+ '(;;face slime-repl-output-face
+ rear-nonsticky (face))))
+
+(defun slime-repl-bol ()
+ "Go to the beginning of line or the prompt."
+ (interactive)
+ (cond ((and (>= (point) slime-repl-input-start-mark)
+ (slime-same-line-p (point) slime-repl-input-start-mark))
+ (goto-char slime-repl-input-start-mark))
+ (t (beginning-of-line 1)))
+ (slime-preserve-zmacs-region))
+
+(defun slime-repl-eol ()
+ "Go to the end of line or the prompt."
+ (interactive)
+ (if (and (<= (point) slime-repl-input-end-mark)
+ (slime-same-line-p (point) slime-repl-input-end-mark))
+ (goto-char slime-repl-input-end-mark)
+ (end-of-line 1))
+ (slime-preserve-zmacs-region))
+
+(defun slime-preserve-zmacs-region ()
+ "In XEmacs, ensure that the zmacs-region stays active after this command."
+ (when (boundp 'zmacs-region-stays)
+ (set 'zmacs-region-stays t)))
+
+(defun slime-repl-in-input-area-p ()
+ (and (<= slime-repl-input-start-mark (point))
+ (<= (point) slime-repl-input-end-mark)))
+
+(defun slime-repl-at-prompt-start-p ()
+ ;; This will not work on non-current prompts.
+ (= (point) slime-repl-input-start-mark))
+
+(defun slime-repl-beginning-of-defun ()
+ "Move to beginning of defun."
+ (interactive)
+ ;; We call BEGINNING-OF-DEFUN if we're at the start of a prompt
+ ;; already, to trigger SLIME-REPL-MODE-BEGINNING-OF-DEFUN by means
+ ;; of the locally bound BEGINNING-OF-DEFUN-FUNCTION, in order to
+ ;; jump to the start of the previous prompt.
+ (if (and (not (slime-repl-at-prompt-start-p))
+ (slime-repl-in-input-area-p))
+ (goto-char slime-repl-input-start-mark)
+ (beginning-of-defun))
+ t)
+
+(defun slime-repl-end-of-defun ()
+ "Move to next of defun."
+ (interactive)
+ ;; C.f. SLIME-REPL-BEGINNING-OF-DEFUN.
+ (if (and (not (= (point) slime-repl-input-end-mark))
+ (slime-repl-in-input-area-p))
+ (goto-char slime-repl-input-end-mark)
+ (end-of-defun))
+ t)
+
+;; FIXME: Shouldn't this be (= (point) slime-repl-input-end-mark)?
+(defun slime-repl-at-prompt-end-p ()
+ (and (get-char-property (max 1 (1- (point))) 'slime-repl-prompt)
+ (not (get-char-property (point) 'slime-repl-prompt))))
+
+(defun slime-repl-find-prompt (move)
+ (let ((origin (point)))
+ (loop (funcall move)
+ (when (or (slime-repl-at-prompt-end-p) (bobp) (eobp))
+ (return)))
+ (unless (slime-repl-at-prompt-end-p)
+ (goto-char origin))))
+
+(defun slime-search-property-change-fn (prop &optional backward)
+ (with-lexical-bindings (prop)
+ (if backward
+ (lambda ()
+ (goto-char
+ (previous-single-char-property-change (point) prop)))
+ (lambda ()
+ (goto-char
+ (next-single-char-property-change (point) prop))))))
+
+(defun slime-repl-previous-prompt ()
+ "Move backward to the previous prompt."
+ (interactive)
+ (slime-repl-find-prompt
+ (slime-search-property-change-fn 'slime-repl-prompt t)))
+
+(defun slime-repl-next-prompt ()
+ "Move forward to the next prompt."
+ (interactive)
+ (slime-repl-find-prompt
+ (slime-search-property-change-fn 'slime-repl-prompt)))
+
+(defvar slime-repl-return-hooks)
+
+(defun slime-repl-return (&optional end-of-input)
+ "Evaluate the current input string, or insert a newline.
+Send the current input ony if a whole expression has been entered,
+i.e. the parenthesis are matched.
+
+With prefix argument send the input even if the parenthesis are not
+balanced."
+ (interactive "P")
+ (slime-check-connected)
+ (assert (<= (point) slime-repl-input-end-mark))
+ (cond (end-of-input
+ (slime-repl-send-input))
+ (slime-repl-read-mode ; bad style?
+ (slime-repl-send-input t))
+ ((and (get-text-property (point) 'slime-repl-old-input)
+ (< (point) slime-repl-input-start-mark))
+ (slime-repl-grab-old-input end-of-input)
+ (slime-repl-recenter-if-needed))
+ ((run-hook-with-args-until-success 'slime-repl-return-hooks))
+ ((slime-input-complete-p slime-repl-input-start-mark
+ (ecase slime-repl-return-behaviour
+ (:send-only-if-after-complete (min (point) slime-repl-input-end-mark))
+ (:send-if-complete slime-repl-input-end-mark)))
+ (slime-repl-send-input t))
+ (t
+ (slime-repl-newline-and-indent)
+ (message "[input not complete]"))))
+
+(defun slime-repl-recenter-if-needed ()
+ "Make sure that slime-repl-input-end-mark is visible."
+ (unless (pos-visible-in-window-p slime-repl-input-end-mark)
+ (save-excursion
+ (goto-char slime-repl-input-end-mark)
+ (recenter -1))))
+
+(defun slime-repl-send-input (&optional newline)
+ "Goto to the end of the input and send the current input.
+If NEWLINE is true then add a newline at the end of the input."
+ (when (< (point) slime-repl-input-start-mark)
+ (error "No input at point."))
+ (goto-char slime-repl-input-end-mark)
+ (let ((end (point))) ; end of input, without the newline
+ (slime-repl-add-to-input-history
+ (buffer-substring slime-repl-input-start-mark end))
+ (when newline
+ (insert "\n")
+ (slime-repl-show-maximum-output))
+ (let ((inhibit-read-only t))
+ (add-text-properties slime-repl-input-start-mark
+ (point)
+ `(slime-repl-old-input
+ ,(incf slime-repl-old-input-counter))))
+ (let ((overlay (make-overlay slime-repl-input-start-mark end)))
+ ;; These properties are on an overlay so that they won't be taken
+ ;; by kill/yank.
+ (overlay-put overlay 'read-only t)
+ (overlay-put overlay 'face 'slime-repl-input-face)))
+ (let ((input (slime-repl-current-input)))
+ (goto-char slime-repl-input-end-mark)
+ (slime-mark-input-start)
+ (slime-mark-output-start)
+ (slime-repl-send-string input)))
+
+(defun slime-repl-grab-old-input (replace)
+ "Resend the old REPL input at point.
+If replace is non-nil the current input is replaced with the old
+input; otherwise the new input is appended. The old input has the
+text property `slime-repl-old-input'."
+ (multiple-value-bind (beg end) (slime-property-bounds 'slime-repl-old-input)
+ (let ((old-input (buffer-substring beg end)) ;;preserve
+ ;;properties, they will be removed later
+ (offset (- (point) beg)))
+ ;; Append the old input or replace the current input
+ (cond (replace (goto-char slime-repl-input-start-mark))
+ (t (goto-char slime-repl-input-end-mark)
+ (unless (eq (char-before) ?\ )
+ (insert " "))))
+ (delete-region (point) slime-repl-input-end-mark)
+ (save-excursion (insert old-input))
+ (forward-char offset))))
+
+(defun slime-property-bounds (prop)
+ "Return two the positions of the previous and next changes to PROP.
+PROP is the name of a text property."
+ (let* ((beg (save-excursion
+ ;; previous-single-char-property-change searches for a
+ ;; property change from the previous character, but we
+ ;; want to look for a change from the point. We step
+ ;; forward one char to avoid doing the wrong thing if
+ ;; we're at the beginning of the old input. -luke
+ ;; (18/Jun/2004)
+ (unless (not (get-text-property (point) prop))
+ ;; alanr unless we are sitting right after it May 19, 2005
+ (ignore-errors (forward-char)))
+ (previous-single-char-property-change (point) prop)))
+ (end (save-excursion
+ (if (get-text-property (point) prop)
+ (progn (goto-char (next-single-char-property-change
+ (point) prop))
+ (skip-chars-backward "\n \t\r" beg)
+ (point))
+ (point)))))
+ (values beg end)))
+
+(defun slime-repl-closing-return ()
+ "Evaluate the current input string after closing all open lists."
+ (interactive)
+ (goto-char (point-max))
+ (save-restriction
+ (narrow-to-region slime-repl-input-start-mark (point))
+ (while (ignore-errors (save-excursion (backward-up-list 1)) t)
+ (insert ")")))
+ (slime-repl-return))
+
+(defun slime-repl-newline-and-indent ()
+ "Insert a newline, then indent the next line.
+Restrict the buffer from the prompt for indentation, to avoid being
+confused by strange characters (like unmatched quotes) appearing
+earlier in the buffer."
+ (interactive)
+ (save-restriction
+ (narrow-to-region slime-repl-prompt-start-mark (point-max))
+ (insert "\n")
+ (lisp-indent-line)))
+
+(defun slime-repl-delete-current-input ()
+ (delete-region slime-repl-input-start-mark slime-repl-input-end-mark))
+
+(defun slime-repl-kill-input ()
+ "Kill all text from the prompt to point."
+ (interactive)
+ (cond ((< (marker-position slime-repl-input-start-mark) (point))
+ (kill-region slime-repl-input-start-mark (point)))
+ ((= (point) (marker-position slime-repl-input-start-mark))
+ (slime-repl-delete-current-input))))
+
+(defun slime-repl-replace-input (string)
+ (slime-repl-delete-current-input)
+ (insert-and-inherit string))
+
+(defun slime-repl-input-line-beginning-position ()
+ (save-excursion
+ (goto-char slime-repl-input-start-mark)
+ (line-beginning-position)))
+
+(defvar slime-repl-clear-buffer-hook)
+
+(defun slime-repl-clear-buffer ()
+ "Delete the output generated by the Lisp process."
+ (interactive)
+ (set-marker slime-repl-last-input-start-mark nil)
+ (let ((inhibit-read-only t))
+ (delete-region (point-min) (slime-repl-input-line-beginning-position))
+ (goto-char slime-repl-input-start-mark))
+ (run-hooks 'slime-repl-clear-buffer-hook))
+
+(defun slime-repl-clear-output ()
+ "Delete the output inserted since the last input."
+ (interactive)
+ (let ((start (save-excursion
+ (slime-repl-previous-prompt)
+ (ignore-errors (forward-sexp))
+ (forward-line)
+ (point)))
+ (end (1- (slime-repl-input-line-beginning-position))))
+ (when (< start end)
+ (let ((inhibit-read-only t))
+ (delete-region start end)
+ (save-excursion
+ (goto-char start)
+ (insert ";;; output flushed"))))))
+
+(defun slime-indent-and-complete-symbol ()
+ "Indent the current line and perform symbol completion.
+First indent the line. If indenting doesn't move point, complete
+the symbol. If there's no symbol at the point, show the arglist
+for the most recently enclosed macro or function."
+ (interactive)
+ (let ((pos (point)))
+ (unless (get-text-property (line-beginning-position) 'slime-repl-prompt)
+ (lisp-indent-line))
+ (when (= pos (point))
+ (cond ((save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t))
+ (slime-complete-symbol))
+ ((memq (char-before) '(?\t ?\ ))
+ (slime-echo-arglist))))))
+
+(defun slime-repl-set-package (package)
+ "Set the package of the REPL buffer to PACKAGE."
+ (interactive (list (slime-read-package-name
+ "Package: " (slime-pretty-find-buffer-package))))
+ (with-current-buffer (slime-output-buffer)
+ (let ((unfinished-input (slime-repl-current-input)))
+ (destructuring-bind (name prompt-string)
+ (slime-eval `(swank:set-package ,package))
+ (setf (slime-lisp-package) name)
+ (setf (slime-lisp-package-prompt-string) prompt-string)
+ (slime-repl-insert-prompt)
+ (insert unfinished-input)))))
+
+
+;;;;; History
+
+(defcustom slime-repl-wrap-history nil
+ "*T to wrap history around when the end is reached."
+ :type 'boolean
+ :group 'slime-repl)
+
+(make-variable-buffer-local
+ (defvar slime-repl-input-history '()
+ "History list of strings read from the REPL buffer."))
+
+(defun slime-repl-add-to-input-history (string)
+ "Add STRING to the input history.
+Empty strings and duplicates are ignored."
+ (unless (or (equal string "")
+ (equal string (car slime-repl-input-history)))
+ (push string slime-repl-input-history)))
+
+;; These two vars contain the state of the last history search. We
+;; only use them if `last-command' was 'slime-repl-history-replace,
+;; otherwise we reinitialize them.
+
+(defvar slime-repl-input-history-position -1
+ "Newer items have smaller indices.")
+
+(defvar slime-repl-history-pattern nil
+ "The regexp most recently used for finding input history.")
+
+(defun slime-repl-history-replace (direction &optional regexp delete-at-end-p)
+ "Replace the current input with the next line in DIRECTION.
+DIRECTION is 'forward' or 'backward' (in the history list).
+If REGEXP is non-nil, only lines matching REGEXP are considered.
+If DELETE-AT-END-P is non-nil then remove the string if the end of the
+history is reached."
+ (setq slime-repl-history-pattern regexp)
+ (let* ((min-pos -1)
+ (max-pos (length slime-repl-input-history))
+ (pos0 (cond ((slime-repl-history-search-in-progress-p)
+ slime-repl-input-history-position)
+ (t min-pos)))
+ (pos (slime-repl-position-in-history pos0 direction (or regexp "")))
+ (msg nil))
+ (cond ((and (< min-pos pos) (< pos max-pos))
+ (slime-repl-replace-input (nth pos slime-repl-input-history))
+ (setq msg (format "History item: %d" pos)))
+ ((not slime-repl-wrap-history)
+ (setq msg (cond ((= pos min-pos) "End of history")
+ ((= pos max-pos) "Beginning of history"))))
+ (slime-repl-wrap-history
+ (setq pos (if (= pos min-pos) max-pos min-pos))
+ (setq msg "Wrapped history")))
+ (when (or (<= pos min-pos) (<= max-pos pos))
+ (when regexp
+ (setq msg (concat msg "; no matching item")))
+ (when delete-at-end-p
+ (slime-repl-replace-input "")))
+ ;;(message "%s [%d %d %s]" msg start-pos pos regexp)
+ (message "%s%s" msg (cond ((not regexp) "")
+ (t (format "; current regexp: %s" regexp))))
+ (setq slime-repl-input-history-position pos)
+ (setq this-command 'slime-repl-history-replace)))
+
+(defun slime-repl-history-search-in-progress-p ()
+ (eq last-command 'slime-repl-history-replace))
+
+(defun slime-repl-terminate-history-search ()
+ (setq last-command this-command))
+
+(defun slime-repl-position-in-history (start-pos direction regexp)
+ "Return the position of the history item matching regexp.
+Return -1 resp. the length of the history if no item matches"
+ ;; Loop through the history list looking for a matching line
+ (let* ((step (ecase direction
+ (forward -1)
+ (backward 1)))
+ (history slime-repl-input-history)
+ (len (length history)))
+ (loop for pos = (+ start-pos step) then (+ pos step)
+ if (< pos 0) return -1
+ if (<= len pos) return len
+ if (string-match regexp (nth pos history)) return pos)))
+
+(defun slime-repl-previous-input ()
+ "Cycle backwards through input history.
+If the `last-command' was a history navigation command use the
+same search pattern for this command.
+Otherwise use the current input as search pattern."
+ (interactive)
+ (slime-repl-history-replace 'backward (slime-repl-history-pattern t) t))
+
+(defun slime-repl-next-input ()
+ "Cycle forwards through input history.
+See `slime-repl-previous-input'."
+ (interactive)
+ (slime-repl-history-replace 'forward (slime-repl-history-pattern t) t))
+
+(defun slime-repl-forward-input ()
+ "Cycle forwards through input history."
+ (interactive)
+ (slime-repl-history-replace 'forward (slime-repl-history-pattern) t))
+
+(defun slime-repl-backward-input ()
+ "Cycle backwards through input history."
+ (interactive)
+ (slime-repl-history-replace 'backward (slime-repl-history-pattern) t))
+
+(defun slime-repl-previous-matching-input (regexp)
+ (interactive "sPrevious element matching (regexp): ")
+ (slime-repl-terminate-history-search)
+ (slime-repl-history-replace 'backward regexp))
+
+(defun slime-repl-next-matching-input (regexp)
+ (interactive "sNext element matching (regexp): ")
+ (slime-repl-terminate-history-search)
+ (slime-repl-history-replace 'forward regexp))
+
+(defun slime-repl-history-pattern (&optional use-current-input)
+ "Return the regexp for the navigation commands."
+ (cond ((slime-repl-history-search-in-progress-p)
+ slime-repl-history-pattern)
+ (use-current-input
+ (let ((str (slime-repl-current-input)))
+ (cond ((string-match "^[ \n]*$" str) nil)
+ (t (concat "^" (regexp-quote str))))))
+ (t nil)))
+
+(defun slime-repl-delete-from-input-history (string)
+ "Delete STRING from the repl input history.
+
+When string is not provided then clear the current repl input and
+use it as an input. This is useful to get rid of unwanted repl
+history entries while navigating the repl history."
+ (interactive (list (slime-repl-current-input)))
+ (let ((merged-history
+ (slime-repl-merge-histories slime-repl-input-history
+ (slime-repl-read-history nil t))))
+ (setq slime-repl-input-history
+ (delete* string merged-history :test #'string=))
+ (slime-repl-save-history))
+ (slime-repl-delete-current-input))
+
+;;;;; Persistent History
+
+(defun slime-repl-merge-histories (old-hist new-hist)
+ "Merge entries from OLD-HIST and NEW-HIST."
+ ;; Newer items in each list are at the beginning.
+ (let* ((ht (make-hash-table :test #'equal))
+ (test (lambda (entry)
+ (or (gethash entry ht)
+ (progn (setf (gethash entry ht) t)
+ nil)))))
+ (append (remove-if test new-hist)
+ (remove-if test old-hist))))
+
+(defun slime-repl-load-history (&optional filename)
+ "Set the current SLIME REPL history.
+It can be read either from FILENAME or `slime-repl-history-file' or
+from a user defined filename."
+ (interactive (list (slime-repl-read-history-filename)))
+ (let ((file (or filename slime-repl-history-file)))
+ (setq slime-repl-input-history (slime-repl-read-history file t))))
+
+(defun slime-repl-read-history (&optional filename noerrer)
+ "Read and return the history from FILENAME.
+The default value for FILENAME is `slime-repl-history-file'.
+If NOERROR is true return and the file doesn't exits return nil."
+ (let ((file (or filename slime-repl-history-file)))
+ (cond ((not (file-readable-p file)) '())
+ (t (with-temp-buffer
+ (insert-file-contents file)
+ (read (current-buffer)))))))
+
+(defun slime-repl-read-history-filename ()
+ (read-file-name "Use SLIME REPL history from file: "
+ slime-repl-history-file))
+
+(defun slime-repl-save-merged-history (&optional filename)
+ "Read the history file, merge the current REPL history and save it.
+This tries to be smart in merging the history from the file and the
+current history in that it tries to detect the unique entries using
+`slime-repl-merge-histories'."
+ (interactive (list (slime-repl-read-history-filename)))
+ (let ((file (or filename slime-repl-history-file)))
+ (with-temp-message "saving history..."
+ (let ((hist (slime-repl-merge-histories (slime-repl-read-history file t)
+ slime-repl-input-history)))
+ (slime-repl-save-history file hist)))))
+
+(defun slime-repl-save-history (&optional filename history)
+ "Simply save the current SLIME REPL history to a file.
+When SLIME is setup to always load the old history and one uses only
+one instance of slime all the time, there is no need to merge the
+files and this function is sufficient.
+
+When the list is longer than `slime-repl-history-size' it will be
+truncated. That part is untested, though!"
+ (interactive (list (slime-repl-read-history-filename)))
+ (let ((file (or filename slime-repl-history-file))
+ (hist (or history slime-repl-input-history)))
+ (unless (file-writable-p file)
+ (error (format "History file not writable: %s" file)))
+ (let ((hist (subseq hist 0 (min (length hist) slime-repl-history-size))))
+ ;;(message "saving %s to %s\n" hist file)
+ (with-temp-file file
+ (let ((cs slime-repl-history-file-coding-system)
+ (print-length nil) (print-level nil))
+ (setq buffer-file-coding-system cs)
+ (insert (format ";; -*- coding: %s -*-\n" cs))
+ (insert ";; History for SLIME REPL. Automatically written.\n"
+ ";; Edit only if you know what you're doing\n")
+ (prin1 (mapcar #'substring-no-properties hist) (current-buffer)))))))
+
+(defun slime-repl-save-all-histories ()
+ "Save the history in each repl buffer."
+ (dolist (b (buffer-list))
+ (with-current-buffer b
+ (when (eq major-mode 'slime-repl-mode)
+ (slime-repl-safe-save-merged-history)))))
+
+(defun slime-repl-safe-save-merged-history ()
+ (slime-repl-call-with-handler
+ #'slime-repl-save-merged-history
+ "%S while saving the history. Continue? "))
+
+(defun slime-repl-safe-load-history ()
+ (slime-repl-call-with-handler
+ #'slime-repl-load-history
+ "%S while loading the history. Continue? "))
+
+(defun slime-repl-call-with-handler (fun query)
+ "Call FUN in the context of an error handler.
+The handler will use qeuery to ask the use if the error should be ingored."
+ (condition-case err
+ (funcall fun)
+ (error
+ (if (y-or-n-p (format query (error-message-string err)))
+ nil
+ (signal (car err) (cdr err))))))
+
+
+;;;;; REPL Read Mode
+
+(define-key slime-repl-mode-map
+ (string slime-repl-shortcut-dispatch-char) 'slime-handle-repl-shortcut)
+
+(define-minor-mode slime-repl-read-mode
+ "Mode the read input from Emacs
+\\{slime-repl-read-mode-map}"
+ nil
+ "[read]"
+ '(("\C-m" . slime-repl-return)
+ ([return] . slime-repl-return)
+ ("\C-c\C-b" . slime-repl-read-break)
+ ("\C-c\C-c" . slime-repl-read-break)))
+
+(make-variable-buffer-local
+ (defvar slime-read-string-threads nil))
+
+(make-variable-buffer-local
+ (defvar slime-read-string-tags nil))
+
+(defun slime-repl-read-string (thread tag)
+ (slime-switch-to-output-buffer)
+ (push thread slime-read-string-threads)
+ (push tag slime-read-string-tags)
+ (goto-char (point-max))
+ (slime-mark-output-end)
+ (slime-mark-input-start)
+ (slime-repl-read-mode 1))
+
+(defun slime-y-or-n-p (thread tag question)
+ (slime-dispatch-event `(:emacs-return ,thread ,tag ,(y-or-n-p question))))
+
+(defun slime-repl-return-string (string)
+ (slime-dispatch-event `(:emacs-return-string
+ ,(pop slime-read-string-threads)
+ ,(pop slime-read-string-tags)
+ ,string))
+ (slime-repl-read-mode -1))
+
+(defun slime-repl-read-break ()
+ (interactive)
+ (slime-dispatch-event `(:emacs-interrupt ,(car slime-read-string-threads))))
+
+(defun slime-repl-abort-read (thread tag)
+ (with-current-buffer (slime-output-buffer)
+ (pop slime-read-string-threads)
+ (pop slime-read-string-tags)
+ (slime-repl-read-mode -1)
+ (message "Read aborted")))
+
+
+;;;;; REPL handlers
+
+(defstruct (slime-repl-shortcut (:conc-name slime-repl-shortcut.))
+ symbol names handler one-liner)
+
+(defvar slime-repl-shortcut-table nil
+ "A list of slime-repl-shortcuts")
+
+(defvar slime-repl-shortcut-history '()
+ "History list of shortcut command names.")
+
+(defun slime-handle-repl-shortcut ()
+ (interactive)
+ (if (> (point) slime-repl-input-start-mark)
+ (insert (string slime-repl-shortcut-dispatch-char))
+ (let ((shortcut (slime-lookup-shortcut
+ (completing-read "Command: "
+ (slime-bogus-completion-alist
+ (slime-list-all-repl-shortcuts))
+ nil t nil
+ 'slime-repl-shortcut-history))))
+ (call-interactively (slime-repl-shortcut.handler shortcut)))))
+
+(defun slime-list-all-repl-shortcuts ()
+ (loop for shortcut in slime-repl-shortcut-table
+ append (slime-repl-shortcut.names shortcut)))
+
+(defun slime-lookup-shortcut (name)
+ (find-if (lambda (s) (member name (slime-repl-shortcut.names s)))
+ slime-repl-shortcut-table))
+
+(defmacro defslime-repl-shortcut (elisp-name names &rest options)
+ "Define a new repl shortcut. ELISP-NAME is a symbol specifying
+ the name of the interactive function to create, or NIL if no
+ function should be created. NAMES is a list of (full-name .
+ aliases). OPTIONS is an olist specifying the handler and the
+ help text."
+ `(progn
+ ,(when elisp-name
+ `(defun ,elisp-name ()
+ (interactive)
+ (call-interactively ,(second (assoc :handler options)))))
+ (let ((new-shortcut (make-slime-repl-shortcut
+ :symbol ',elisp-name
+ :names (list , at names)
+ ,@(apply #'append options))))
+ (setq slime-repl-shortcut-table
+ (remove-if (lambda (s)
+ (member ',(car names) (slime-repl-shortcut.names s)))
+ slime-repl-shortcut-table))
+ (push new-shortcut slime-repl-shortcut-table)
+ ',elisp-name)))
+
+(defun slime-list-repl-short-cuts ()
+ (interactive)
+ (slime-with-output-to-temp-buffer ("*slime-repl-help*") nil
+ (let ((table (sort* (copy-list slime-repl-shortcut-table) #'string<
+ :key (lambda (x)
+ (car (slime-repl-shortcut.names x))))))
+ (dolist (shortcut table)
+ (let ((names (slime-repl-shortcut.names shortcut)))
+ (insert (pop names)) ;; first print the "full" name
+ (when names
+ ;; we also have aliases
+ (insert " (aka ")
+ (while (cdr names)
+ (insert (pop names) ", "))
+ (insert (car names) ")"))
+ (insert "\n " (slime-repl-shortcut.one-liner shortcut)
+ "\n"))))))
+
+(defun slime-save-some-lisp-buffers ()
+ (if slime-repl-only-save-lisp-buffers
+ (save-some-buffers nil (lambda ()
+ (and (memq major-mode slime-lisp-modes)
+ (not (null buffer-file-name)))))
+ (save-some-buffers)))
+
+(defslime-repl-shortcut slime-repl-shortcut-help ("help" "?")
+ (:handler 'slime-list-repl-short-cuts)
+ (:one-liner "Display the help."))
+
+(defslime-repl-shortcut nil ("change-directory" "!d" "cd")
+ (:handler 'slime-set-default-directory)
+ (:one-liner "Change the current directory."))
+
+(defslime-repl-shortcut nil ("pwd")
+ (:handler (lambda ()
+ (interactive)
+ (let ((dir (slime-eval `(swank:default-directory))))
+ (message "Directory %s" dir))))
+ (:one-liner "Show the current directory."))
+
+(defslime-repl-shortcut slime-repl-push-directory
+ ("push-directory" "+d" "pushd")
+ (:handler (lambda (directory)
+ (interactive
+ (list (read-directory-name
+ "Push directory: "
+ (slime-eval '(swank:default-directory))
+ nil nil "")))
+ (push (slime-eval '(swank:default-directory))
+ slime-repl-directory-stack)
+ (slime-set-default-directory directory)))
+ (:one-liner "Save the current directory and set it to a new one."))
+
+(defslime-repl-shortcut slime-repl-pop-directory
+ ("pop-directory" "-d" "popd")
+ (:handler (lambda ()
+ (interactive)
+ (if (null slime-repl-directory-stack)
+ (message "Directory stack is empty.")
+ (slime-set-default-directory
+ (pop slime-repl-directory-stack)))))
+ (:one-liner "Restore the last saved directory."))
+
+(defslime-repl-shortcut nil ("change-package" "!p" "in-package" "in")
+ (:handler 'slime-repl-set-package)
+ (:one-liner "Change the current package."))
+
+(defslime-repl-shortcut slime-repl-push-package ("push-package" "+p")
+ (:handler (lambda (package)
+ (interactive (list (slime-read-package-name "Package: ")))
+ (push (slime-lisp-package) slime-repl-package-stack)
+ (slime-repl-set-package package)))
+ (:one-liner "Save the current package and set it to a new one."))
+
+(defslime-repl-shortcut slime-repl-pop-package ("pop-package" "-p")
+ (:handler (lambda ()
+ (interactive)
+ (if (null slime-repl-package-stack)
+ (message "Package stack is empty.")
+ (slime-repl-set-package
+ (pop slime-repl-package-stack)))))
+ (:one-liner "Restore the last saved package."))
+
+(defslime-repl-shortcut slime-repl-resend ("resend-form")
+ (:handler (lambda ()
+ (interactive)
+ (insert (car slime-repl-input-history))
+ (insert "\n")
+ (slime-repl-send-input)))
+ (:one-liner "Resend the last form."))
+
+(defslime-repl-shortcut slime-repl-disconnect ("disconnect")
+ (:handler 'slime-disconnect)
+ (:one-liner "Disconnect all connections."))
+
+(defslime-repl-shortcut slime-repl-sayoonara ("sayoonara")
+ (:handler (lambda ()
+ (interactive)
+ (when (slime-connected-p)
+ (slime-quit-lisp))
+ (slime-kill-all-buffers)))
+ (:one-liner "Quit all Lisps and close all SLIME buffers."))
+
+(defslime-repl-shortcut slime-repl-quit ("quit")
+ (:handler 'slime-quit-lisp)
+ (:one-liner "Quit the current Lisp."))
+
+(defslime-repl-shortcut slime-repl-defparameter ("defparameter" "!")
+ (:handler (lambda (name value)
+ (interactive (list (slime-read-symbol-name "Name (symbol): " t)
+ (slime-read-from-minibuffer "Value: " "*")))
+ (insert "(cl:defparameter " name " " value
+ " \"REPL generated global variable.\")")
+ (slime-repl-send-input t)))
+ (:one-liner "Define a new global, special, variable."))
+
+(defslime-repl-shortcut slime-repl-compile-and-load ("compile-and-load" "cl")
+ (:handler (lambda (filename)
+ (interactive (list (expand-file-name
+ (read-file-name "File: " nil nil nil nil))))
+ (slime-save-some-lisp-buffers)
+ (slime-eval-async
+ `(swank:compile-file-if-needed
+ ,(slime-to-lisp-filename filename) t)
+ (slime-make-compilation-finished-continuation (current-buffer)))))
+ (:one-liner "Compile (if neccessary) and load a lisp file."))
+
+(defslime-repl-shortcut nil ("restart-inferior-lisp")
+ (:handler 'slime-restart-inferior-lisp)
+ (:one-liner "Restart *inferior-lisp* and reconnect SLIME."))
+
+(defun slime-restart-inferior-lisp ()
+ (interactive)
+ (assert (slime-inferior-process) () "No inferior lisp process")
+ (slime-eval-async '(swank:quit-lisp))
+ (set-process-filter (slime-connection) nil)
+ (set-process-sentinel (slime-connection) 'slime-restart-sentinel))
+
+(defun slime-restart-sentinel (process message)
+ "Restart the inferior lisp process.
+Also rearrange windows."
+ (assert (process-status process) 'closed)
+ (let* ((proc (slime-inferior-process process))
+ (args (slime-inferior-lisp-args proc))
+ (buffer (buffer-name (process-buffer proc)))
+ (buffer-window (get-buffer-window buffer))
+ (new-proc (slime-start-lisp (plist-get args :program)
+ (plist-get args :program-args)
+ nil
+ buffer))
+ (repl-buffer (slime-repl-buffer nil process))
+ (repl-window (and repl-buffer (get-buffer-window repl-buffer))))
+ (slime-net-close process)
+ (slime-inferior-connect new-proc args)
+ (cond ((and repl-window (not buffer-window))
+ (set-window-buffer repl-window buffer)
+ (select-window repl-window))
+ (repl-window
+ (select-window repl-window))
+ (t
+ (pop-to-buffer buffer)))
+ (switch-to-buffer buffer)
+ (goto-char (point-max))))
+
+
+;;;;; Cleanup after a quit
+
+(defun slime-kill-all-buffers ()
+ "Kill all the slime related buffers. This is only used by the
+ repl command sayoonara."
+ (dolist (buf (buffer-list))
+ (when (or (string= (buffer-name buf) slime-event-buffer-name)
+ (string-match "^\\*inferior-lisp*" (buffer-name buf))
+ (string-match "^\\*slime-repl .*\\*$" (buffer-name buf))
+ (string-match "^\\*sldb .*\\*$" (buffer-name buf))
+ (string-match "^\\*SLIME.*\\*$" (buffer-name buf)))
+ (kill-buffer buf))))
+
+
+;;;; Compilation and the creation of compiler-note annotations
+
+(defvar slime-highlight-compiler-notes t
+ "*When non-nil annotate buffers with compilation notes etc.")
+
+(defcustom slime-display-compilation-output t
+ "Display the REPL buffer before compiling files."
+ :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil))
+ :group 'slime-mode)
+
+(defvar slime-before-compile-functions nil
+ "A list of function called before compiling a buffer or region.
+The function receive two arguments: the beginning and the end of the
+region that will be compiled.")
+
+(defcustom slime-compilation-finished-hook 'slime-maybe-list-compiler-notes
+ "Hook called with a list of compiler notes after a compilation."
+ :group 'slime-mode
+ :type 'hook
+ :options '(slime-maybe-list-compiler-notes
+ slime-list-compiler-notes
+ slime-maybe-show-xrefs-for-notes))
+
+(defcustom slime-goto-first-note-after-compilation nil
+ "When T next-note will always goto to the first note in a
+final, no matter where the point is."
+ :group 'slime-mode
+ :type 'boolean)
+
+(defun slime-compile-and-load-file ()
+ "Compile and load the buffer's file and highlight compiler notes.
+
+Each source location that is the subject of a compiler note is
+underlined and annotated with the relevant information. The commands
+`slime-next-note' and `slime-previous-note' can be used to navigate
+between compiler notes and to display their full details."
+ (interactive)
+ (slime-compile-file t))
+
+(defun slime-compile-file (&optional load)
+ "Compile current buffer's file and highlight resulting compiler notes.
+
+See `slime-compile-and-load-file' for further details."
+ (interactive)
+ ;;(unless (memq major-mode slime-lisp-modes)
+ ;; (error "Only valid in lisp-mode"))
+ (check-parens)
+ (unless buffer-file-name
+ (error "Buffer %s is not associated with a file." (buffer-name)))
+ (when (and (buffer-modified-p)
+ (y-or-n-p (format "Save file %s? " (buffer-file-name))))
+ (save-buffer))
+ (run-hook-with-args 'slime-before-compile-functions (point-min) (point-max))
+ (let ((file (slime-to-lisp-filename (buffer-file-name))))
+ (slime-insert-transcript-delimiter (format "Compile file %s" file))
+ (when slime-display-compilation-output
+ (slime-display-output-buffer))
+ (slime-eval-async
+ `(swank:compile-file-for-emacs ,file ,(if load t nil))
+ (slime-rcurry #'slime-compilation-finished (current-buffer)))
+ (message "Compiling %s..." file)))
+
+(defun slime-compile-defun ()
+ "Compile the current toplevel form."
+ (interactive)
+ (apply #'slime-compile-region (slime-region-for-defun-at-point)))
+
+(defun slime-compile-region (start end)
+ "Compile the region."
+ (interactive "r")
+ (run-hook-with-args 'slime-before-compile-functions start end)
+ (slime-compile-string (buffer-substring-no-properties start end) start))
+
+(defun slime-compile-string (string start-offset)
+ (slime-eval-async
+ `(swank:compile-string-for-emacs
+ ,string
+ ,(buffer-name)
+ ,start-offset
+ ,(if (buffer-file-name) (file-name-directory (buffer-file-name))))
+ (slime-make-compilation-finished-continuation (current-buffer))))
+
+(defun slime-note-count-string (severity count &optional suppress-if-zero)
+ (cond ((and (zerop count) suppress-if-zero)
+ "")
+ (t (format "%2d %s%s " count severity (if (= count 1) "" "s")))))
+
+(defun slime-show-note-counts (notes &optional secs)
+ (let ((nerrors 0) (nwarnings 0) (nstyle-warnings 0) (nnotes 0))
+ (dolist (note notes)
+ (ecase (slime-note.severity note)
+ ((:error :read-error) (incf nerrors))
+ (:warning (incf nwarnings))
+ (:style-warning (incf nstyle-warnings))
+ (:note (incf nnotes))))
+ (message "Compilation finished:%s%s%s%s%s"
+ (slime-note-count-string "error" nerrors)
+ (slime-note-count-string "warning" nwarnings)
+ (slime-note-count-string "style-warning" nstyle-warnings t)
+ (slime-note-count-string "note" nnotes)
+ (if secs (format "[%s secs]" secs) ""))))
+
+(defun slime-xrefs-for-notes (notes)
+ (let ((xrefs))
+ (dolist (note notes)
+ (let* ((location (getf note :location))
+ (fn (cadr (assq :file (cdr location))))
+ (file (assoc fn xrefs))
+ (node
+ (cons (format "%s: %s"
+ (getf note :severity)
+ (slime-one-line-ify (getf note :message)))
+ location)))
+ (when fn
+ (if file
+ (push node (cdr file))
+ (setf xrefs (acons fn (list node) xrefs))))))
+ xrefs))
+
+(defun slime-one-line-ify (string)
+ "Return a single-line version of STRING.
+Each newlines and following indentation is replaced by a single space."
+ (with-temp-buffer
+ (insert string)
+ (goto-char (point-min))
+ (while (re-search-forward "\n[\n \t]*" nil t)
+ (replace-match " "))
+ (buffer-string)))
+
+(defun slime-compilation-finished (result buffer &optional emacs-snapshot)
+ (let ((notes (slime-compiler-notes)))
+ (with-current-buffer buffer
+ (setf slime-compilation-just-finished t)
+ (destructuring-bind (result secs) result
+ (slime-show-note-counts notes secs)
+ (when slime-highlight-compiler-notes
+ (slime-highlight-notes notes))))
+ (run-hook-with-args 'slime-compilation-finished-hook notes emacs-snapshot)))
+
+(defun slime-make-compilation-finished-continuation (current-buffer &optional emacs-snapshot)
+ (lexical-let ((buffer current-buffer) (snapshot emacs-snapshot))
+ (lambda (result)
+ (slime-compilation-finished result buffer snapshot))))
+
+(defun slime-highlight-notes (notes)
+ "Highlight compiler notes, warnings, and errors in the buffer."
+ (interactive (list (slime-compiler-notes)))
+ (with-temp-message "Highlighting notes..."
+ (save-excursion
+ (save-restriction
+ (widen) ; highlight notes on the whole buffer
+ (slime-remove-old-overlays)
+ (mapc #'slime-overlay-note (slime-merge-notes-for-display notes))))))
+
+(defun slime-compiler-notes ()
+ "Return all compiler notes, warnings, and errors."
+ (slime-eval `(swank:compiler-notes-for-emacs)))
+
+(defun slime-remove-old-overlays ()
+ "Delete the existing Slime overlays in the current buffer."
+ (dolist (buffer (slime-filter-buffers (lambda () slime-mode)))
+ (with-current-buffer buffer
+ (save-excursion
+ (save-restriction
+ (widen) ; remove overlays within the whole buffer.
+ (goto-char (point-min))
+ (while (not (eobp))
+ (dolist (o (overlays-at (point)))
+ (when (overlay-get o 'slime)
+ (delete-overlay o)))
+ (goto-char (next-overlay-change (point)))))))))
+
+(defun slime-filter-buffers (predicate)
+ "Return a list of where PREDICATE returns true.
+PREDICATE is executed in the buffer to test."
+ (remove-if-not (lambda (%buffer)
+ (with-current-buffer %buffer
+ (funcall predicate)))
+ (buffer-list)))
+
+
+;;;;; Merging together compiler notes in the same location.
+
+(defun slime-merge-notes-for-display (notes)
+ "Merge together notes that refer to the same location.
+This operation is \"lossy\" in the broad sense but not for display purposes."
+ (mapcar #'slime-merge-notes
+ (slime-group-similar 'slime-notes-in-same-location-p notes)))
+
+(defun slime-merge-notes (notes)
+ "Merge NOTES together. Keep the highest severity, concatenate the messages."
+ (let* ((new-severity (reduce #'slime-most-severe notes
+ :key #'slime-note.severity))
+ (new-message (mapconcat #'slime-note.short-message notes "\n")))
+ (let ((new-note (copy-list (car notes))))
+ (setf (getf new-note :message) new-message)
+ (setf (getf new-note :severity) new-severity)
+ new-note)))
+
+;; XXX: unused function
+(defun slime-intersperse (element list)
+ "Intersperse ELEMENT between each element of LIST."
+ (if (null list)
+ '()
+ (cons (car list)
+ (mapcan (lambda (x) (list element x)) (cdr list)))))
+
+(defun slime-notes-in-same-location-p (a b)
+ (equal (slime-note.location a) (slime-note.location b)))
+
+(defun slime-group-similar (similar-p list)
+ "Return the list of lists of 'similar' adjacent elements of LIST.
+The function SIMILAR-P is used to test for similarity.
+The order of the input list is preserved."
+ (if (null list)
+ nil
+ (let ((accumulator (list (list (car list)))))
+ (dolist (x (cdr list))
+ (if (funcall similar-p x (caar accumulator))
+ (push x (car accumulator))
+ (push (list x) accumulator)))
+ (reverse (mapcar #'reverse accumulator)))))
+
+
+;;;;; Compiler notes list
+
+(defun slime-maybe-show-xrefs-for-notes (&optional notes emacs-snapshot)
+ "Show the compiler notes NOTES if they come from more than one file."
+ (let* ((notes (or notes (slime-compiler-notes)))
+ (xrefs (slime-xrefs-for-notes notes)))
+ (when (slime-length> xrefs 1) ; >1 file
+ (slime-show-xrefs
+ xrefs 'definition "Compiler notes" (slime-current-package)
+ emacs-snapshot))))
+
+(defun slime-note-has-location-p (note)
+ (not (eq ':error (car (slime-note.location note)))))
+
+(defun slime-maybe-list-compiler-notes (notes &optional emacs-snapshot)
+ "Show the compiler notes if appropriate."
+ ;; don't pop up a buffer if all notes are already annotated in the
+ ;; buffer itself
+ (unless (every #'slime-note-has-location-p notes)
+ (slime-list-compiler-notes notes emacs-snapshot)))
+
+(defun slime-list-compiler-notes (notes &optional emacs-snapshot)
+ "Show the compiler notes NOTES in tree view."
+ (interactive (list (slime-compiler-notes)))
+ (with-temp-message "Preparing compiler note tree..."
+ (with-current-buffer
+ (slime-get-temp-buffer-create "*compiler notes*"
+ :mode 'slime-compiler-notes-mode
+ :emacs-snapshot emacs-snapshot)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (when (null notes)
+ (insert "[no notes]"))
+ (dolist (tree (slime-compiler-notes-to-tree notes))
+ (slime-tree-insert tree "")
+ (insert "\n")))
+ (setq buffer-read-only t)
+ (goto-char (point-min)))))
+
+(defun slime-alistify (list key test)
+ "Partition the elements of LIST into an alist.
+KEY extracts the key from an element and TEST is used to compare keys."
+ (declare (type function key))
+ (let ((alist '()))
+ (dolist (e list)
+ (let* ((k (funcall key e))
+ (probe (assoc* k alist :test test)))
+ (if probe
+ (push e (cdr probe))
+ (push (cons k (list e)) alist))))
+ ;; Put them back in order.
+ (loop for (key . value) in alist
+ collect (cons key (reverse value)))))
+
+(defun slime-note.severity (note)
+ (plist-get note :severity))
+
+(defun slime-note.message (note)
+ (plist-get note :message))
+
+(defun slime-note.short-message (note)
+ (or (plist-get note :short-message)
+ (plist-get note :message)))
+
+(defun slime-note.location (note)
+ (plist-get note :location))
+
+(defun slime-severity-label (severity)
+ (ecase severity
+ (:note "Notes")
+ (:warning "Warnings")
+ (:error "Errors")
+ (:read-error "Read Errors")
+ (:style-warning "Style Warnings")))
+
+(defvar slime-tree-printer 'slime-tree-default-printer)
+
+(defun slime-tree-for-note (note)
+ (make-slime-tree :item (slime-note.message note)
+ :plist (list 'note note)
+ :print-fn slime-tree-printer))
+
+(defun slime-tree-for-severity (severity notes collapsed-p)
+ (make-slime-tree :item (format "%s (%d)"
+ (slime-severity-label severity)
+ (length notes))
+ :kids (mapcar #'slime-tree-for-note notes)
+ :collapsed-p collapsed-p))
+
+(defun slime-compiler-notes-to-tree (notes)
+ (let* ((alist (slime-alistify notes #'slime-note.severity #'eq))
+ (collapsed-p (slime-length> alist 1)))
+ (loop for (severity . notes) in alist
+ collect (slime-tree-for-severity severity notes
+ collapsed-p))))
+
+(defvar slime-compiler-notes-mode-map)
+
+(define-derived-mode slime-compiler-notes-mode fundamental-mode
+ "Compiler Notes"
+ "\\<slime-compiler-notes-mode-map>\
+\\{slime-compiler-notes-mode-map}"
+ (slime-set-truncate-lines))
+
+(slime-define-keys slime-compiler-notes-mode-map
+ ((kbd "RET") 'slime-compiler-notes-default-action-or-show-details)
+ ([return] 'slime-compiler-notes-default-action-or-show-details)
+ ([mouse-2] 'slime-compiler-notes-default-action-or-show-details/mouse)
+ ("q" 'slime-temp-buffer-quit))
+
+(defun slime-compiler-notes-default-action-or-show-details/mouse (event)
+ "Invoke the action pointed at by the mouse, or show details."
+ (interactive "e")
+ (destructuring-bind (mouse-2 (w pos &rest _) &rest __) event
+ (save-excursion
+ (goto-char pos)
+ (let ((fn (get-text-property (point)
+ 'slime-compiler-notes-default-action)))
+ (if fn (funcall fn) (slime-compiler-notes-show-details))))))
+
+(defun slime-compiler-notes-default-action-or-show-details ()
+ "Invoke the action at point, or show details."
+ (interactive)
+ (let ((fn (get-text-property (point) 'slime-compiler-notes-default-action)))
+ (if fn (funcall fn) (slime-compiler-notes-show-details))))
+
+(defun slime-compiler-notes-show-details ()
+ (interactive)
+ (let* ((tree (slime-tree-at-point))
+ (note (plist-get (slime-tree.plist tree) 'note))
+ (inhibit-read-only t))
+ (cond ((not (slime-tree-leaf-p tree))
+ (slime-tree-toggle tree))
+ (t
+ (slime-show-source-location (slime-note.location note) t)))))
+
+
+;;;;;; Tree Widget
+
+(defstruct (slime-tree (:conc-name slime-tree.))
+ item
+ (print-fn #'slime-tree-default-printer :type function)
+ (kids '() :type list)
+ (collapsed-p t :type boolean)
+ (prefix "" :type string)
+ (start-mark nil)
+ (end-mark nil)
+ (plist '() :type list))
+
+(defun slime-tree-leaf-p (tree)
+ (not (slime-tree.kids tree)))
+
+(defun slime-tree-default-printer (tree)
+ (princ (slime-tree.item tree) (current-buffer)))
+
+(defun slime-tree-decoration (tree)
+ (cond ((slime-tree-leaf-p tree) "-- ")
+ ((slime-tree.collapsed-p tree) "[+] ")
+ (t "-+ ")))
+
+(defun slime-tree-insert-list (list prefix)
+ "Insert a list of trees."
+ (loop for (elt . rest) on list
+ do (cond (rest
+ (insert prefix " |")
+ (slime-tree-insert elt (concat prefix " |"))
+ (insert "\n"))
+ (t
+ (insert prefix " `")
+ (slime-tree-insert elt (concat prefix " "))))))
+
+(defun slime-tree-insert-decoration (tree)
+ (insert (slime-tree-decoration tree)))
+
+(defun slime-tree-indent-item (start end prefix)
+ "Insert PREFIX at the beginning of each but the first line.
+This is used for labels spanning multiple lines."
+ (save-excursion
+ (goto-char end)
+ (beginning-of-line)
+ (while (< start (point))
+ (insert-before-markers prefix)
+ (forward-line -1))))
+
+(defun slime-tree-insert (tree prefix)
+ "Insert TREE prefixed with PREFIX at point."
+ (with-struct (slime-tree. print-fn kids collapsed-p start-mark end-mark) tree
+ (let ((line-start (line-beginning-position)))
+ (setf start-mark (point-marker))
+ (slime-tree-insert-decoration tree)
+ (funcall print-fn tree)
+ (slime-tree-indent-item start-mark (point) (concat prefix " "))
+ (add-text-properties line-start (point) (list 'slime-tree tree))
+ (set-marker-insertion-type start-mark t)
+ (when (and kids (not collapsed-p))
+ (terpri (current-buffer))
+ (slime-tree-insert-list kids prefix))
+ (setf (slime-tree.prefix tree) prefix)
+ (setf end-mark (point-marker)))))
+
+(defun slime-tree-at-point ()
+ (cond ((get-text-property (point) 'slime-tree))
+ (t (error "No tree at point"))))
+
+(defun slime-tree-delete (tree)
+ "Delete the region for TREE."
+ (delete-region (slime-tree.start-mark tree)
+ (slime-tree.end-mark tree)))
+
+(defun slime-tree-toggle (tree)
+ "Toggle the visibility of TREE's children."
+ (with-struct (slime-tree. collapsed-p start-mark end-mark prefix) tree
+ (setf collapsed-p (not collapsed-p))
+ (slime-tree-delete tree)
+ (insert-before-markers " ") ; move parent's end-mark
+ (backward-char 1)
+ (slime-tree-insert tree prefix)
+ (delete-char 1)
+ (goto-char start-mark)))
+
+
+;;;;; Adding a single compiler note
+
+(defun slime-overlay-note (note)
+ "Add a compiler note to the buffer as an overlay.
+If an appropriate overlay for a compiler note in the same location
+already exists then the new information is merged into it. Otherwise a
+new overlay is created."
+ (multiple-value-bind (start end) (slime-choose-overlay-region note)
+ (when start
+ (goto-char start)
+ (let ((severity (plist-get note :severity))
+ (message (plist-get note :message))
+ (overlay (slime-note-at-point)))
+ (if overlay
+ (slime-merge-note-into-overlay overlay severity message)
+ (slime-create-note-overlay note start end severity message))))))
+
+(defun slime-create-note-overlay (note start end severity message)
+ "Create an overlay representing a compiler note.
+The overlay has several properties:
+ FACE - to underline the relevant text.
+ SEVERITY - for future reference, :NOTE, :STYLE-WARNING, :WARNING, or :ERROR.
+ MOUSE-FACE - highlight the note when the mouse passes over.
+ HELP-ECHO - a string describing the note, both for future reference
+ and for display as a tooltip (due to the special
+ property name)."
+ (let ((overlay (make-overlay start end)))
+ (flet ((putp (name value) (overlay-put overlay name value)))
+ (putp 'slime note)
+ (putp 'face (slime-severity-face severity))
+ (putp 'severity severity)
+ (unless (slime-emacs-20-p)
+ (putp 'mouse-face 'highlight))
+ (putp 'help-echo message)
+ overlay)))
+
+;; XXX Obsolete due to `slime-merge-notes-for-display' doing the
+;; work already -- unless we decide to put several sets of notes on a
+;; buffer without clearing in between, which only this handles.
+(defun slime-merge-note-into-overlay (overlay severity message)
+ "Merge another compiler note into an existing overlay.
+The help text describes both notes, and the highest of the severities
+is kept."
+ (flet ((putp (name value) (overlay-put overlay name value))
+ (getp (name) (overlay-get overlay name)))
+ (putp 'severity (slime-most-severe severity (getp 'severity)))
+ (putp 'face (slime-severity-face (getp 'severity)))
+ (putp 'help-echo (concat (getp 'help-echo) "\n" message))))
+
+(defun slime-choose-overlay-region (note)
+ "Choose the start and end points for an overlay over NOTE.
+If the location's sexp is a list spanning multiple lines, then the
+region around the first element is used.
+Return nil if there's no useful source location."
+ (let ((location (slime-note.location note)))
+ (when location
+ (destructure-case location
+ ((:error _) _ nil) ; do nothing
+ ((:location file pos _hints)
+ (cond ((eq (car file) ':source-form) nil)
+ (t
+ (destructure-case pos
+ ((:position pos &optional alignp)
+ (if (eq (slime-note.severity note) :read-error)
+ (values pos (1+ pos))
+ (slime-choose-overlay-for-sexp location)))
+ (t
+ (slime-choose-overlay-for-sexp location))))))))))
+
+(defun slime-choose-overlay-for-sexp (location)
+ (slime-goto-source-location location)
+ (skip-chars-forward "'#`")
+ (let ((start (point)))
+ (ignore-errors (slime-forward-sexp))
+ (if (slime-same-line-p start (point))
+ (values start (point))
+ (values (1+ start)
+ (progn (goto-char (1+ start))
+ (ignore-errors (forward-sexp 1))
+ (point))))))
+
+(defun slime-same-line-p (pos1 pos2)
+ "Return t if buffer positions POS1 and POS2 are on the same line."
+ (save-excursion (goto-char (min pos1 pos2))
+ (<= (max pos1 pos2) (line-end-position))))
+
+(defun slime-severity-face (severity)
+ "Return the name of the font-lock face representing SEVERITY."
+ (ecase severity
+ (:error 'slime-error-face)
+ (:read-error 'slime-error-face)
+ (:warning 'slime-warning-face)
+ (:style-warning 'slime-style-warning-face)
+ (:note 'slime-note-face)))
+
+(defun slime-most-severe (sev1 sev2)
+ "Return the most servere of two conditions.
+Severity is ordered as :NOTE < :STYLE-WARNING < :WARNING < :ERROR."
+ ; Well, not exactly Smullyan..
+ (let ((order '(:note :style-warning :warning :error :read-error)))
+ (if (>= (position sev1 order)
+ (position sev2 order))
+ sev1
+ sev2)))
+
+;; XXX: unused function
+(defun slime-visit-source-path (source-path)
+ "Visit a full source path including the top-level form."
+ (goto-char (point-min))
+ (slime-forward-source-path source-path))
+
+(defun slime-forward-positioned-source-path (source-path)
+ "Move forward through a sourcepath from a fixed position.
+The point is assumed to already be at the outermost sexp, making the
+first element of the source-path redundant."
+ (ignore-errors
+ (slime-forward-sexp)
+ (beginning-of-defun))
+ (when-let (source-path (cdr source-path))
+ (down-list 1)
+ (slime-forward-source-path source-path)))
+
+(defun slime-forward-source-path (source-path)
+ (let ((origin (point)))
+ (condition-case nil
+ (progn
+ (loop for (count . more) on source-path
+ do (progn
+ (slime-forward-sexp count)
+ (when more (down-list 1))))
+ ;; Align at beginning
+ (slime-forward-sexp)
+ (beginning-of-sexp))
+ (error (goto-char origin)))))
+
+(defun slime-filesystem-toplevel-directory ()
+ ;; Windows doesn't have a true toplevel root directory, and all
+ ;; filenames look like "c:/foo/bar/quux.baz" from an Emacs
+ ;; perspective anyway.
+ (if (memq system-type '(ms-dos windows-nt))
+ ""
+ (file-name-as-directory "/")))
+
+(defun slime-file-name-merge-source-root (target-filename buffer-filename)
+ "Returns a filename where the source root directory of TARGET-FILENAME
+is replaced with the source root directory of BUFFER-FILENAME.
+
+If no common source root could be determined, return NIL.
+
+E.g. (slime-file-name-merge-source-root
+ \"/usr/local/src/joe/upstream/sbcl/code/late-extensions.lisp\"
+ \"/usr/local/src/joe/hacked/sbcl/compiler/deftype.lisp\")
+
+ ==> \"/usr/local/src/joe/hacked/sbcl/code/late-extensions.lisp\"
+"
+ (let ((target-dirs (slime-split-string (file-name-directory target-filename) "/" t))
+ (buffer-dirs (slime-split-string (file-name-directory buffer-filename) "/" t)))
+ ;; Starting from the end, we look if one of the TARGET-DIRS exists
+ ;; in BUFFER-FILENAME---if so, it and everything left from that dirname
+ ;; is considered to be the source root directory of BUFFER-FILENAME.
+ (loop with target-suffix-dirs = nil
+ with buffer-dirs* = (reverse buffer-dirs)
+ with target-dirs* = (reverse target-dirs)
+ for target-dir in target-dirs*
+ do (flet ((concat-dirs (dirs)
+ (apply #'concat (mapcar #'file-name-as-directory dirs))))
+ (let ((pos (position target-dir buffer-dirs* :test #'equal)))
+ (if (not pos) ; TARGET-DIR not in BUFFER-FILENAME?
+ (push target-dir target-suffix-dirs)
+ (let* ((target-suffix (concat-dirs target-suffix-dirs)) ; PUSH reversed for us!
+ (buffer-root (concat-dirs (reverse (nthcdr pos buffer-dirs*)))))
+ (return (concat (slime-filesystem-toplevel-directory)
+ buffer-root
+ target-suffix
+ (file-name-nondirectory target-filename))))))))))
+
+(defun slime-highlight-differences-in-dirname (base-dirname contrast-dirname)
+ "Returns a copy of BASE-DIRNAME where all differences between
+BASE-DIRNAME and CONTRAST-DIRNAME are propertized with a
+highlighting face."
+ (setq base-dirname (file-name-as-directory base-dirname))
+ (setq contrast-dirname (file-name-as-directory contrast-dirname))
+ (flet ((insert-dir (dirname)
+ (insert (file-name-as-directory dirname)))
+ (insert-dir/propzd (dirname)
+ (slime-insert-propertized '(face highlight) dirname)
+ (insert "/"))) ; Not exactly portable (to VMS...)
+ (let ((base-dirs (slime-split-string base-dirname "/" t))
+ (contrast-dirs (slime-split-string contrast-dirname "/" t)))
+ (with-temp-buffer
+ (loop initially (insert (slime-filesystem-toplevel-directory))
+ for base-dir in base-dirs do
+ (let ((pos (position base-dir contrast-dirs :test #'equal)))
+ (if (not pos)
+ (insert-dir/propzd base-dir)
+ (progn (insert-dir base-dir)
+ (setq contrast-dirs (nthcdr (1+ pos) contrast-dirs))))))
+ (buffer-substring (point-min) (point-max))))))
+
+(defvar slime-warn-when-possibly-tricked-by-M-. t
+ "When working on multiple source trees simultaneously, the way
+`slime-edit-definition' (M-.) works can sometimes be confusing:
+
+`M-.' visits locations that are present in the current Lisp image,
+which works perfectly well as long as the image reflects the source
+tree that one is currently looking at.
+
+In the other case, however, one can easily end up visiting a file
+in a different source root directory (the one corresponding to
+the Lisp image), and is thus easily tricked to modify the wrong
+source files---which can lead to quite some stressfull cursing.
+
+If this variable is T, a warning message is issued to raise the
+user's attention whenever `M-.' is about opening a file in a
+different source root that also exists in the source root
+directory of the user's current buffer.
+
+There's no guarantee that all possible cases are covered, but
+if you encounter such a warning, it's a strong indication that
+you should check twice before modifying.")
+
+(defun slime-maybe-warn-for-different-source-root (target-filename buffer-filename)
+ (when slime-warn-when-possibly-tricked-by-M-.
+ (let ((guessed-target (slime-file-name-merge-source-root target-filename
+ buffer-filename)))
+ (when (and guessed-target
+ (not (equal guessed-target target-filename))
+ (file-exists-p guessed-target))
+ (slime-message "Attention: This is `%s'."
+ (concat (slime-highlight-differences-in-dirname
+ (file-name-directory target-filename)
+ (file-name-directory guessed-target))
+ (file-name-nondirectory target-filename)))))))
+
+
+(defun slime-goto-location-buffer (buffer)
+ (flet ((file-truename-safe (filename) (and filename (file-truename filename))))
+ (destructure-case buffer
+ ((:file filename)
+ (let ((target-filename (file-truename-safe (slime-from-lisp-filename filename)))
+ (buffer-filename (file-truename-safe (buffer-file-name))))
+ (when buffer-filename
+ (slime-maybe-warn-for-different-source-root target-filename buffer-filename))
+ (unless (and buffer-filename (string= buffer-filename target-filename))
+ (set-buffer (find-file-noselect target-filename t))))
+ (goto-char (point-min)))
+ ((:buffer buffer-name)
+ (let ((old-buffer-filename (file-truename-safe (buffer-file-name)))
+ (target-buffer-filename (file-truename-safe
+ (buffer-file-name (get-buffer buffer-name)))))
+ (when (and target-buffer-filename old-buffer-filename)
+ (slime-maybe-warn-for-different-source-root target-buffer-filename
+ old-buffer-filename)))
+ (set-buffer buffer-name)
+ (goto-char (point-min)))
+ ((:source-form string)
+ (set-buffer (get-buffer-create "*SLIME Source Form*"))
+ (erase-buffer)
+ (lisp-mode)
+ (insert string)
+ (goto-char (point-min)))
+ ((:zip file entry)
+ (require 'arc-mode)
+ (set-buffer (find-file-noselect file t))
+ (goto-char (point-min))
+ (re-search-forward (concat " " entry "$"))
+ (let ((buffer (save-window-excursion
+ (archive-extract)
+ (current-buffer))))
+ (set-buffer buffer)
+ (goto-char (point-min)))))))
+
+(defun slime-goto-location-position (position)
+ (save-restriction-if-possible ; try to keep restriction if possible.
+ (widen)
+ (destructure-case position
+ ((:position pos &optional align-p)
+ (goto-char pos)
+ (when align-p
+ (slime-forward-sexp)
+ (beginning-of-sexp)))
+ ((:line start &optional column)
+ (goto-line start)
+ (cond (column (move-to-column column))
+ (t (skip-chars-forward " \t"))))
+ ((:function-name name)
+ (let ((case-fold-search t)
+ (name (regexp-quote name)))
+ (or
+ (re-search-forward
+ (format "\\s *(def\\(\\s_\\|\\sw\\)*\\s +%s\\S_" name) nil t)
+ (re-search-forward
+ (format "\\s *(def\\(\\s_\\|\\sw\\)*\\s +(*%s\\S_" name) nil t)
+ (re-search-forward
+ (format "[( \t]%s\\>\\(\\s \\|$\\)" name) nil t)))
+ (goto-char (match-beginning 0)))
+ ((:method name specializers &rest qualifiers)
+ (slime-search-method-location name specializers qualifiers))
+ ((:source-path source-path start-position)
+ (cond (start-position
+ (goto-char start-position)
+ (slime-forward-positioned-source-path source-path))
+ (t
+ (slime-forward-source-path source-path))))
+ ;; Goes to "start" then looks for the anchor text, then moves
+ ;; delta from that position.
+ ((:text-anchored start text delta)
+ (goto-char start)
+ (slime-isearch text)
+ (forward-char delta)))))
+
+(defun slime-search-method-location (name specializers qualifiers)
+ ;; Look for a sequence of words (def<something> method name
+ ;; qualifers specializers don't look for "T" since it isn't requires
+ ;; (arg without t) as class is taken as such.
+ (let* ((case-fold-search t)
+ (name (regexp-quote name))
+ (qualifiers (mapconcat (lambda (el) (concat ".+?\\<" el "\\>"))
+ qualifiers ""))
+ (specializers (mapconcat (lambda (el)
+ (if (eql (aref el 0) ?\()
+ (let ((spec (read el)))
+ (if (eq (car spec) 'EQL)
+ (concat ".*?\\n\\{0,1\\}.*?(EQL.*?'\\{0,1\\}" (format "%s" (second spec)) ")")
+ (error "don't understand specializer: %s,%s" el (car spec))))
+ (concat ".+?\n\\{0,1\\}.+?\\<" el "\\>")))
+ (remove "T" specializers) ""))
+ (regexp (format "\\s *(def\\(\\s_\\|\\sw\\)*\\s +%s\\s +%s%s" name
+ qualifiers specializers)))
+ (or (and (re-search-forward regexp nil t)
+ (goto-char (match-beginning 0)))
+ ;; (slime-goto-location-position `(:function-name ,name))
+ )))
+
+(defun slime-search-call-site (fname)
+ "Move to the place where FNAME called.
+Don't move if there are multiple or no calls in the current defun."
+ (save-restriction
+ (narrow-to-defun)
+ (let ((start (point))
+ (regexp (concat "(" fname "[\n \t]")))
+ (cond ((and (re-search-forward regexp nil t)
+ (not (re-search-forward regexp nil t)))
+ (goto-char (match-beginning 0)))
+ (t (goto-char start))))))
+
+(defun slime-goto-source-location (location &optional noerror)
+ "Move to the source location LOCATION. Several kinds of locations
+are supported:
+
+<location> ::= (:location <buffer> <position> <hints>)
+ | (:error <message>)
+
+<buffer> ::= (:file <filename>)
+ | (:buffer <buffername>)
+ | (:source-form <string>)
+ | (:zip <file> <entry>)
+
+<position> ::= (:position <fixnum> [<align>]) ; 1 based
+ | (:line <line> [<column>])
+ | (:function-name <string>)
+ | (:source-path <list> <start-position>)
+ | (:text-anchored <fixnum> <string> <fixnum>)
+ | (:method <name string> <specializer strings> . <qualifiers strings>)"
+ (destructure-case location
+ ((:location buffer position hints)
+ (slime-goto-location-buffer buffer)
+ (slime-goto-location-position position)
+ (when-let (snippet (getf hints :snippet))
+ (slime-isearch snippet))
+ (when-let (fname (getf hints :call-site))
+ (slime-search-call-site fname)))
+ ((:error message)
+ (if noerror
+ (slime-message "%s" message)
+ (error "%s" message)))))
+
+(defmacro slime-point-moves-p (&rest body)
+ "Execute BODY and return true if the current buffer's point moved."
+ (let ((pointvar (gensym "point-")))
+ `(let ((,pointvar (point)))
+ (save-current-buffer , at body)
+ (/= ,pointvar (point)))))
+
+(put 'slime-point-moves-p 'lisp-indent-function 0)
+
+(defun slime-forward-sexp (&optional count)
+ "Like `forward-sexp', but understands reader-conditionals (#- and #+)."
+ (dotimes (i (or count 1))
+ (while (slime-point-moves-p (slime-forward-blanks)
+ (slime-forward-reader-comment)
+ (slime-forward-reader-conditional)))
+ (forward-sexp)))
+
+(defun slime-forward-blanks ()
+ "Move forward over all whitespace and newlines at point."
+ (ignore-errors
+ (while (slime-point-moves-p
+ (skip-syntax-forward " ")
+ ;; newlines aren't in lisp-mode's whitespace syntax class
+ (when (eolp) (forward-char))))))
+
+;; Emacs 21's forward-sexp understands #| |# comments in lisp-mode
+;; buffers, but (at least) Emacs 20's doesn't, so here it is.
+(defun slime-forward-reader-comment ()
+ "Move forward over #|...|# reader comments. The comments may be nested."
+ (when (looking-at "#|")
+ (goto-char (match-end 0))
+ (while (not (looking-at "|#"))
+ (re-search-forward (regexp-opt '("|#" "#|")))
+ (goto-char (match-beginning 0))
+ (when (looking-at "#|") ; nested comment
+ (slime-forward-reader-comment)))
+ (goto-char (match-end 0))))
+
+(defun slime-forward-reader-conditional ()
+ "Move past any reader conditional (#+ or #-) at point."
+ (when (or (looking-at "#\\+")
+ (looking-at "#-"))
+ (goto-char (match-end 0))
+ (let* ((plus-conditional-p (eq (char-before) ?+))
+ (result (slime-eval-feature-conditional (read (current-buffer)))))
+ (unless (if plus-conditional-p result (not result))
+ ;; skip this sexp
+ (slime-forward-sexp)))))
+
+(defun slime-keywordify (symbol)
+ "Make a keyword out of the symbol SYMBOL."
+ (let ((name (downcase (symbol-name symbol))))
+ (intern (if (eq ?: (aref name 0))
+ name
+ (concat ":" name)))))
+
+(defun slime-eval-feature-conditional (e)
+ "Interpret a reader conditional expression."
+ (if (symbolp e)
+ (memq (slime-keywordify e) (slime-lisp-features))
+ (funcall (ecase (slime-keywordify (car e))
+ (:and #'every)
+ (:or #'some)
+ (:not (lambda (f l) (not (apply f l)))))
+ #'slime-eval-feature-conditional
+ (cdr e))))
+
+
+;;;;; Incremental search
+;;
+;; Search for the longest match of a string in either direction.
+;;
+;; This is for locating text that is expected to be near the point and
+;; may have been modified (but hopefully not near the beginning!)
+
+(defun slime-isearch (string)
+ "Find the longest occurence of STRING either backwards of forwards.
+If multiple matches exist the choose the one nearest to point."
+ (goto-char
+ (let* ((start (point))
+ (len1 (slime-isearch-with-function 'search-forward string))
+ (pos1 (point)))
+ (goto-char start)
+ (let* ((len2 (slime-isearch-with-function 'search-backward string))
+ (pos2 (point)))
+ (cond ((and len1 len2)
+ ;; Have a match in both directions
+ (cond ((= len1 len2)
+ ;; Both are full matches -- choose the nearest.
+ (if (< (abs (- start pos1))
+ (abs (- start pos2)))
+ pos1 pos2))
+ ((> len1 len2) pos1)
+ ((> len2 len1) pos2)))
+ (len1 pos1)
+ (len2 pos2)
+ (t start))))))
+
+(defun slime-isearch-with-function (search-fn string)
+ "Search for the longest substring of STRING using SEARCH-FN.
+SEARCH-FN is either the symbol `search-forward' or `search-backward'."
+ (unless (string= string "")
+ (loop for i from 1 to (length string)
+ while (funcall search-fn (substring string 0 i) nil t)
+ for match-data = (match-data)
+ do (case search-fn
+ (search-forward (goto-char (match-beginning 0)))
+ (search-backward (goto-char (1+ (match-end 0)))))
+ finally (return (if (null match-data)
+ nil
+ ;; Finish based on the last successful match
+ (store-match-data match-data)
+ (goto-char (match-beginning 0))
+ (- (match-end 0) (match-beginning 0)))))))
+
+
+;;;;; Visiting and navigating the overlays of compiler notes
+
+(defvar slime-compilation-just-finished nil
+ "A buffer local variable which is T when we've just compiled a
+buffer and haven't yet started navigating its notes.")
+(make-variable-buffer-local 'slime-compilation-just-finished)
+
+(defun slime-next-note ()
+ "Go to and describe the next compiler note in the buffer."
+ (interactive)
+ (let ((here (point)))
+ (when (and slime-goto-first-note-after-compilation
+ slime-compilation-just-finished)
+ (goto-char (point-min))
+ (setf slime-compilation-just-finished nil))
+ (slime-find-next-note)
+ (if (slime-note-at-point)
+ (slime-show-note (slime-note-at-point))
+ (progn
+ (goto-char here)
+ (message "No next note.")))))
+
+(defun slime-previous-note ()
+ "Go to and describe the previous compiler note in the buffer."
+ (interactive)
+ (let ((here (point)))
+ (when (and slime-goto-first-note-after-compilation
+ slime-compilation-just-finished)
+ (goto-char (point-max))
+ (setf slime-compilation-just-finished nil))
+ (slime-find-previous-note)
+ (if (slime-note-at-point)
+ (slime-show-note (slime-note-at-point))
+ (progn
+ (goto-char here)
+ (message "No previous note.")))))
+
+(defun slime-remove-notes ()
+ "Remove compiler-note annotations from the current buffer."
+ (interactive)
+ (slime-remove-old-overlays))
+
+(defun slime-show-note (overlay)
+ "Present the details of a compiler note to the user."
+ (slime-temporarily-highlight-note overlay)
+ (let ((message (get-char-property (point) 'help-echo)))
+ (slime-message "%s" (if (zerop (length message)) "\"\"" message))))
+
+(defun slime-temporarily-highlight-note (overlay)
+ "Temporarily highlight a compiler note's overlay.
+The highlighting is designed to both make the relevant source more
+visible, and to highlight any further notes that are nested inside the
+current one.
+
+The highlighting is automatically undone before the next Emacs command."
+ (lexical-let ((old-face (overlay-get overlay 'face))
+ (overlay overlay))
+ (push (lambda () (overlay-put overlay 'face old-face))
+ slime-pre-command-actions)
+ (overlay-put overlay 'face 'slime-highlight-face)))
+
+
+;;;;; Overlay lookup operations
+
+(defun slime-note-at-point ()
+ "Return the overlay for a note starting at point, otherwise NIL."
+ (find (point) (slime-note-overlays-at-point)
+ :key 'overlay-start))
+
+(defun slime-note-overlay-p (overlay)
+ "Return true if OVERLAY represents a compiler note."
+ (overlay-get overlay 'slime))
+
+(defun slime-note-overlays-at-point ()
+ "Return a list of all note overlays that are under the point."
+ (remove-if-not 'slime-note-overlay-p (overlays-at (point))))
+
+(defun slime-find-next-note ()
+ "Go to the next position with the `slime-note' text property.
+Retuns true if such a position is found."
+ (slime-find-note 'next-single-char-property-change))
+
+(defun slime-find-previous-note ()
+ "Go to the next position with the `slime' text property.
+Returns true if such a position is found."
+ (slime-find-note 'previous-single-char-property-change))
+
+(defun slime-find-note (next-candidate-fn)
+ "Seek out the beginning of a note.
+NEXT-CANDIDATE-FN is called to find each new position for consideration."
+ (let ((origin (point)))
+ (loop do (goto-char (funcall next-candidate-fn (point) 'slime))
+ until (or (slime-note-at-point)
+ (eobp)
+ (bobp)))
+ (unless (slime-note-at-point)
+ (goto-char origin))))
+
+
+;;;; Arglist Display
+
+(defun slime-space (n)
+ "Insert a space and print some relevant information (function arglist).
+Designed to be bound to the SPC key. Prefix argument can be used to insert
+more than one space."
+ (interactive "p")
+ (self-insert-command n)
+ (when (and slime-space-information-p
+ (slime-background-activities-enabled-p))
+ (slime-echo-arglist)))
+
+(defvar slime-echo-arglist-function 'slime-show-arglist)
+
+(defun slime-echo-arglist ()
+ "Display the arglist of the current form in the echo area."
+ (funcall slime-echo-arglist-function))
+
+(defun slime-show-arglist ()
+ (let ((op (slime-operator-before-point)))
+ (when op
+ (slime-eval-async `(swank:operator-arglist ,op ,(slime-current-package))
+ (lambda (arglist)
+ (when arglist
+ (slime-message "%s" arglist)))))))
+
+(defun slime-operator-before-point ()
+ (ignore-errors
+ (save-excursion
+ (backward-up-list 1)
+ (down-list 1)
+ (slime-symbol-name-at-point))))
+
+
+;;;; Completion
+
+;; XXX those long names are ugly to read; long names an indicator for
+;; bad factoring?
+
+(defvar slime-completions-buffer-name "*Completions*")
+
+(make-variable-buffer-local
+ (defvar slime-complete-saved-window-configuration nil
+ "Window configuration before we show the *Completions* buffer.
+This is buffer local in the buffer where the completion is
+performed."))
+
+(make-variable-buffer-local
+ (defvar slime-completions-window nil
+ "The window displaying *Completions* after saving window configuration.
+If this window is no longer active or displaying the completions
+buffer then we can ignore `slime-complete-saved-window-configuration'."))
+
+(defun slime-complete-maybe-save-window-configuration ()
+ "Maybe save the current window configuration.
+Return true if the configuration was saved."
+ (unless (or slime-complete-saved-window-configuration
+ (get-buffer-window slime-completions-buffer-name))
+ (setq slime-complete-saved-window-configuration
+ (current-window-configuration))
+ t))
+
+(defun slime-complete-delay-restoration ()
+ (make-local-hook 'pre-command-hook)
+ (add-hook 'pre-command-hook
+ 'slime-complete-maybe-restore-window-configuration))
+
+(defun slime-complete-forget-window-configuration ()
+ (setq slime-complete-saved-window-configuration nil)
+ (setq slime-completions-window nil))
+
+(defun slime-complete-restore-window-configuration ()
+ "Restore the window config if available."
+ (remove-hook 'pre-command-hook
+ 'slime-complete-maybe-restore-window-configuration)
+ (when (and slime-complete-saved-window-configuration
+ (slime-completion-window-active-p))
+ ;; XEmacs does not allow us to restore a window configuration from
+ ;; pre-command-hook, so we do it asynchronously.
+ (slime-run-when-idle
+ (lambda ()
+ (save-excursion
+ (set-window-configuration
+ slime-complete-saved-window-configuration))
+ (setq slime-complete-saved-window-configuration nil)
+ (when (buffer-live-p slime-completions-buffer-name)
+ (kill-buffer slime-completions-buffer-name))))))
+
+(defun slime-complete-maybe-restore-window-configuration ()
+ "Restore the window configuration, if the following command
+terminates a current completion."
+ (remove-hook 'pre-command-hook
+ 'slime-complete-maybe-restore-window-configuration)
+ (condition-case err
+ (cond ((find last-command-char "()\"'`,# \r\n:")
+ (slime-complete-restore-window-configuration))
+ ((not (slime-completion-window-active-p))
+ (slime-complete-forget-window-configuration))
+ (t
+ (slime-complete-delay-restoration)))
+ (error
+ ;; Because this is called on the pre-command-hook, we mustn't let
+ ;; errors propagate.
+ (message "Error in slime-complete-restore-window-configuration: %S" err))))
+
+(defun slime-completion-window-active-p ()
+ "Is the completion window currently active?"
+ (and (window-live-p slime-completions-window)
+ (equal (buffer-name (window-buffer slime-completions-window))
+ slime-completions-buffer-name)))
+
+(defun slime-display-completion-list (completions base)
+ (let ((savedp (slime-complete-maybe-save-window-configuration)))
+ (with-output-to-temp-buffer slime-completions-buffer-name
+ (display-completion-list completions)
+ (let ((offset (- (point) 1 (length base))))
+ (with-current-buffer standard-output
+ (setq completion-base-size offset)
+ (set-syntax-table lisp-mode-syntax-table))))
+ (when savedp
+ (setq slime-completions-window
+ (get-buffer-window slime-completions-buffer-name)))))
+
+(defun slime-display-or-scroll-completions (completions base)
+ (cond ((and (eq last-command this-command)
+ (slime-completion-window-active-p))
+ (slime-scroll-completions))
+ (t
+ (slime-display-completion-list completions base)))
+ (slime-complete-delay-restoration))
+
+(defun slime-scroll-completions ()
+ (let ((window slime-completions-window))
+ (with-current-buffer (window-buffer window)
+ (if (pos-visible-in-window-p (point-max) window)
+ (set-window-start window (point-min))
+ (save-selected-window
+ (select-window window)
+ (scroll-up))))))
+
+(defun slime-complete-symbol ()
+ "Complete the symbol at point.
+
+Completion is performed by `slime-complete-symbol-function'."
+ (interactive)
+ (funcall slime-complete-symbol-function))
+
+(defun slime-simple-complete-symbol ()
+ "Complete the symbol at point.
+Perform completion more similar to Emacs' complete-symbol."
+ (or (slime-maybe-complete-as-filename)
+ (let* ((end (point))
+ (beg (slime-symbol-start-pos))
+ (prefix (buffer-substring-no-properties beg end))
+ (result (slime-simple-completions prefix)))
+ (destructuring-bind (completions partial) result
+ (if (null completions)
+ (progn (slime-minibuffer-respecting-message
+ "Can't find completion for \"%s\"" prefix)
+ (ding)
+ (slime-complete-restore-window-configuration))
+ (insert-and-inherit (substring partial (length prefix)))
+ (cond ((slime-length= completions 1)
+ (slime-minibuffer-respecting-message "Sole completion")
+ (slime-complete-restore-window-configuration))
+ ;; Incomplete
+ (t
+ (slime-minibuffer-respecting-message
+ "Complete but not unique")
+ (slime-display-or-scroll-completions completions
+ partial))))))))
+
+(defun slime-maybe-complete-as-filename ()
+ "If point is at a string starting with \", complete it as filename.
+Return nil iff if point is not at filename."
+ (if (save-excursion (re-search-backward "\"[^ \t\n]+\\=" nil t))
+ (let ((comint-completion-addsuffix '("/" . "\"")))
+ (if slime-when-complete-filename-expand
+ (comint-replace-by-expanded-filename)
+ (comint-dynamic-complete-as-filename))
+ t)
+ nil))
+
+(defun slime-minibuffer-respecting-message (format &rest format-args)
+ "Display TEXT as a message, without hiding any minibuffer contents."
+ (let ((text (format " [%s]" (apply #'format format format-args))))
+ (if (minibuffer-window-active-p (minibuffer-window))
+ (if (fboundp 'temp-minibuffer-message) ;; XEmacs
+ (temp-minibuffer-message text)
+ (minibuffer-message text))
+ (message "%s" text))))
+
+(defvar slime-read-expression-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map minibuffer-local-map)
+ (define-key map "\t" 'slime-complete-symbol)
+ (define-key map "\M-\t" 'slime-complete-symbol)
+ map)
+ "Minibuffer keymap used for reading CL expressions.")
+
+(defvar slime-read-expression-history '()
+ "History list of expressions read from the minibuffer.")
+
+(defun slime-read-from-minibuffer (prompt &optional initial-value)
+ "Read a string from the minibuffer, prompting with PROMPT.
+If INITIAL-VALUE is non-nil, it is inserted into the minibuffer before
+reading input. The result is a string (\"\" if no input was given)."
+ (let ((minibuffer-setup-hook
+ (cons (lexical-let ((package (slime-current-package))
+ (connection (slime-connection)))
+ (lambda ()
+ (setq slime-buffer-package package)
+ (setq slime-buffer-connection connection)
+ (set-syntax-table lisp-mode-syntax-table)))
+ minibuffer-setup-hook)))
+ (read-from-minibuffer prompt initial-value slime-read-expression-map
+ nil 'slime-read-expression-history)))
+
+(defun slime-bogus-completion-alist (list)
+ "Make an alist out of list.
+The same elements go in the CAR, and nil in the CDR. To support the
+apparently very stupid `try-completions' interface, that wants an
+alist but ignores CDRs."
+ (mapcar (lambda (x) (cons x nil)) list))
+
+(defun slime-simple-completions (prefix)
+ (slime-eval `(swank:simple-completions ,prefix ',(slime-current-package))))
+
+
+;;;; Edit definition
+
+(defvar slime-find-definition-history-ring (make-ring 20)
+ "History ring recording the definition-finding \"stack\".")
+
+(defun slime-push-definition-stack (&optional marker narrowing-configuration)
+ "Add MARKER and NARROWING-CONFIGURATION to the edit-definition history stack.
+If MARKER is nil, use the current point. If NARROWING-CONFIGURATION is nil,
+look if the current buffer is narrowed, and if so use the relevant values."
+ (ring-insert-at-beginning slime-find-definition-history-ring
+ (list (or marker (point-marker))
+ (or narrowing-configuration
+ (slime-current-narrowing-configuration)))))
+
+(defun slime-pop-find-definition-stack ()
+ "Pop the edit-definition stack and goto the location."
+ (interactive)
+ (unless (ring-empty-p slime-find-definition-history-ring)
+ (destructuring-bind (marker narrowing-cfg)
+ (ring-remove slime-find-definition-history-ring)
+ (let ((buffer (marker-buffer marker))
+ (narrowedp (slime-narrowing-configuration.narrowedp narrowing-cfg))
+ (narrow-beg (slime-narrowing-configuration.beg narrowing-cfg))
+ (narrow-end (slime-narrowing-configuration.end narrowing-cfg)))
+ (if (buffer-live-p buffer)
+ (progn (switch-to-buffer buffer)
+ (goto-char (marker-position marker))
+ (when narrowedp
+ (narrow-to-region narrow-beg narrow-end)))
+ ;; If this buffer was deleted, recurse to try the next one
+ (slime-pop-find-definition-stack))))))
+
+(defstruct (slime-definition (:conc-name slime-definition.)
+ (:type list))
+ dspec location)
+
+(defun slime-edit-definition (name &optional where)
+ "Lookup the definition of the name at point.
+If there's no name at point, or a prefix argument is given, then the
+function name is prompted."
+ (interactive (list (slime-read-symbol-name "Name: ")))
+ (let ((definitions (slime-eval `(swank:find-definitions-for-emacs ,name))))
+ (cond
+ ((null definitions)
+ (if slime-edit-definition-fallback-function
+ (funcall slime-edit-definition-fallback-function name)
+ (error "No known definition for: %s" name)))
+ ((and (slime-length= definitions 1)
+ (eql (car (slime-definition.location (car definitions))) :error))
+ (if slime-edit-definition-fallback-function
+ (funcall slime-edit-definition-fallback-function name)
+ (error "%s" (cadr (slime-definition.location (car definitions))))))
+ (t
+ (slime-goto-definition name definitions where)))))
+
+(defun slime-find-tag-if-tags-table-visited (name)
+ "Find tag (in current tags table) whose name contains NAME.
+If no tags table is visited, don't offer to visit one;
+just signal that no definition is known."
+ (if tags-table-list
+ (find-tag name)
+ (error "No known definition for: %s; use M-x visit-tags-table RET" name)))
+
+(defun slime-goto-definition (name definitions &optional where)
+ (slime-push-definition-stack)
+ (let ((all-locations-equal
+ (or (null definitions)
+ (let ((first-location (slime-definition.location (first definitions))))
+ (every (lambda (definition)
+ (equal (slime-definition.location definition)
+ first-location))
+ (rest definitions))))))
+ (if (and (slime-length> definitions 1)
+ (not all-locations-equal))
+ (slime-show-definitions name definitions)
+ (let ((def (car definitions)))
+ (destructure-case (slime-definition.location def)
+ ;; Take care of errors before switching any windows/buffers.
+ ((:error message)
+ (error "%s" message))
+ (t
+ (cond ((equal where 'window)
+ (slime-goto-definition-other-window (car definitions)))
+ ((equal where 'frame)
+ (let ((pop-up-frames t))
+ (slime-goto-definition-other-window (car definitions))))
+ (t
+ (slime-goto-source-location (slime-definition.location
+ (car definitions)))
+ (switch-to-buffer (current-buffer))))))))))
+
+(defun slime-goto-definition-other-window (definition)
+ (slime-pop-to-other-window)
+ (slime-goto-source-location (slime-definition.location definition))
+ (switch-to-buffer (current-buffer)))
+
+(defun slime-pop-to-other-window ()
+ "Pop to the other window, but not to any particular buffer."
+ (pop-to-buffer (current-buffer) t))
+
+(defun slime-edit-definition-other-window (name)
+ "Like `slime-edit-definition' but switch to the other window."
+ (interactive (list (slime-read-symbol-name "Symbol: ")))
+ (slime-edit-definition name 'window))
+
+(defun slime-edit-definition-other-frame (name)
+ "Like `slime-edit-definition' but switch to the other window."
+ (interactive (list (slime-read-symbol-name "Symbol: ")))
+ (slime-edit-definition name 'frame))
+
+(defun slime-edit-definition-with-etags (name)
+ (interactive (list (slime-read-symbol-name "Symbol: ")))
+ (let ((tagdefs (slime-etags-definitions name)))
+ (cond (tagdefs
+ (message "Using tag file...")
+ (slime-goto-definition name tagdefs))
+ (t
+ (error "No known definition for: %s" name)))))
+
+(defun slime-etags-definitions (name)
+ "Search definitions matching NAME in the tags file.
+The result is a (possibly empty) list of definitions."
+ (require 'etags)
+ (let ((defs '()))
+ (save-excursion
+ (let ((first-time t))
+ (while (visit-tags-table-buffer (not first-time))
+ (setq first-time nil)
+ (goto-char (point-min))
+ (while (search-forward name nil t)
+ (beginning-of-line)
+ (destructuring-bind (hint line &rest pos) (etags-snarf-tag)
+ (unless (eq hint t) ; hint==t if we are in a filename line
+ (let ((file (expand-file-name (file-of-tag))))
+ (let ((loc `(:location (:file ,file)
+ (:line ,line)
+ (:snippet ,hint))))
+ (push (list hint loc) defs))))))))
+ (reverse defs))))
+
+(defun slime-show-definitions (name definitions)
+ (slime-show-xrefs
+ `((,name . ,(loop for (dspec location) in definitions
+ collect (cons dspec location))))
+ 'definition
+ name
+ (slime-current-package)))
+
+;;;;; first-change-hook
+
+(defun slime-first-change-hook ()
+ "Notify Lisp that a source file's buffer has been modified."
+ ;; Be careful not to disturb anything!
+ ;; In particular if we muck up the match-data then query-replace
+ ;; breaks. -luke (26/Jul/2004)
+ (save-excursion
+ (save-match-data
+ (when (and (buffer-file-name)
+ (file-exists-p (buffer-file-name))
+ (slime-background-activities-enabled-p))
+ (let ((filename (slime-to-lisp-filename (buffer-file-name))))
+ (slime-eval-async `(swank:buffer-first-change ,filename)))))))
+
+(defun slime-setup-first-change-hook ()
+ (add-hook (make-local-variable 'first-change-hook)
+ 'slime-first-change-hook))
+
+(add-hook 'slime-mode-hook 'slime-setup-first-change-hook)
+
+
+;;;; Eval for Lisp
+
+(defun slime-eval-for-lisp (thread tag form-string)
+ (let ((ok nil)
+ (value nil)
+ (c (slime-connection)))
+ (unwind-protect (progn
+ (slime-check-eval-in-emacs-enabled)
+ (setq value (eval (read form-string)))
+ (setq ok t))
+ (let ((result (if ok `(:ok ,value) `(:abort))))
+ (slime-dispatch-event `(:emacs-return ,thread ,tag ,result) c)))))
+
+(defun slime-check-eval-in-emacs-enabled ()
+ "Raise an error if `slime-enable-evaluate-in-emacs' isn't true."
+ (unless slime-enable-evaluate-in-emacs
+ (error "slime-eval-in-emacs disabled for security. Set slime-enable-evaluate-in-emacs true to enable it.")))
+
+
+;;;; `ED'
+
+(defvar slime-ed-frame nil
+ "The frame used by `slime-ed'.")
+
+(defcustom slime-ed-use-dedicated-frame t
+ "*When non-nil, `slime-ed' will create and reuse a dedicated frame."
+ :type 'boolean
+ :group 'slime-mode)
+
+(defun slime-ed (what)
+ "Edit WHAT.
+
+WHAT can be:
+ A filename (string),
+ A list (FILENAME LINE [COLUMN]),
+ A list (FILENAME :charpos CHARPOS),
+ A function name (symbol or cons),
+ nil.
+
+This is for use in the implementation of COMMON-LISP:ED."
+ ;; Without `save-excursion' very strange things happen if you call
+ ;; (swank:ed-in-emacs X) from the REPL. -luke (18/Jan/2004)
+ (save-excursion
+ (when slime-ed-use-dedicated-frame
+ (unless (and slime-ed-frame (frame-live-p slime-ed-frame))
+ (setq slime-ed-frame (make-frame)))
+ (select-frame slime-ed-frame))
+ (cond ((stringp what)
+ (find-file (slime-from-lisp-filename what)))
+ ((and (consp what) (stringp (first what)))
+ (find-file (first (slime-from-lisp-filename what)))
+ (cond
+ ((eql (second what) :charpos)
+ (goto-char (third what)))
+ (t
+ (goto-line (second what))
+ ;; Find the correct column, without going past the end of
+ ;; the line.
+ (let ((col (third what)))
+ (while (and col
+ (< (point) (point-at-eol))
+ (/= (decf col) -1))
+ (forward-char 1))))))
+ ((and what (symbolp what))
+ (slime-edit-definition (symbol-name what)))
+ ((consp what)
+ (slime-edit-definition (prin1-to-string what)))
+ (t nil)))) ; nothing in particular
+
+
+;;;; Interactive evaluation.
+
+(defun slime-interactive-eval (string)
+ "Read and evaluate STRING and print value in minibuffer.
+
+Note: If a prefix argument is in effect then the result will be
+inserted in the current buffer."
+ (interactive (list (slime-read-from-minibuffer "Slime Eval: ")))
+ (slime-insert-transcript-delimiter string)
+ (cond ((not current-prefix-arg)
+ (slime-eval-with-transcript `(swank:interactive-eval ,string)
+ 'slime-display-eval-result))
+ (t
+ (slime-eval-print string))))
+
+(defun slime-display-eval-result (value)
+ (slime-message "%s" value))
+
+(defun slime-eval-print (string)
+ "Eval STRING in Lisp; insert any output and the result at point."
+ (slime-eval-async `(swank:eval-and-grab-output ,string)
+ (lexical-let ((buffer (current-buffer)))
+ (lambda (result)
+ (with-current-buffer buffer
+ (destructuring-bind (output value) result
+ (insert output value)))))))
+
+(defun slime-eval-with-transcript (form &optional fn)
+ "Send FROM and PACKAGE to Lisp and pass the result to FN.
+Display the result in the message area, if FN is nil.
+Show the output buffer if the evaluation causes any output."
+ (with-current-buffer (slime-output-buffer)
+ (slime-with-output-end-mark
+ (slime-mark-output-start)))
+ (with-lexical-bindings (fn)
+ (slime-eval-async form
+ (lambda (value)
+ (with-current-buffer (slime-output-buffer)
+ (slime-show-last-output)
+ (cond (fn (funcall fn value))
+ (t (message "%s" value))))))))
+
+(defun slime-eval-describe (form)
+ "Evaluate FORM in Lisp and display the result in a new buffer."
+ (lexical-let ((package (slime-current-package)))
+ (slime-eval-with-transcript
+ form (lambda (string) (slime-show-description string package)))))
+
+(defun slime-insert-transcript-delimiter (string)
+ (with-current-buffer (slime-output-buffer)
+ (slime-with-output-end-mark
+ (unless (bolp) (insert-before-markers "\n"))
+ (slime-propertize-region '(slime-transcript-delimiter t)
+ (insert-before-markers
+ ";;;; " (subst-char-in-string ?\n ?\
+ (substring string 0
+ (min 60 (length string))))
+ " ...\n")))))
+
+(defun slime-display-buffer-region (buffer start end &optional other-window)
+ "Like `display-buffer', but only display the specified region."
+ (let ((window-min-height 1))
+ (with-current-buffer buffer
+ (save-excursion
+ (save-restriction
+ (goto-char start)
+ (beginning-of-line)
+ (narrow-to-region (point) end)
+ (let ((window (display-buffer buffer other-window t)))
+ (set-window-start window (point))
+ (unless (or (one-window-p t)
+ (/= (frame-width) (window-width)))
+ (set-window-text-height window (/ (1- (frame-height)) 2)))
+ (shrink-window-if-larger-than-buffer window)
+ window))))))
+
+(defun slime-last-expression ()
+ (buffer-substring-no-properties
+ (save-excursion (backward-sexp) (point))
+ (point)))
+
+(defun slime-eval-last-expression ()
+ "Evaluate the expression preceding point."
+ (interactive)
+ (slime-interactive-eval (slime-last-expression)))
+
+(defun slime-eval-last-expression-display-output ()
+ "Display output buffer and evaluate the expression preceding point."
+ (interactive)
+ (slime-display-output-buffer)
+ (slime-interactive-eval (slime-last-expression)))
+
+(defun slime-eval-defun ()
+ "Evaluate the current toplevel form.
+Use `slime-re-evaluate-defvar' if the from starts with '(defvar'"
+ (interactive)
+ (let ((form (slime-defun-at-point)))
+ (cond ((string-match "^(defvar " form)
+ (slime-re-evaluate-defvar form))
+ (t
+ (slime-interactive-eval form)))))
+
+(defun slime-eval-region (start end)
+ "Evaluate region."
+ (interactive "r")
+ (slime-eval-with-transcript
+ `(swank:interactive-eval-region
+ ,(buffer-substring-no-properties start end))))
+
+(defun slime-eval-buffer ()
+ "Evaluate the current buffer.
+The value is printed in the echo area."
+ (interactive)
+ (slime-eval-region (point-min) (point-max)))
+
+(defun slime-re-evaluate-defvar (form)
+ "Force the re-evaluaton of the defvar form before point.
+
+First make the variable unbound, then evaluate the entire form."
+ (interactive (list (slime-last-expression)))
+ (slime-eval-with-transcript `(swank:re-evaluate-defvar ,form)))
+
+(defun slime-pprint-eval-last-expression ()
+ "Evaluate the form before point; pprint the value in a buffer."
+ (interactive)
+ (slime-eval-describe `(swank:pprint-eval ,(slime-last-expression))))
+
+(defun slime-eval-print-last-expression (string)
+ "Evaluate sexp before point; print value into the current buffer"
+ (interactive (list (slime-last-expression)))
+ (insert "\n")
+ (slime-eval-print string))
+
+(defun slime-call-defun ()
+ "Insert a call to the function defined around point into the REPL."
+ (interactive)
+ (let ((toplevel (slime-parse-toplevel-form)))
+ (unless (and (consp toplevel)
+ (member (car toplevel) '(:defun :defmethod :defgeneric))
+ (symbolp (cadr toplevel)))
+ (error "Not in a function definition"))
+ (let* ((symbol (cadr toplevel))
+ (function-call
+ (format "(%s " (slime-qualify-cl-symbol-name symbol))))
+ (slime-switch-to-output-buffer)
+ (goto-char slime-repl-input-start-mark)
+ (insert function-call)
+ (save-excursion (insert ")")))))
+
+;;;; Edit Lisp value
+;;;
+(defun slime-edit-value (form-string)
+ "\\<slime-edit-value-mode-map>\
+Edit the value of a setf'able form in a new buffer.
+The value is inserted into a temporary buffer for editing and then set
+in Lisp when committed with \\[slime-edit-value-commit]."
+ (interactive
+ (list (slime-read-from-minibuffer "Edit value (evaluated): "
+ (slime-sexp-at-point))))
+ (slime-eval-async `(swank:value-for-editing ,form-string)
+ (lexical-let ((form-string form-string)
+ (package (slime-current-package)))
+ (lambda (result)
+ (slime-edit-value-callback form-string result
+ package)))))
+
+(make-variable-buffer-local
+ (defvar slime-edit-form-string nil
+ "The form being edited by `slime-edit-value'."))
+
+(define-minor-mode slime-edit-value-mode
+ "Mode for editing a Lisp value."
+ nil
+ " edit"
+ '(("\C-c\C-c" . slime-edit-value-commit)))
+
+(defun slime-edit-value-callback (form-string current-value package)
+ (let ((name (generate-new-buffer-name (format "*Edit %s*" form-string))))
+ (with-current-buffer (slime-get-temp-buffer-create name :mode 'lisp-mode)
+ (slime-mode 1)
+ (slime-temp-buffer-mode -1) ; don't want binding of 'q'
+ (slime-edit-value-mode 1)
+ (setq slime-edit-form-string form-string)
+ (setq slime-buffer-connection (slime-connection))
+ (setq slime-buffer-package package)
+ (insert current-value))))
+
+(defun slime-edit-value-commit ()
+ "Commit the edited value to the Lisp image.
+\\(See `slime-edit-value'.)"
+ (interactive)
+ (if (null slime-edit-form-string)
+ (error "Not editing a value.")
+ (let ((value (buffer-substring-no-properties (point-min) (point-max))))
+ (lexical-let ((buffer (current-buffer)))
+ (slime-eval-async `(swank:commit-edited-value ,slime-edit-form-string
+ ,value)
+ (lambda (_)
+ (with-current-buffer buffer
+ (slime-temp-buffer-quit t))))))))
+
+;;;; Tracing
+
+(defun slime-redirect-trace-output ()
+ "Redirect the trace output to a separate Emacs buffer."
+ (interactive)
+ (let ((buffer (get-buffer-create "*SLIME Trace Output*")))
+ (with-current-buffer buffer
+ (let ((marker (copy-marker (buffer-size)))
+ (target (incf slime-last-output-target-id)))
+ (puthash target marker slime-output-target-to-marker)
+ (slime-eval `(swank:redirect-trace-output ,target))))
+ ;; Note: We would like the entries in
+ ;; slime-output-target-to-marker to disappear when the buffers are
+ ;; killed. We cannot just make the hash-table ":weakness 'value"
+ ;; -- there is no reference from the buffers to the markers in the
+ ;; buffer, so entries would disappear even though the buffers are
+ ;; alive. Best solution might be to make buffer-local variables
+ ;; that keep the markers. --mkoeppe
+ (pop-to-buffer buffer)))
+
+(defun slime-untrace-all ()
+ "Untrace all functions."
+ (interactive)
+ (slime-eval `(swank:untrace-all)))
+
+(defun slime-toggle-trace-fdefinition (&optional using-context-p)
+ "Toggle trace."
+ (interactive "P")
+ (let* ((spec (if using-context-p
+ (slime-extract-context)
+ (slime-symbol-name-at-point)))
+ (spec (slime-trace-query spec)))
+ (message "%s" (slime-eval `(swank:swank-toggle-trace ,spec)))))
+
+(defun slime-trace-query (spec)
+ "Ask the user which function to trace; SPEC is the default.
+The result is a string."
+ (cond ((null spec)
+ (slime-read-from-minibuffer "(Un)trace: "))
+ ((stringp spec)
+ (slime-read-from-minibuffer "(Un)trace: " spec))
+ (t
+ (destructure-case spec
+ ((setf n)
+ (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string spec)))
+ (((:defun :defmacro) n)
+ (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string n)))
+ ((:defgeneric n)
+ (let* ((name (prin1-to-string n))
+ (answer (slime-read-from-minibuffer "(Un)trace: " name)))
+ (cond ((and (string= name answer)
+ (y-or-n-p (concat "(Un)trace also all "
+ "methods implementing "
+ name "? ")))
+ (prin1-to-string `(:defgeneric ,n)))
+ (t
+ answer))))
+ ((:defmethod &rest _)
+ (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string spec)))
+ ((:call caller callee)
+ (let* ((callerstr (prin1-to-string caller))
+ (calleestr (prin1-to-string callee))
+ (answer (slime-read-from-minibuffer "(Un)trace: "
+ calleestr)))
+ (cond ((and (string= calleestr answer)
+ (y-or-n-p (concat "(Un)trace only when " calleestr
+ " is called by " callerstr "? ")))
+ (prin1-to-string `(:call ,caller ,callee)))
+ (t
+ answer))))
+ (((:labels :flet) &rest _)
+ (slime-read-from-minibuffer "(Un)trace local function: "
+ (prin1-to-string spec)))))))
+
+(defun slime-extract-context ()
+ "Parse the context for the symbol at point.
+Nil is returned if there's no symbol at point. Otherwise we detect
+the following cases (the . shows the point position):
+
+ (defun n.ame (...) ...) -> (:defun name)
+ (defun (setf n.ame) (...) ...) -> (:defun (setf name))
+ (defmethod n.ame (...) ...) -> (:defmethod name (...))
+ (defun ... (...) (labels ((n.ame (...) -> (:labels (:defun ...) name)
+ (defun ... (...) (flet ((n.ame (...) -> (:flet (:defun ...) name)
+ (defun ... (...) ... (n.ame ...) ...) -> (:call (:defun ...) name)
+ (defun ... (...) ... (setf (n.ame ...) -> (:call (:defun ...) (setf name))
+
+For other contexts we return the symbol at point."
+ (let ((name (slime-symbol-name-at-point)))
+ (if name
+ (let ((symbol (read name)))
+ (or (progn ;;ignore-errors
+ (slime-parse-context symbol))
+ symbol)))))
+
+(defun slime-parse-context (name)
+ (save-excursion
+ (cond ((slime-in-expression-p '(defun *)) `(:defun ,name))
+ ((slime-in-expression-p '(defmacro *)) `(:defmacro ,name))
+ ((slime-in-expression-p '(defgeneric *)) `(:defgeneric ,name))
+ ((slime-in-expression-p '(setf *))
+ ;;a setf-definition, but which?
+ (backward-up-list 1)
+ (slime-parse-context `(setf ,name)))
+ ((slime-in-expression-p '(defmethod *))
+ (unless (looking-at "\\s ")
+ (forward-sexp 1)) ; skip over the methodname
+ (let (qualifiers arglist)
+ (loop for e = (read (current-buffer))
+ until (listp e) do (push e qualifiers)
+ finally (setq arglist e))
+ `(:defmethod ,name , at qualifiers
+ ,(slime-arglist-specializers arglist))))
+ ((and (symbolp name)
+ (slime-in-expression-p `(,name)))
+ ;; looks like a regular call
+ (let ((toplevel (ignore-errors (slime-parse-toplevel-form))))
+ (cond ((slime-in-expression-p `(setf (*))) ;a setf-call
+ (if toplevel
+ `(:call ,toplevel (setf ,name))
+ `(setf ,name)))
+ ((not toplevel)
+ name)
+ ((slime-in-expression-p `(labels ((*))))
+ `(:labels ,toplevel ,name))
+ ((slime-in-expression-p `(flet ((*))))
+ `(:flet ,toplevel ,name))
+ (t
+ `(:call ,toplevel ,name)))))
+ (t
+ name))))
+
+(defun slime-in-expression-p (pattern)
+ "A helper function to determine the current context.
+The pattern can have the form:
+ pattern ::= () ;matches always
+ | (*) ;matches inside a list
+ | (<symbol> <pattern>) ;matches if the first element in
+ ; the current list is <symbol> and
+ ; if <pattern> matches.
+ | ((<pattern>)) ;matches if we are in a nested list."
+ (save-excursion
+ (let ((path (reverse (slime-pattern-path pattern))))
+ (loop for p in path
+ always (ignore-errors
+ (etypecase p
+ (symbol (slime-beginning-of-list)
+ (eq (read (current-buffer)) p))
+ (number (backward-up-list p)
+ t)))))))
+
+(defun slime-pattern-path (pattern)
+ ;; Compute the path to the * in the pattern to make matching
+ ;; easier. The path is a list of symbols and numbers. A number
+ ;; means "(down-list <n>)" and a symbol "(look-at <sym>)")
+ (if (null pattern)
+ '()
+ (etypecase (car pattern)
+ ((member *) '())
+ (symbol (cons (car pattern) (slime-pattern-path (cdr pattern))))
+ (cons (cons 1 (slime-pattern-path (car pattern)))))))
+
+(defun slime-beginning-of-list (&optional up)
+ "Move backward the the beginning of the current expression.
+Point is placed before the first expression in the list."
+ (backward-up-list (or up 1))
+ (down-list 1)
+ (skip-syntax-forward " "))
+
+(defun slime-parse-toplevel-form ()
+ (save-excursion
+ (beginning-of-defun)
+ (down-list 1)
+ (forward-sexp 1)
+ (slime-parse-context (read (current-buffer)))))
+
+(defun slime-arglist-specializers (arglist)
+ (cond ((or (null arglist)
+ (member (first arglist) '(&optional &key &rest &aux)))
+ (list))
+ ((consp (first arglist))
+ (cons (second (first arglist))
+ (slime-arglist-specializers (rest arglist))))
+ (t
+ (cons 't
+ (slime-arglist-specializers (rest arglist))))))
+
+(defun slime-disassemble-symbol (symbol-name)
+ "Display the disassembly for SYMBOL-NAME."
+ (interactive (list (slime-read-symbol-name "Disassemble: ")))
+ (slime-eval-describe `(swank:disassemble-symbol ,symbol-name)))
+
+(defun slime-undefine-function (symbol-name)
+ "Unbind the function slot of SYMBOL-NAME."
+ (interactive (list (slime-read-symbol-name "fmakunbound: " t)))
+ (slime-eval-async `(swank:undefine-function ,symbol-name)
+ (lambda (result) (message "%s" result))))
+
+(defun slime-load-file (filename)
+ "Load the Lisp file FILENAME."
+ (interactive (list
+ (read-file-name "Load file: " nil nil
+ nil (if (buffer-file-name)
+ (file-name-nondirectory
+ (buffer-file-name))))))
+ (let ((lisp-filename (slime-to-lisp-filename (expand-file-name filename))))
+ (slime-eval-with-transcript `(swank:load-file ,lisp-filename))))
+
+
+
+
+;;;; Profiling
+
+(defun slime-toggle-profile-fdefinition (fname-string)
+ "Toggle profiling for FNAME-STRING."
+ (interactive (list (slime-read-from-minibuffer
+ "(Un)Profile: "
+ (slime-symbol-name-at-point))))
+ (slime-eval-async `(swank:toggle-profile-fdefinition ,fname-string)
+ (lambda (r) (message "%s" r))))
+
+(defun slime-unprofile-all ()
+ "Unprofile all functions."
+ (interactive)
+ (slime-eval-async '(swank:unprofile-all)
+ (lambda (r) (message "%s" r))))
+
+(defun slime-profile-report ()
+ "Print profile report."
+ (interactive)
+ (slime-eval-with-transcript '(swank:profile-report)))
+
+(defun slime-profile-reset ()
+ "Reset profile counters."
+ (interactive)
+ (slime-eval-async (slime-eval `(swank:profile-reset))
+ (lambda (r) (message "%s" r))))
+
+(defun slime-profiled-functions ()
+ "Return list of names of currently profiled functions."
+ (interactive)
+ (slime-eval-async `(swank:profiled-functions)
+ (lambda (r) (message "%s" r))))
+
+(defun slime-profile-package (package callers methods)
+ "Profile all functions in PACKAGE.
+If CALLER is non-nil names have counts of the most common calling
+functions recorded.
+If METHODS is non-nil, profile all methods of all generic function
+having names in the given package."
+ (interactive (list (slime-read-package-name "Package: ")
+ (y-or-n-p "Record the most common callers? ")
+ (y-or-n-p "Profile methods? ")))
+ (slime-eval-async `(swank:profile-package ,package ,callers ,methods)
+ (lambda (r) (message "%s" r))))
+
+
+
+;;;; Documentation
+
+(defun slime-hyperspec-lookup (symbol-name)
+ "A wrapper for `hyperspec-lookup'"
+ (interactive (list (let* ((symbol-at-point (slime-symbol-name-at-point))
+ (stripped-symbol
+ (and symbol-at-point
+ (downcase
+ (common-lisp-hyperspec-strip-cl-package
+ symbol-at-point)))))
+ (if (and stripped-symbol
+ (intern-soft stripped-symbol
+ common-lisp-hyperspec-symbols))
+ stripped-symbol
+ (completing-read
+ "Look up symbol in Common Lisp HyperSpec: "
+ common-lisp-hyperspec-symbols #'boundp
+ t stripped-symbol
+ 'common-lisp-hyperspec-history)))))
+ (hyperspec-lookup symbol-name))
+
+(defun slime-show-description (string package)
+ (slime-with-output-to-temp-buffer ("*SLIME Description*")
+ package (princ string)))
+
+(defun slime-describe-symbol (symbol-name)
+ "Describe the symbol at point."
+ (interactive (list (slime-read-symbol-name "Describe symbol: ")))
+ (when (not symbol-name)
+ (error "No symbol given"))
+ (slime-eval-describe `(swank:describe-symbol ,symbol-name)))
+
+(defun slime-documentation (symbol-name)
+ "Display function- or symbol-documentation for SYMBOL-NAME."
+ (interactive (list (slime-read-symbol-name "Documentation for symbol: ")))
+ (when (not symbol-name)
+ (error "No symbol given"))
+ (slime-eval-describe
+ `(swank:documentation-symbol ,symbol-name "(not documented)")))
+
+(defun slime-describe-function (symbol-name)
+ (interactive (list (slime-read-symbol-name "Describe symbol: ")))
+ (when (not symbol-name)
+ (error "No symbol given"))
+ (slime-eval-describe `(swank:describe-function ,symbol-name)))
+
+(defun slime-apropos-summary (string case-sensitive-p package only-external-p)
+ "Return a short description for the performed apropos search."
+ (concat (if case-sensitive-p "Case-sensitive " "")
+ "Apropos for "
+ (format "%S" string)
+ (if package (format " in package %S" package) "")
+ (if only-external-p " (external symbols only)" "")))
+
+(defun slime-apropos (string &optional only-external-p package
+ case-sensitive-p)
+ "Show all bound symbols whose names match STRING. With prefix
+arg, you're interactively asked for parameters of the search."
+ (interactive
+ (if current-prefix-arg
+ (list (read-string "SLIME Apropos: ")
+ (y-or-n-p "External symbols only? ")
+ (let ((pkg (slime-read-package-name "Package: ")))
+ (if (string= pkg "") nil pkg))
+ (y-or-n-p "Case-sensitive? "))
+ (list (read-string "SLIME Apropos: ") t nil nil)))
+ (let ((buffer-package (or package (slime-current-package))))
+ (slime-eval-async
+ `(swank:apropos-list-for-emacs ,string ,only-external-p
+ ,case-sensitive-p ',package)
+ (lexical-let ((string string)
+ (package buffer-package)
+ (summary (slime-apropos-summary string case-sensitive-p
+ package only-external-p)))
+ (lambda (r) (slime-show-apropos r string package summary))))))
+
+(defun slime-apropos-all ()
+ "Shortcut for (slime-apropos <string> nil nil)"
+ (interactive)
+ (slime-apropos (read-string "SLIME Apropos: ") nil nil))
+
+(defun slime-apropos-package (package &optional internal)
+ "Show apropos listing for symbols in PACKAGE.
+With prefix argument include internal symbols."
+ (interactive (list (let ((pkg (slime-read-package-name "Package: ")))
+ (if (string= pkg "") (slime-current-package) pkg))
+ current-prefix-arg))
+ (slime-apropos "" (not internal) package))
+
+(defun slime-show-apropos (plists string package summary)
+ (if (null plists)
+ (message "No apropos matches for %S" string)
+ (slime-with-output-to-temp-buffer ("*SLIME Apropos*" :mode apropos-mode)
+ package
+ (set-syntax-table lisp-mode-syntax-table)
+ (slime-mode t)
+ (if (boundp 'header-line-format)
+ (setq header-line-format summary)
+ (insert summary "\n\n"))
+ (slime-set-truncate-lines)
+ (slime-print-apropos plists))))
+
+(defvar slime-apropos-label-properties
+ (progn
+ (require 'apropos)
+ (cond ((and (boundp 'apropos-label-properties)
+ (symbol-value 'apropos-label-properties)))
+ ((boundp 'apropos-label-face)
+ (etypecase (symbol-value 'apropos-label-face)
+ (symbol `(face ,(or (symbol-value 'apropos-label-face)
+ 'italic)
+ mouse-face highlight))
+ (list (symbol-value 'apropos-label-face)))))))
+
+(eval-when-compile (require 'apropos))
+
+(defun slime-print-apropos (plists)
+ (dolist (plist plists)
+ (let ((designator (plist-get plist :designator)))
+ (assert designator)
+ (slime-insert-propertized `(face ,apropos-symbol-face) designator))
+ (terpri)
+ (let ((apropos-label-properties slime-apropos-label-properties))
+ (loop for (prop namespace)
+ in '((:variable "Variable")
+ (:function "Function")
+ (:generic-function "Generic Function")
+ (:macro "Macro")
+ (:special-operator "Special Operator")
+ (:setf "Setf")
+ (:type "Type")
+ (:class "Class")
+ (:alien-type "Alien type")
+ (:alien-struct "Alien struct")
+ (:alien-union "Alien type")
+ (:alien-enum "Alien enum"))
+ ;; Properties not listed here will not show up in the buffer
+ do
+ (let ((value (plist-get plist prop))
+ (start (point)))
+ (when value
+ (princ " ")
+ (slime-insert-propertized apropos-label-properties namespace)
+ (princ ": ")
+ (princ (etypecase value
+ (string value)
+ ((member :not-documented) "(not documented)")))
+ (add-text-properties
+ start (point)
+ (list 'type prop 'action 'slime-call-describer
+ 'button t 'apropos-label namespace
+ 'item (plist-get plist :designator)))
+ (terpri)))))))
+
+(defun slime-call-describer (arg)
+ (let* ((pos (if (markerp arg) arg (point)))
+ (type (get-text-property pos 'type))
+ (item (get-text-property pos 'item)))
+ (slime-eval-describe `(swank:describe-definition-for-emacs ,item ,type))))
+
+
+;;;; XREF: cross-referencing
+
+(defvar slime-xref-mode-map)
+(defvar slime-xref-saved-emacs-snapshot nil
+ "Buffer local variable in xref windows.")
+
+(define-derived-mode slime-xref-mode lisp-mode "xref"
+ "slime-xref-mode: Major mode for cross-referencing.
+\\<slime-xref-mode-map>\
+The most important commands:
+\\[slime-xref-quit] - Dismiss buffer.
+\\[slime-show-xref] - Display referenced source and keep xref window.
+\\[slime-goto-xref] - Jump to referenced source and dismiss xref window.
+
+\\{slime-xref-mode-map}"
+ (setq font-lock-defaults nil)
+ (setq delayed-mode-hooks nil)
+ (slime-mode -1))
+
+(slime-define-keys slime-xref-mode-map
+ ((kbd "RET") 'slime-show-xref)
+ ([return] 'slime-show-xref)
+ ("\C-m" 'slime-show-xref)
+ (" " 'slime-goto-xref)
+ ("q" 'slime-xref-quit)
+ ("n" 'slime-next-line/not-add-newlines)
+ ("p" 'previous-line))
+
+(defun slime-next-line/not-add-newlines ()
+ (interactive)
+ (let ((next-line-add-newlines nil))
+ (next-line 1)))
+
+;; FIXME: binding SLDB keys in xref buffer? -luke
+(dolist (spec slime-keys)
+ (destructuring-bind (key command &key sldb prefixed &allow-other-keys) spec
+ (when sldb
+ (let ((key (if prefixed (concat slime-prefix-key key) key)))
+ (define-key slime-xref-mode-map key command)))))
+
+
+;;;;; XREF results buffer and window management
+
+(defun slime-xref-buffer ()
+ "Return the XREF results buffer.
+If CREATE is non-nil, create it if necessary."
+ (or (find-if (lambda (b) (string-match "*XREF\\[" (buffer-name b)))
+ (buffer-list))
+ (error "No XREF buffer")))
+
+(defun slime-init-xref-buffer (package ref-type symbol)
+ "Initialize the current buffer for displaying XREF information."
+ (slime-xref-mode)
+ (setq buffer-read-only nil)
+ (erase-buffer)
+ (setq slime-buffer-package package)
+ (slime-set-truncate-lines))
+
+;; XXX: unused function
+(defun slime-display-xref-buffer ()
+ "Display the XREF results buffer in a window and select it."
+ (let* ((buffer (slime-xref-buffer))
+ (window (get-buffer-window buffer)))
+ (if (and window (window-live-p window))
+ (select-window window)
+ (select-window (display-buffer buffer t))
+ (shrink-window-if-larger-than-buffer))))
+
+(defmacro* slime-with-xref-buffer ((package ref-type symbol &key emacs-snapshot)
+ &body body)
+ "Execute BODY in a xref buffer, then show that buffer."
+ (let ((type (gensym "TYPE+")) (sym (gensym "SYM+"))
+ (pkg (gensym "PKG+")) (snapshot (gensym "SNAPSHOT+")))
+ `(let ((,type ,ref-type) (,sym ,symbol) (,pkg ,package))
+ ;; We don't want the the xref buffer to be the current buffer
+ ;; in the snapshot, so we gotta take the snapshot here.
+ (let ((,snapshot (or ,emacs-snapshot (slime-current-emacs-snapshot))))
+ (with-current-buffer (get-buffer-create
+ (format "*XREF[%s: %s]*" ,type ,sym))
+ (prog2 (progn
+ (slime-init-xref-buffer ,pkg ,type ,sym)
+ (make-local-variable 'slime-xref-saved-emacs-snapshot)
+ (setq slime-xref-saved-emacs-snapshot ,snapshot))
+ (progn , at body)
+ (setq buffer-read-only t)
+ (select-window (or (get-buffer-window (current-buffer) t)
+ (display-buffer (current-buffer) t)))
+ (shrink-window-if-larger-than-buffer)))))))
+
+(put 'slime-with-xref-buffer 'lisp-indent-function 1)
+
+(defun slime-insert-xrefs (xrefs)
+ "Insert XREFS in the current-buffer.
+XREFS is a list of the form ((GROUP . ((LABEL . LOCATION) ...)) ...)
+GROUP and LABEL are for decoration purposes. LOCATION is a source-location."
+ (unless (bobp) (insert "\n"))
+ (loop for (group . refs) in xrefs do
+ (progn
+ (slime-insert-propertized '(face bold) group "\n")
+ (loop
+ for (label . location) in refs
+ do (slime-insert-propertized
+ (list 'slime-location location
+ 'face 'font-lock-keyword-face)
+ " " (slime-one-line-ify label))
+ do (insert " - " (slime-insert-xref-location location) "\n"))))
+ ;; Remove the final newline to prevent accidental window-scrolling
+ (backward-char 1)
+ (delete-char 1))
+
+(defun slime-insert-xref-location (location)
+ (if (eql :location (car location))
+ (cond ((assoc :file (cdr location))
+ (second (assoc :file (cdr location))))
+ ((assoc :buffer (cdr location))
+ (let* ((name (second (assoc :buffer (cdr location))))
+ (buffer (get-buffer name)))
+ (if buffer
+ (format "%S" buffer)
+ (format "%s (previously existing buffer)" name)))))
+ "file unknown"))
+
+(defvar slime-next-location-function nil
+ "Function to call for going to the next location.")
+
+(defun slime-show-xrefs (xrefs type symbol package &optional emacs-snapshot)
+ "Show the results of an XREF query."
+ (if (null xrefs)
+ (message "No references found for %s." symbol)
+ (setq slime-next-location-function 'slime-goto-next-xref)
+ (slime-with-xref-buffer (package type symbol :emacs-snapshot emacs-snapshot)
+ (slime-insert-xrefs xrefs)
+ (goto-char (point-min))
+ (forward-line)
+ (skip-chars-forward " \t"))))
+
+
+;;;;; XREF commands
+
+(defun slime-who-calls (symbol)
+ "Show all known callers of the function SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who calls: " t)))
+ (slime-xref :calls symbol))
+
+(defun slime-calls-who (symbol)
+ "Show all known functions called by the function SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who calls: " t)))
+ (slime-xref :calls-who symbol))
+
+(defun slime-who-references (symbol)
+ "Show all known referrers of the global variable SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who references: " t)))
+ (slime-xref :references symbol))
+
+(defun slime-who-binds (symbol)
+ "Show all known binders of the global variable SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who binds: " t)))
+ (slime-xref :binds symbol))
+
+(defun slime-who-sets (symbol)
+ "Show all known setters of the global variable SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who sets: " t)))
+ (slime-xref :sets symbol))
+
+(defun slime-who-macroexpands (symbol)
+ "Show all known expanders of the macro SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who macroexpands: " t)))
+ (slime-xref :macroexpands symbol))
+
+(defun slime-who-specializes (symbol)
+ "Show all known methods specialized on class SYMBOL."
+ (interactive (list (slime-read-symbol-name "Who specializes: " t)))
+ (slime-xref :specializes symbol))
+
+(defun slime-list-callers (symbol-name)
+ "List the callers of SYMBOL-NAME in a xref window."
+ (interactive (list (slime-read-symbol-name "List callers: ")))
+ (slime-xref :callers symbol-name))
+
+(defun slime-list-callees (symbol-name)
+ "List the callees of SYMBOL-NAME in a xref window."
+ (interactive (list (slime-read-symbol-name "List callees: ")))
+ (slime-xref :callees symbol-name))
+
+(defun slime-xref (type symbol)
+ "Make an XREF request to Lisp."
+ (slime-eval-async
+ `(swank:xref ',type ',symbol)
+ (lexical-let ((type type)
+ (symbol symbol)
+ (package (slime-current-package))
+ ;; We have to take the snapshot here, because SLIME-EVAL-ASYNC
+ ;; is invoking its continuation within the extent of a different
+ ;; buffer. (2007-08-14)
+ (snapshot (slime-current-emacs-snapshot)))
+ (lambda (result)
+ (slime-show-xrefs result type symbol package snapshot)))))
+
+
+;;;;; XREF navigation
+
+(defun slime-xref-location-at-point ()
+ (save-excursion
+ ;; When the end of the last line is at (point-max) we can't find
+ ;; the text property there. Going to bol avoids this problem.
+ (beginning-of-line 1)
+ (or (get-text-property (point) 'slime-location)
+ (error "No reference at point."))))
+
+(defun slime-goto-xref ()
+ "Goto the cross-referenced location at point."
+ (interactive)
+ (let ((location (slime-xref-location-at-point)))
+ (slime-xref-cleanup)
+ (slime-goto-source-location location)
+ (switch-to-buffer (current-buffer))))
+
+(defun slime-show-xref ()
+ "Display the xref at point in the other window."
+ (interactive)
+ (let ((location (slime-xref-location-at-point)))
+ (slime-show-source-location location)))
+
+(defun slime-goto-next-xref ()
+ "Goto the next cross-reference location."
+ (let ((location (with-current-buffer (slime-xref-buffer)
+ (let ((w (display-buffer (current-buffer) t)))
+ (goto-char (1+ (next-single-char-property-change
+ (point) 'slime-location)))
+ (set-window-point w (point)))
+ (cond ((eobp)
+ (message "No more xrefs.")
+ nil)
+ (t
+ (slime-xref-location-at-point))))))
+ (when location
+ (slime-goto-source-location location)
+ (switch-to-buffer (current-buffer)))))
+
+(defun slime-next-location ()
+ "Go to the next location, depending on context.
+When displaying XREF information, this goes to the next reference."
+ (interactive)
+ (when (null slime-next-location-function)
+ (error "No context for finding locations."))
+ (funcall slime-next-location-function))
+
+(defun slime-xref-quit ()
+ "Kill the current xref buffer and restore the window configuration."
+ (interactive)
+ (let ((snapshot slime-xref-saved-emacs-snapshot))
+ (slime-xref-cleanup)
+ (slime-set-emacs-snapshot snapshot)))
+
+(defun slime-xref-cleanup ()
+ "Delete overlays created by xref mode and kill the xref buffer."
+ (sldb-delete-overlays)
+ (let ((buffer (current-buffer)))
+ (delete-windows-on buffer)
+ (kill-buffer buffer)))
+
+
+;;;; Macroexpansion
+
+(define-minor-mode slime-macroexpansion-minor-mode
+ "SLIME mode for macroexpansion"
+ nil
+ " temp"
+ '(("q" . slime-temp-buffer-quit)
+ ("g" . slime-macroexpand-again)))
+
+(flet ((remap (from to)
+ (dolist (mapping (where-is-internal from slime-mode-map))
+ (define-key slime-macroexpansion-minor-mode-map mapping to))))
+ (remap 'slime-macroexpand-1 'slime-macroexpand-1-inplace)
+ (remap 'slime-macroexpand-all 'slime-macroexpand-all-inplace)
+ (remap 'undo '(lambda (&optional arg)
+ (interactive)
+ (let ((buffer-read-only nil))
+ (when (fboundp 'slime-remove-edits)
+ (slime-remove-edits (point-min) (point-max)))
+ (undo arg)))))
+
+(defun slime-sexp-at-point-for-macroexpansion ()
+ "Essentially like SLIME-SEXP-AT-POINT-OR-ERROR, but behaves a
+bit more sanely in situations like ,(loop ...) where you want to
+expand the LOOP form. See comment in the source of this function."
+ (let ((string (slime-sexp-at-point-or-error))
+ (bounds (bounds-of-thing-at-point 'sexp))
+ (char-at-point (substring-no-properties (thing-at-point 'char))))
+ ;; SLIME-SEXP-AT-POINT(-OR-ERROR) uses (THING-AT-POINT 'SEXP)
+ ;; which is quite a bit botched: it returns "'(FOO BAR BAZ)" even
+ ;; when point is placed _at the opening parenthesis_, and hence
+ ;; "(FOO BAR BAZ)" wouldn't get expanded. Likewise for ",(...)",
+ ;; ",@(...)" (would return "@(...)"!!), and "\"(...)".
+ ;; So we better fix this up here:
+ (when (string= char-at-point "(")
+ (let ((char0 (elt string 0)))
+ (when (member char0 '(?\' ?\, ?\" ?\@))
+ (setf string (substring string 1))
+ (incf (car bounds)))))
+ (list string bounds)))
+
+(defvar slime-eval-macroexpand-expression nil
+ "Specifies the last macroexpansion preformed. This variable
+ specifies both what was expanded and how.")
+
+(defun slime-eval-macroexpand (expander &optional string)
+ (unless string
+ (setf string (first (slime-sexp-at-point-for-macroexpansion))))
+ (setf slime-eval-macroexpand-expression `(,expander ,string))
+ (lexical-let ((package (slime-current-package)))
+ (slime-eval-async
+ slime-eval-macroexpand-expression
+ (lambda (expansion)
+ (slime-with-output-to-temp-buffer
+ ;; reusep for preserving `undo' functionality.
+ ("*SLIME macroexpansion*" :mode lisp-mode :reusep t) package
+ (slime-macroexpansion-minor-mode)
+ (erase-buffer)
+ (insert expansion)
+ (font-lock-fontify-buffer))))))
+
+(defun slime-eval-macroexpand-inplace (expander)
+ "Substitutes the current sexp at place with its macroexpansion.
+
+NB: Does not affect *slime-eval-macroexpand-expression*"
+ (interactive)
+ (destructuring-bind (string bounds)
+ (slime-sexp-at-point-for-macroexpansion)
+ (lexical-let* ((start (car bounds))
+ (end (cdr bounds))
+ (point (point))
+ (package (slime-current-package))
+ (buffer (current-buffer)))
+ (slime-eval-async
+ `(,expander ,string)
+ (lambda (expansion)
+ (with-current-buffer buffer
+ (let ((buffer-read-only nil))
+ (when (fboundp 'slime-remove-edits)
+ (slime-remove-edits (point-min) (point-max)))
+ (goto-char start)
+ (delete-region start end)
+ (insert expansion)
+ (goto-char start)
+ (indent-sexp)
+ (goto-char point))))))))
+
+
+(defun slime-macroexpand-1 (&optional repeatedly)
+ "Display the macro expansion of the form at point. The form is
+expanded with CL:MACROEXPAND-1 or, if a prefix argument is given, with
+CL:MACROEXPAND."
+ (interactive "P")
+ (slime-eval-macroexpand
+ (if repeatedly 'swank:swank-macroexpand 'swank:swank-macroexpand-1)))
+
+(defun slime-macroexpand-1-inplace (&optional repeatedly)
+ (interactive "P")
+ (slime-eval-macroexpand-inplace
+ (if repeatedly 'swank:swank-macroexpand 'swank:swank-macroexpand-1)))
+
+(defun slime-macroexpand-all ()
+ "Display the recursively macro expanded sexp at point."
+ (interactive)
+ (slime-eval-macroexpand 'swank:swank-macroexpand-all))
+
+(defun slime-macroexpand-all-inplace ()
+ "Display the recursively macro expanded sexp at point."
+ (interactive)
+ (slime-eval-macroexpand-inplace 'swank:swank-macroexpand-all))
+
+(defun slime-compiler-macroexpand ()
+ "Display the compiler-macro expansion of sexp at point."
+ (interactive)
+ (slime-eval-macroexpand 'swank:swank-compiler-macroexpand))
+
+(defun slime-compiler-macroexpand-1 ()
+ "Display the compiler-macro expansion of sexp at point."
+ (interactive)
+ (slime-eval-macroexpand 'swank:swank-compiler-macroexpand-1))
+
+(defun slime-macroexpand-again ()
+ "Reperform the last macroexpansion."
+ (interactive)
+ (slime-eval-macroexpand (first slime-eval-macroexpand-expression)
+ (second slime-eval-macroexpand-expression)))
+
+
+;;;; Subprocess control
+
+(defun slime-interrupt ()
+ "Interrupt Lisp."
+ (interactive)
+ (cond ((slime-use-sigint-for-interrupt) (slime-send-sigint))
+ (t (slime-dispatch-event `(:emacs-interrupt ,slime-current-thread)))))
+
+(defun slime-quit ()
+ (error "Not implemented properly. Use `slime-interrupt' instead."))
+
+(defun slime-quit-lisp (&optional keep-buffers)
+ "Quit lisp, kill the inferior process and associated buffers."
+ (interactive)
+ (slime-eval-async '(swank:quit-lisp))
+ (kill-buffer (slime-output-buffer))
+ (set-process-filter (slime-connection) nil)
+ (set-process-sentinel (slime-connection) 'slime-quit-sentinel))
+
+(defun slime-quit-sentinel (process message)
+ (assert (process-status process) 'closed)
+ (let* ((inferior (slime-inferior-process process))
+ (inferior-buffer (if inferior (process-buffer inferior))))
+ (when inferior (delete-process inferior))
+ (when inferior-buffer (kill-buffer inferior-buffer))
+ (slime-net-close process)
+ (message "Connection closed.")))
+
+(defun slime-set-package (package)
+ (interactive (list (slime-read-package-name
+ "Package: " (slime-pretty-find-buffer-package))))
+ (message "*package*: %s" (slime-eval `(swank:set-package ,package))))
+
+(defun slime-set-default-directory (directory)
+ "Make DIRECTORY become Lisp's current directory."
+ (interactive (list (read-directory-name "Directory: " nil nil t)))
+ (message "default-directory: %s"
+ (slime-from-lisp-filename
+ (slime-eval `(swank:set-default-directory
+ ,(slime-to-lisp-filename directory)))))
+ (with-current-buffer (slime-output-buffer)
+ (setq default-directory (expand-file-name directory))))
+
+(defun slime-sync-package-and-default-directory ()
+ "Set Lisp's package and directory to the values in current buffer."
+ (interactive)
+ (let ((package (slime-eval `(swank:set-package
+ ,(slime-find-buffer-package))))
+ (directory (slime-from-lisp-filename
+ (slime-eval `(swank:set-default-directory
+ ,(slime-to-lisp-filename
+ default-directory))))))
+ (let ((dir default-directory))
+ ;; Sync REPL dir
+ (with-current-buffer (slime-output-buffer)
+ (setq default-directory dir))
+ ;; Sync *inferior-lisp* dir
+ (let* ((proc (slime-process))
+ (buffer (and proc (process-buffer proc))))
+ (when buffer
+ (with-current-buffer buffer
+ (setq default-directory dir)))))
+ (message "package: %s default-directory: %s" (car package) directory)))
+
+
+;;;; Debugger (SLDB)
+
+(defvar sldb-hook nil
+ "Hook run on entry to the debugger.")
+
+
+;;;;; Local variables in the debugger buffer
+
+(slime-make-variables-buffer-local
+ (defvar sldb-condition nil
+ "A list (DESCRIPTION TYPE) describing the condition being debugged.")
+
+ (defvar sldb-saved-window-configuration nil
+ "Window configuration before the debugger was initially entered.")
+
+ (defvar sldb-restarts nil
+ "List of (NAME DESCRIPTION) for each available restart.")
+
+ (defvar sldb-level nil
+ "Current debug level (recursion depth) displayed in buffer.")
+
+ (defvar sldb-backtrace-start-marker nil
+ "Marker placed at the beginning of the backtrace text.")
+
+ (defvar sldb-continuations nil
+ "List of ids for pending continuation."))
+
+;;;;; SLDB macros
+
+;; some macros that we need to define before the first use
+
+(defmacro in-sldb-face (name string)
+ "Return STRING propertised with face sldb-NAME-face."
+ (let ((facename (intern (format "sldb-%s-face" (symbol-name name))))
+ (var (gensym "string")))
+ `(let ((,var ,string))
+ (slime-add-face ',facename ,var)
+ ,var)))
+
+(put 'in-sldb-face 'lisp-indent-function 1)
+
+(defun slime-add-face (face string)
+ (add-text-properties 0 (length string) (list 'face face) string)
+ string)
+
+
+;;;;; sldb-mode
+
+(defvar sldb-mode-syntax-table
+ (let ((table (copy-syntax-table lisp-mode-syntax-table)))
+ ;; We give < and > parenthesis syntax, so that #< ... > is treated
+ ;; as a balanced expression. This enables autodoc-mode to match
+ ;; #<unreadable> actual arguments in the backtraces with formal
+ ;; arguments of the function. (For Lisp mode, this is not
+ ;; desirable, since we do not wish to get a mismatched paren
+ ;; highlighted everytime we type < or >.)
+ (modify-syntax-entry ?< "(" table)
+ (modify-syntax-entry ?> ")" table)
+ table)
+ "Syntax table for SLDB mode.")
+
+(define-derived-mode sldb-mode fundamental-mode "sldb"
+ "Superior lisp debugger mode. In addition to ordinary SLIME commands,
+the following are available:\\<sldb-mode-map>
+
+Commands to examine the selected frame:
+ \\[sldb-toggle-details] - toggle details (local bindings, CATCH tags)
+ \\[sldb-show-source] - view source for the frame
+ \\[sldb-eval-in-frame] - eval in frame
+ \\[sldb-pprint-eval-in-frame] - eval in frame, pretty-print result
+ \\[sldb-disassemble] - disassemble
+ \\[sldb-inspect-in-frame] - inspect
+
+Commands to invoke restarts:
+ \\[sldb-quit] - quit
+ \\[sldb-abort] - abort
+ \\[sldb-continue] - continue
+ \\[sldb-invoke-restart-0]-\\[sldb-invoke-restart-9] - restart shortcuts
+
+Commands to navigate frames:
+ \\[sldb-down] - down
+ \\[sldb-up] - up
+ \\[sldb-details-down] - down, with details
+ \\[sldb-details-up] - up, with details
+
+Miscellaneous commands:
+ \\[sldb-restart-frame] - restart frame
+ \\[sldb-return-from-frame] - return from frame
+ \\[sldb-step] - step
+ \\[sldb-break-with-default-debugger] - switch to default debugger
+ \\[slime-interactive-eval] - eval
+
+Full list of commands:
+
+\\{sldb-mode-map}"
+ (erase-buffer)
+ (set-syntax-table sldb-mode-syntax-table)
+ (slime-set-truncate-lines)
+ ;; Make original slime-connection "sticky" for SLDB commands in this buffer
+ (setq slime-buffer-connection (slime-connection))
+ (add-local-hook 'kill-buffer-hook 'sldb-delete-overlays)
+ (add-local-hook 'kill-buffer-hook 'sldb-quit))
+
+(slime-define-keys sldb-mode-map
+ ("h" 'describe-mode)
+ ("v" 'sldb-show-source)
+ ((kbd "RET") 'sldb-default-action)
+ ("\C-m" 'sldb-default-action)
+ ([return] 'sldb-default-action)
+ ([mouse-2] 'sldb-default-action/mouse)
+ ([follow-link] 'mouse-face)
+ ("e" 'sldb-eval-in-frame)
+ ("d" 'sldb-pprint-eval-in-frame)
+ ("D" 'sldb-disassemble)
+ ("i" 'sldb-inspect-in-frame)
+ ("n" 'sldb-down)
+ ("p" 'sldb-up)
+ ("\M-n" 'sldb-details-down)
+ ("\M-p" 'sldb-details-up)
+ ("<" 'sldb-beginning-of-backtrace)
+ (">" 'sldb-end-of-backtrace)
+ ("t" 'sldb-toggle-details)
+ ("r" 'sldb-restart-frame)
+ ("R" 'sldb-return-from-frame)
+ ("c" 'sldb-continue)
+ ("s" 'sldb-step)
+ ("x" 'sldb-next)
+ ("o" 'sldb-out)
+ ("b" 'sldb-break-on-return)
+ ("a" 'sldb-abort)
+ ("q" 'sldb-quit)
+ ("B" 'sldb-break-with-default-debugger)
+ ("P" 'sldb-print-condition)
+ ("C" 'sldb-inspect-condition)
+ (":" 'slime-interactive-eval)
+ ("\C-c\C-d" slime-doc-map))
+
+;; Inherit bindings from slime-mode
+(dolist (spec slime-keys)
+ (destructuring-bind (key command &key sldb prefixed &allow-other-keys) spec
+ (when sldb
+ (let ((key (if prefixed (concat slime-prefix-key key) key)))
+ (define-key sldb-mode-map key command)))))
+
+;; Keys 0-9 are shortcuts to invoke particular restarts.
+(defmacro define-sldb-invoke-restart-key (number key)
+ (let ((fname (intern (format "sldb-invoke-restart-%S" number)))
+ (docstring (format "Invoke restart numbered %S." number)))
+ `(progn
+ (defun ,fname ()
+ ,docstring
+ (interactive)
+ (sldb-invoke-restart ,number))
+ (define-key sldb-mode-map ,key ',fname))))
+
+(defmacro define-sldb-invoke-restart-keys (from to)
+ `(progn
+ ,@(loop for n from from to to
+ collect `(define-sldb-invoke-restart-key ,n
+ ,(number-to-string n)))))
+
+(define-sldb-invoke-restart-keys 0 9)
+
+
+;;;;; SLDB buffer creation & update
+
+(defun sldb-buffers ()
+ "Return a list of all sldb buffers."
+ (slime-filter-buffers (lambda () (eq major-mode 'sldb-mode))))
+
+(defun sldb-find-buffer (thread &optional connection)
+ (let ((connection (or connection (slime-connection))))
+ (find-if (lambda (buffer)
+ (with-current-buffer buffer
+ (and (eq slime-buffer-connection connection)
+ (eq slime-current-thread thread))))
+ (sldb-buffers))))
+
+(defun sldb-get-default-buffer ()
+ "Get a sldb buffer.
+The buffer is chosen more or less randomly."
+ (car (sldb-buffers)))
+
+(defun sldb-get-buffer (thread &optional connection)
+ "Find or create a sldb-buffer for THREAD."
+ (let ((connection (or connection (slime-connection))))
+ (or (sldb-find-buffer thread connection)
+ (let ((name (format "*sldb %s/%s*" (slime-connection-name) thread)))
+ (with-current-buffer (generate-new-buffer name)
+ (setq slime-buffer-connection connection
+ slime-current-thread thread)
+ (current-buffer))))))
+
+(defun sldb-debugged-continuations (connection)
+ "Return the debugged continuations for CONNECTION."
+ (lexical-let ((accu '()))
+ (dolist (b (sldb-buffers))
+ (with-current-buffer b
+ (when (eq slime-buffer-connection connection)
+ (setq accu (append sldb-continuations accu)))))
+ accu))
+
+(defun sldb-setup (thread level condition restarts frames conts)
+ "Setup a new SLDB buffer.
+CONDITION is a string describing the condition to debug.
+RESTARTS is a list of strings (NAME DESCRIPTION) for each available restart.
+FRAMES is a list (NUMBER DESCRIPTION) describing the initial
+portion of the backtrace. Frames are numbered from 0.
+CONTS is a list of pending Emacs continuations."
+ (with-current-buffer (sldb-get-buffer thread)
+ (unless (equal sldb-level level)
+ (setq buffer-read-only nil)
+ (sldb-mode)
+ (unless sldb-saved-window-configuration
+ (setq sldb-saved-window-configuration (current-window-configuration)))
+ (setq slime-current-thread thread)
+ (setq sldb-level level)
+ (setq mode-name (format "sldb[%d]" sldb-level))
+ (setq sldb-condition condition)
+ (setq sldb-restarts restarts)
+ (setq sldb-continuations conts)
+ (sldb-insert-condition condition)
+ (insert "\n\n" (in-sldb-face section "Restarts:") "\n")
+ (sldb-insert-restarts restarts)
+ (insert "\n" (in-sldb-face section "Backtrace:") "\n")
+ (setq sldb-backtrace-start-marker (point-marker))
+ (save-excursion
+ (sldb-insert-frames (sldb-prune-initial-frames frames) t))
+ (run-hooks 'sldb-hook)
+ (pop-to-buffer (current-buffer))
+ (sldb-recenter-region (point-min) (point))
+ (setq buffer-read-only t)
+ (when (and slime-stack-eval-tags
+ ;; (y-or-n-p "Enter recursive edit? ")
+ )
+ (message "Entering recursive edit..")
+ (recursive-edit)))))
+
+(defun sldb-activate (thread level)
+ "Display the debugger buffer for THREAD.
+If LEVEL isn't the same as in the buffer, reinitialize the buffer."
+ (unless (let ((b (sldb-find-buffer thread)))
+ (and b (with-current-buffer b (equal sldb-level level))))
+ (slime-rex (thread level)
+ ('(swank:debugger-info-for-emacs 0 10)
+ nil thread)
+ ((:ok result)
+ (apply #'sldb-setup thread level result)))))
+
+(defun sldb-exit (thread level &optional stepping)
+ "Exit from the debug level LEVEL."
+ (when-let (sldb (sldb-find-buffer thread))
+ (with-current-buffer sldb
+ (unless stepping
+ (set-window-configuration sldb-saved-window-configuration))
+ (let ((inhibit-read-only t))
+ (erase-buffer))
+ (setq sldb-level nil))
+ (when (and (= level 1) (not stepping))
+ (kill-buffer sldb))))
+
+(defun sldb-insert-condition (condition)
+ "Insert the text for CONDITION.
+CONDITION should be a list (MESSAGE TYPE EXTRAS).
+EXTRAS is currently used for the stepper."
+ (destructuring-bind (message type extras) condition
+ (when (> (length message) 70)
+ (add-text-properties 0 (length message) (list 'help-echo message)
+ message))
+ (slime-insert-propertized '(sldb-default-action sldb-inspect-condition)
+ (in-sldb-face topline message)
+ "\n"
+ (in-sldb-face condition type))
+ (sldb-dispatch-extras extras)))
+
+(defvar sldb-extras-hooks)
+
+(defun sldb-dispatch-extras (extras)
+ ;; this is (mis-)used for the stepper
+ (dolist (extra extras)
+ (destructure-case extra
+ ((:show-frame-source n)
+ (sldb-show-frame-source n))
+ (t
+ (or (run-hook-with-args-until-success 'sldb-extras-hooks extra)
+ ;;(error "Unhandled extra element:" extra)
+ )))))
+
+(defun sldb-insert-restarts (restarts)
+ "Insert RESTARTS and add the needed text props
+RESTARTS should be alist ((NAME DESCRIPTION) ...)."
+ (loop for (name string) in restarts
+ for number from 0 do
+ (insert " ")
+ (slime-insert-propertized
+ `(, at nil restart-number ,number
+ sldb-default-action sldb-invoke-restart
+ mouse-face highlight)
+ (in-sldb-face restart-number (number-to-string number))
+ ": [" (in-sldb-face restart-type name) "] "
+ (in-sldb-face restart string))
+ (insert "\n")))
+
+(defun sldb-prune-initial-frames (frames)
+ "Return the prefix of FRAMES to initially present to the user.
+Regexp heuristics are used to avoid showing SWANK-internal frames."
+ (let* ((case-fold-search t)
+ (rx "^\\([() ]\\|lambda\\)*swank\\>"))
+ (or (loop for frame in frames
+ for (_ string) = frame
+ until (string-match rx string)
+ collect frame)
+ frames)))
+
+(defun sldb-insert-frames (frames more)
+ "Insert FRAMES into buffer.
+If MORE is non-nil, more frames are on the Lisp stack."
+ (mapc #'sldb-insert-frame frames)
+ (when more
+ (destructuring-bind ((num _)) (last frames)
+ (slime-insert-propertized
+ `(, at nil sldb-default-action sldb-fetch-more-frames
+ sldb-previous-frame-number ,num
+ point-entered sldb-fetch-more-frames
+ start-open t
+ face sldb-section-face
+ mouse-face highlight)
+ " --more--")
+ (insert "\n"))))
+
+(defun sldb-insert-frame (frame &optional face)
+ "Insert FRAME with FACE at point.
+If FACE is nil use `sldb-frame-line-face'."
+ (destructuring-bind (number string) frame
+ (let ((props `(frame ,frame sldb-default-action sldb-toggle-details)))
+ (slime-propertize-region props
+ (slime-propertize-region '(mouse-face highlight)
+ (insert " " (in-sldb-face frame-label (format "%2d:" number)) " ")
+ (slime-insert-indented
+ (slime-add-face (or face 'sldb-frame-line-face)
+ string)))
+ (insert "\n")))))
+
+(defun sldb-fetch-more-frames (&rest ignore)
+ "Fetch more backtrace frames.
+Called on the `point-entered' text-property hook."
+ (let ((inhibit-point-motion-hooks t)
+ (inhibit-read-only t)
+ (prev (get-text-property (point) 'sldb-previous-frame-number)))
+ ;; for unkown reasons, PREV is sometimes nil
+ (when prev
+ (let* ((count 40)
+ (from (1+ prev))
+ (to (+ from count))
+ (frames (slime-eval `(swank:backtrace ,from ,to)))
+ (more (slime-length= frames count))
+ (pos (point)))
+ (delete-region (line-beginning-position) (point-max))
+ (sldb-insert-frames frames more)
+ (goto-char pos)))))
+
+
+;;;;;; SLDB examining text props
+
+(defun sldb-restart-at-point ()
+ (or (get-text-property (point) 'restart-number)
+ (error "No restart at point")))
+
+(defun sldb-frame-number-at-point ()
+ (let ((frame (get-text-property (point) 'frame)))
+ (cond (frame (car frame))
+ (t (error "No frame at point")))))
+
+(defun sldb-var-number-at-point ()
+ (let ((var (get-text-property (point) 'var)))
+ (cond (var var)
+ (t (error "No variable at point")))))
+
+(defun sldb-previous-frame-number ()
+ (save-excursion
+ (sldb-backward-frame)
+ (sldb-frame-number-at-point)))
+
+(defun sldb-frame-details-visible-p ()
+ (and (get-text-property (point) 'frame)
+ (get-text-property (point) 'details-visible-p)))
+
+(defun sldb-frame-region ()
+ (save-excursion
+ (goto-char (next-single-property-change (point) 'frame nil (point-max)))
+ (backward-char)
+ (values (previous-single-property-change (point) 'frame)
+ (next-single-property-change (point) 'frame nil (point-max)))))
+
+(defun sldb-forward-frame ()
+ (goto-char (next-single-char-property-change (point) 'frame)))
+
+(defun sldb-backward-frame ()
+ (goto-char (previous-single-char-property-change
+ (car (sldb-frame-region))
+ 'frame
+ nil sldb-backtrace-start-marker)))
+
+(defun sldb-goto-last-frame ()
+ (goto-char (point-max))
+ (while (not (get-text-property (point) 'frame))
+ (goto-char (previous-single-property-change (point) 'frame))))
+
+(defun sldb-beginning-of-backtrace ()
+ "Goto the first frame."
+ (interactive)
+ (goto-char sldb-backtrace-start-marker))
+
+
+;;;;;; SLDB recenter & redisplay
+
+;; FIXME: these functions need factorization
+
+(defvar sldb-show-location-recenter-arg nil
+ "Argument to pass to `recenter' when displaying a source location.")
+
+(defun slime-show-buffer-position (position)
+ "Ensure sure that the POSITION in the current buffer is visible."
+ (save-selected-window
+ (let ((w (select-window (or (get-buffer-window (current-buffer) t)
+ (display-buffer (current-buffer) t)))))
+ (goto-char position)
+ (push-mark)
+ (unless (pos-visible-in-window-p)
+ (slime-recenter-window w sldb-show-location-recenter-arg)))))
+
+(defun slime-recenter-window (window line)
+ "Set window-start in WINDOW LINE lines before point."
+ (let* ((line (if (not line)
+ (/ (window-height window) 2)
+ line))
+ (start (save-excursion
+ (loop repeat line do (forward-line -1))
+ (point))))
+ (set-window-start window start)))
+
+(defun sldb-recenter-region (start end &optional center)
+ "Make the region from START to END visible.
+Avoid point motions, if possible.
+Minimize scrolling, if CENTER is nil.
+If CENTER is true, scroll enough to center the region in the window."
+ (let ((pos (point)) (lines (count-screen-lines start end t)))
+ (assert (and (<= start pos) (<= pos end)))
+ ;;(sit-for 0)
+ (cond ((and (pos-visible-in-window-p start)
+ (pos-visible-in-window-p end)))
+ ((< lines (window-height))
+ (cond (center (recenter (+ (/ (- (window-height) 1 lines)
+ 2)
+ (slime-count-lines start pos))))
+ (t (recenter (+ (- (window-height) 1 lines)
+ (slime-count-lines start pos))))))
+ (t
+ (goto-char start)
+ (recenter 0)
+ (cond ((pos-visible-in-window-p pos)
+ (goto-char pos))
+ (t
+ (goto-char start)
+ (next-line (- (window-height) 2))))))))
+
+;; not sure yet, whether this is a good idea.
+(defmacro slime-save-coordinates (origin &rest body)
+ "Restore line and column relative to ORIGIN, after executing BODY.
+
+This is useful if BODY deletes and inserts some text but we want to
+preserve the current row and column as closely as possible."
+ (let ((base (make-symbol "base"))
+ (goal (make-symbol "goal"))
+ (mark (make-symbol "mark")))
+ `(let* ((,base ,origin)
+ (,goal (slime-coordinates ,base))
+ (,mark (point-marker)))
+ (set-marker-insertion-type ,mark t)
+ (prog1 (save-excursion , at body)
+ (slime-restore-coordinate ,base ,goal ,mark)))))
+
+(put 'slime-save-coordinates 'lisp-indent-function 1)
+
+(defun slime-coordinates (origin)
+ ;; Return a pair (X . Y) for the column and line distance to ORIGIN.
+ (let ((y (slime-count-lines origin (point)))
+ (x (save-excursion
+ (- (current-column)
+ (progn (goto-char origin) (current-column))))))
+ (cons x y)))
+
+(defun slime-restore-coordinate (base goal limit)
+ ;; Move point to GOAL. Coordinates are relative to BASE.
+ ;; Don't move beyond LIMIT.
+ (save-restriction
+ (narrow-to-region base limit)
+ (goto-char (point-min))
+ (let ((col (current-column)))
+ (forward-line (cdr goal))
+ (when (and (eobp) (bolp) (not (bobp)))
+ (backward-char))
+ (move-to-column (+ col (car goal))))))
+
+(defun slime-count-lines (start end)
+ "Return the number of lines between START and END.
+This is 0 if START and END at the same line."
+ (- (count-lines start end)
+ (if (save-excursion (goto-char end) (bolp)) 0 1)))
+
+
+;;;;; SLDB commands
+
+(defun sldb-default-action ()
+ "Invoke the action at point."
+ (interactive)
+ (let ((fn (get-text-property (point) 'sldb-default-action)))
+ (if fn (funcall fn))))
+
+(defun sldb-default-action/mouse (event)
+ "Invoke the action pointed at by the mouse."
+ (interactive "e")
+ (destructuring-bind (mouse-1 (w pos &rest _)) event
+ (save-excursion
+ (goto-char pos)
+ (let ((fn (get-text-property (point) 'sldb-default-action)))
+ (if fn (funcall fn))))))
+
+(defun sldb-end-of-backtrace ()
+ "Fetch the entire backtrace and go to the last frame."
+ (interactive)
+ (sldb-fetch-all-frames)
+ (sldb-goto-last-frame))
+
+(defun sldb-fetch-all-frames ()
+ (let ((inhibit-read-only t)
+ (inhibit-point-motion-hooks t))
+ (sldb-goto-last-frame)
+ (let ((last (sldb-frame-number-at-point)))
+ (goto-char (next-single-char-property-change (point) 'frame))
+ (delete-region (point) (point-max))
+ (save-excursion
+ (sldb-insert-frames (slime-eval `(swank:backtrace ,(1+ last) nil))
+ nil)))))
+
+
+;;;;;; SLDB show source
+
+(defvar sldb-overlays '()
+ "List of overlays created in source code buffers to highlight expressions.")
+
+(defun sldb-show-source ()
+ "Highlight the frame at point's expression in a source code buffer."
+ (interactive)
+ (sldb-show-frame-source (sldb-frame-number-at-point)))
+
+(defun sldb-show-frame-source (frame-number)
+ (sldb-delete-overlays)
+ (slime-eval-async
+ `(swank:frame-source-location-for-emacs ,frame-number)
+ (lambda (source-location)
+ (destructure-case source-location
+ ((:error message)
+ (message "%s" message)
+ (ding))
+ (t
+ (slime-show-source-location source-location))))))
+
+(defun slime-show-source-location (source-location &optional no-highlight-p)
+ (slime-goto-source-location source-location)
+ (unless no-highlight-p (sldb-highlight-sexp))
+ (slime-show-buffer-position (point)))
+
+(defun sldb-highlight-sexp (&optional start end)
+ "Highlight the first sexp after point."
+ (sldb-delete-overlays)
+ (let ((start (or start (point)))
+ (end (or end (save-excursion (ignore-errors (forward-sexp)) (point)))))
+ (push (make-overlay start (1+ start)) sldb-overlays)
+ (push (make-overlay (1- end) end) sldb-overlays))
+ (dolist (overlay sldb-overlays)
+ (overlay-put overlay 'face 'secondary-selection)))
+
+(defun sldb-delete-overlays ()
+ (mapc #'delete-overlay sldb-overlays)
+ (setq sldb-overlays '()))
+
+
+;;;;;; SLDB toggle details
+
+(defun sldb-toggle-details (&optional on)
+ "Toggle display of details for the current frame.
+The details include local variable bindings and CATCH-tags."
+ (interactive)
+ (assert (sldb-frame-number-at-point))
+ (let ((inhibit-read-only t))
+ (if (or on (not (sldb-frame-details-visible-p)))
+ (sldb-show-frame-details)
+ (sldb-hide-frame-details))))
+
+(defun sldb-show-frame-details ()
+ ;; fetch and display info about local variables and catch tags
+ (destructuring-bind (start end frame locals catches) (sldb-frame-details)
+ (slime-save-coordinates start
+ (delete-region start end)
+ (slime-propertize-region `(frame ,frame details-visible-p t)
+ (sldb-insert-frame frame 'sldb-detailed-frame-line-face)
+ (let ((indent1 " ")
+ (indent2 " "))
+ (insert indent1 (in-sldb-face section
+ (if locals "Locals:" "[No Locals]")) "\n")
+ (sldb-insert-locals locals indent2 frame)
+ (when catches
+ (insert indent1 (in-sldb-face section "Catch-tags:") "\n")
+ (dolist (tag catches)
+ (slime-propertize-region `(catch-tag ,tag)
+ (insert indent2 (in-sldb-face catch-tag (format "%s" tag))
+ "\n"))))
+ (setq end (point)))))
+ (sldb-recenter-region start end)))
+
+(defun sldb-frame-details ()
+ ;; Return a list (START END FRAME LOCALS CATCHES) for frame at point.
+ (let* ((frame (get-text-property (point) 'frame))
+ (num (car frame))
+ (catches (sldb-catch-tags num))
+ (locals (sldb-frame-locals num)))
+ (destructuring-bind (start end) (sldb-frame-region)
+ (list start end frame locals catches))))
+
+(defun sldb-insert-locals (vars prefix frame)
+ "Insert VARS and add PREFIX at the beginning of each inserted line.
+VAR should be a plist with the keys :name, :id, and :value."
+ (loop for i from 0
+ for var in vars do
+ (destructuring-bind (&key name id value) var
+ (slime-propertize-region (list 'sldb-default-action 'sldb-inspect-var
+ 'var i)
+ (insert prefix
+ (in-sldb-face local-name
+ (concat name (if (zerop id) "" (format "#%d" id))))
+ " = ")
+ (insert (in-sldb-face local-value value) "\n")))))
+
+(defun sldb-hide-frame-details ()
+ ;; delete locals and catch tags, but keep the function name and args.
+ (destructuring-bind (start end) (sldb-frame-region)
+ (let ((frame (get-text-property (point) 'frame)))
+ (slime-save-coordinates start
+ (delete-region start end)
+ (slime-propertize-region '(details-visible-p nil)
+ (sldb-insert-frame frame))))))
+
+(defun sldb-disassemble ()
+ "Disassemble the code for the current frame."
+ (interactive)
+ (let ((frame (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:sldb-disassemble ,frame)
+ (lambda (result)
+ (slime-show-description result nil)))))
+
+(defun sldb-print-condition ()
+ "Print the condition SLDB is handling in the REPL.
+This way you can still see what the error was after exiting SLDB."
+ (interactive)
+ (unless sldb-condition
+ (error "No condition known (wrong buffer?)"))
+ (slime-write-string (format "%s\n%s\n"
+ (first sldb-condition)
+ (second sldb-condition))))
+
+(defun sldb-frame-locals (frame)
+ (slime-eval `(swank:frame-locals-for-emacs ,frame)))
+
+(defun sldb-catch-tags (frame)
+ (slime-eval `(swank:frame-catch-tags-for-emacs ,frame)))
+
+
+;;;;;; SLDB eval and inspect
+
+(defun sldb-eval-in-frame (string)
+ "Prompt for an expression and evaluate it in the selected frame."
+ (interactive (list (slime-read-from-minibuffer "Eval in frame: ")))
+ (let* ((number (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:eval-string-in-frame ,string ,number)
+ (if current-prefix-arg
+ 'slime-write-string
+ 'slime-display-eval-result))))
+
+(defun sldb-pprint-eval-in-frame (string)
+ "Prompt for an expression, evaluate in selected frame, pretty-print result."
+ (interactive (list (slime-read-from-minibuffer "Eval in frame: ")))
+ (let* ((number (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:pprint-eval-string-in-frame ,string ,number)
+ (lambda (result)
+ (slime-show-description result nil)))))
+
+
+
+(defun sldb-inspect-in-frame (string)
+ "Prompt for an expression and inspect it in the selected frame."
+ (interactive (list (slime-read-from-minibuffer
+ "Inspect in frame (evaluated): "
+ (slime-sexp-at-point))))
+ (let ((number (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:inspect-in-frame ,string ,number)
+ 'slime-open-inspector)))
+
+(defun sldb-inspect-var ()
+ (let ((frame (sldb-frame-number-at-point))
+ (var (sldb-var-number-at-point)))
+ (slime-eval-async `(swank:inspect-frame-var ,frame ,var)
+ 'slime-open-inspector)))
+
+(defun sldb-inspect-condition ()
+ "Inspect the current debugger condition."
+ (interactive)
+ (slime-eval-async '(swank:inspect-current-condition)
+ 'slime-open-inspector))
+
+
+;;;;;; SLDB movement
+
+(defun sldb-down ()
+ "Select next frame."
+ (interactive)
+ (sldb-forward-frame))
+
+(defun sldb-up ()
+ "Select previous frame."
+ (interactive)
+ (sldb-backward-frame)
+ (when (= (point) sldb-backtrace-start-marker)
+ (recenter (1+ (count-lines (point-min) (point))))))
+
+(defun sldb-sugar-move (move-fn)
+ (let ((inhibit-read-only t))
+ (when (sldb-frame-details-visible-p) (sldb-hide-frame-details))
+ (funcall move-fn)
+ (sldb-show-source)
+ (sldb-toggle-details t)))
+
+(defun sldb-details-up ()
+ "Select previous frame and show details."
+ (interactive)
+ (sldb-sugar-move 'sldb-up))
+
+(defun sldb-details-down ()
+ "Select next frame and show details."
+ (interactive)
+ (sldb-sugar-move 'sldb-down))
+
+
+;;;;;; SLDB restarts
+
+(defun sldb-quit ()
+ "Quit to toplevel."
+ (interactive)
+ (slime-rex () ('(swank:throw-to-toplevel))
+ ((:ok _) (error "sldb-quit returned"))
+ ((:abort))))
+
+(defun sldb-continue ()
+ "Invoke the \"continue\" restart."
+ (interactive)
+ (slime-rex ()
+ ('(swank:sldb-continue))
+ ((:ok _)
+ (message "No restart named continue")
+ (ding))
+ ((:abort))))
+
+(defun sldb-abort ()
+ "Invoke the \"abort\" restart."
+ (interactive)
+ (slime-eval-async '(swank:sldb-abort)
+ (lambda (v) (message "Restart returned: %S" v))))
+
+(defun sldb-invoke-restart (&optional number)
+ "Invoke a restart.
+Optional NUMBER specifies the restart to invoke, otherwise
+use the restart at point."
+ (interactive)
+ (let ((restart (or number (sldb-restart-at-point))))
+ (slime-rex ()
+ ((list 'swank:invoke-nth-restart-for-emacs sldb-level restart))
+ ((:ok value) (message "Restart returned: %s" value))
+ ((:abort)))))
+
+(defun sldb-break-with-default-debugger ()
+ "Enter default debugger."
+ (interactive)
+ (slime-rex ()
+ ('(swank:sldb-break-with-default-debugger) nil slime-current-thread)
+ ((:abort))))
+
+(defun sldb-step ()
+ "Select the \"continue\" restart and set a new break point."
+ (interactive)
+ (let ((frame (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:sldb-step ,frame))))
+
+(defun sldb-next ()
+ "Select the \"continue\" restart and set a new break point."
+ (interactive)
+ (let ((frame (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:sldb-next ,frame))))
+
+(defun sldb-out ()
+ "Select the \"continue\" restart and set a new break point."
+ (interactive)
+ (let ((frame (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:sldb-out ,frame))))
+
+(defun sldb-break-on-return ()
+ "Set a breakpoint at the current frame.
+The debugger is entered when the frame exits."
+ (interactive)
+ (let ((frame (sldb-frame-number-at-point)))
+ (slime-eval-async `(swank:sldb-break-on-return ,frame)
+ (lambda (msg) (message "%s" msg)))))
+
+(defun sldb-break (name)
+ "Set a breakpoint at the start of the function NAME."
+ (interactive (list (slime-read-symbol-name "Function: " t)))
+ (slime-eval-async `(swank:sldb-break ,name)
+ (lambda (msg) (message "%s" msg))))
+
+(defun sldb-return-from-frame (string)
+ "Reads an expression in the minibuffer and causes the function to
+return that value, evaluated in the context of the frame."
+ (interactive (list (slime-read-from-minibuffer "Return from frame: ")))
+ (let* ((number (sldb-frame-number-at-point)))
+ (slime-rex ()
+ ((list 'swank:sldb-return-from-frame number string))
+ ((:ok value) (message "%s" value))
+ ((:abort)))))
+
+(defun sldb-restart-frame ()
+ "Causes the frame to restart execution with the same arguments as it
+was called originally."
+ (interactive)
+ (let* ((number (sldb-frame-number-at-point)))
+ (slime-rex ()
+ ((list 'swank:restart-frame number))
+ ((:ok value) (message "%s" value))
+ ((:abort)))))
+
+
+;;;; Thread control panel
+
+(defun slime-list-threads ()
+ "Display a list of threads."
+ (interactive)
+ (let ((threads (slime-eval '(swank:list-threads))))
+ (with-current-buffer (get-buffer-create "*slime-threads*")
+ (slime-thread-control-mode)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (loop for idx from 0
+ for (name status id) in threads
+ do (slime-thread-insert idx name status id))
+ (goto-char (point-min))
+ (setq buffer-read-only t)
+ (pop-to-buffer (current-buffer))))))
+
+(defun slime-thread-insert (idx name summary id)
+ (slime-propertize-region `(thread-id ,idx)
+ (insert (format "%3s: " id))
+ (slime-insert-propertized '(face bold) name)
+ (insert-char ?\ (- 30 (current-column)))
+ (let ((summary-start (point)))
+ (insert " " summary)
+ (unless (bolp) (insert "\n"))
+ (indent-rigidly summary-start (point) 2))))
+
+
+;;;;; Major mode
+
+(define-derived-mode slime-thread-control-mode fundamental-mode
+ "thread-control"
+ "SLIME Thread Control Panel Mode.
+
+\\{slime-thread-control-mode-map}"
+ (when slime-truncate-lines
+ (set (make-local-variable 'truncate-lines) t)))
+
+(slime-define-keys slime-thread-control-mode-map
+ ("a" 'slime-thread-attach)
+ ("d" 'slime-thread-debug)
+ ("g" 'slime-list-threads)
+ ("k" 'slime-thread-kill)
+ ("q" 'slime-thread-quit))
+
+(defun slime-thread-quit ()
+ (interactive)
+ (slime-eval-async `(swank:quit-thread-browser))
+ (kill-buffer (current-buffer)))
+
+(defun slime-thread-kill ()
+ (interactive)
+ (let ((id (get-text-property (point) 'thread-id)))
+ (slime-eval `(swank:kill-nth-thread ,id)))
+ (call-interactively 'slime-list-threads))
+
+(defun slime-thread-attach ()
+ (interactive)
+ (let ((id (get-text-property (point) 'thread-id))
+ (file (slime-swank-port-file)))
+ (slime-eval-async `(swank:start-swank-server-in-thread ,id ,file)))
+ (slime-read-port-and-connect nil nil))
+
+(defun slime-thread-debug ()
+ (interactive)
+ (let ((id (get-text-property (point) 'thread-id)))
+ (slime-eval-async `(swank:debug-nth-thread ,id))))
+
+
+;;;;; Connection listing
+
+(define-derived-mode slime-connection-list-mode fundamental-mode
+ "connection-list"
+ "SLIME Connection List Mode.
+
+\\{slime-connection-list-mode-map}"
+ (when slime-truncate-lines
+ (set (make-local-variable 'truncate-lines) t)))
+
+(slime-define-keys slime-connection-list-mode-map
+ ((kbd "RET") 'slime-goto-connection)
+ ([return] 'slime-goto-connection)
+ ("d" 'slime-connection-list-make-default)
+ ("g" 'slime-update-connection-list)
+ ((kbd "C-k") 'slime-quit-connection-at-point)
+ ("R" 'slime-restart-connection-at-point))
+
+(defun slime-connection-at-point ()
+ (or (get-text-property (point) 'slime-connection)
+ (error "No connection at point")))
+
+(defun slime-goto-connection ()
+ "Switch to the REPL buffer for the connection at point."
+ (interactive)
+ (let ((slime-dispatching-connection (slime-connection-at-point)))
+ (switch-to-buffer (slime-output-buffer))))
+
+(defun slime-quit-connection-at-point (connection)
+ (interactive (list (slime-connection-at-point)))
+ (let ((slime-dispatching-connection connection))
+ (slime-quit-lisp)
+ (while (memq connection slime-net-processes)
+ (sit-for 0 100)))
+ (slime-update-connection-list))
+
+(defun slime-restart-connection-at-point (connection)
+ (interactive (list (slime-connection-at-point)))
+ (let ((slime-dispatching-connection connection))
+ (slime-restart-inferior-lisp)))
+
+(defun slime-connection-list-make-default ()
+ "Make the connection at point the default connection."
+ (interactive)
+ (slime-select-connection (slime-connection-at-point))
+ (slime-update-connection-list))
+
+(defun slime-list-connections ()
+ "Display a list of all connections."
+ (interactive)
+ (when (get-buffer "*SLIME connections*")
+ (kill-buffer "*SLIME connections*"))
+ (with-current-buffer
+ (slime-get-temp-buffer-create "*SLIME connections*"
+ :mode 'slime-connection-list-mode)
+ (slime-draw-connection-list)
+ (setq buffer-read-only t)
+ (pop-to-buffer (current-buffer))))
+
+(defun slime-update-connection-list ()
+ "Display a list of all connections."
+ (interactive)
+ (let ((pos (point))
+ (inhibit-read-only t))
+ (erase-buffer)
+ (slime-draw-connection-list)
+ (goto-char pos)))
+
+(defun slime-draw-connection-list ()
+ (let ((default-pos nil)
+ (default slime-default-connection)
+ (fstring "%s%2s %-10s %-17s %-7s %-s\n"))
+ (insert (format fstring " " "Nr" "Name" "Port" "Pid" "Type")
+ (format fstring " " "--" "----" "----" "---" "----"))
+ (dolist (p (reverse slime-net-processes))
+ (when (eq default p) (setf default-pos (point)))
+ (slime-insert-propertized
+ (list 'slime-connection p)
+ (format fstring
+ (if (eq default p) "*" " ")
+ (slime-connection-number p)
+ (slime-connection-name p)
+ (or (process-id p) (process-contact p))
+ (slime-pid p)
+ (slime-lisp-implementation-type p))))
+ (when default
+ (goto-char default-pos))))
+
+
+;;;; Inspector
+
+(defgroup slime-inspector nil
+ "Inspector faces."
+ :prefix "slime-inspector-"
+ :group 'slime)
+
+(defface slime-inspector-topline-face
+ '((t ()))
+ "Face for top line describing object."
+ :group 'slime-inspector)
+
+(defface slime-inspector-label-face
+ '((t (:inherit font-lock-constant-face)))
+ "Face for labels in the inspector."
+ :group 'slime-inspector)
+
+(defface slime-inspector-value-face
+ (if (slime-face-inheritance-possible-p)
+ '((t (:inherit font-lock-builtin-face)))
+ '((((background light)) (:foreground "MediumBlue" :bold t))
+ (((background dark)) (:foreground "LightGray" :bold t))))
+ "Face for things which can themselves be inspected."
+ :group 'slime-inspector)
+
+(defface slime-inspector-action-face
+ (if (slime-face-inheritance-possible-p)
+ '((t (:inherit font-lock-warning-face)))
+ '((t (:foreground "OrangeRed"))))
+ "Face for labels of inspector actions."
+ :group 'slime-inspector)
+
+(defface slime-inspector-type-face
+ '((t (:inherit font-lock-type-face)))
+ "Face for type description in inspector."
+ :group 'slime-inspector)
+
+(defvar slime-inspector-mark-stack '())
+(defvar slime-saved-window-config)
+
+(defun slime-inspect (string)
+ "Eval an expression and inspect the result."
+ (interactive
+ (list (slime-read-from-minibuffer "Inspect value (evaluated): "
+ (slime-sexp-at-point))))
+ (slime-eval-async `(swank:init-inspector ,string) 'slime-open-inspector))
+
+(define-derived-mode slime-inspector-mode fundamental-mode "Slime-Inspector"
+ (set-syntax-table lisp-mode-syntax-table)
+ (slime-set-truncate-lines)
+ (setq buffer-read-only t))
+
+(defun slime-inspector-buffer ()
+ (or (get-buffer "*Slime Inspector*")
+ (with-current-buffer (get-buffer-create "*Slime Inspector*")
+ (setq slime-inspector-mark-stack '())
+ (buffer-disable-undo)
+ (slime-mode t)
+ (slime-inspector-mode)
+ (make-local-variable 'slime-saved-window-config)
+ (setq slime-saved-window-config (current-window-configuration))
+ (current-buffer))))
+
+(defmacro slime-inspector-fontify (face string)
+ `(slime-add-face ',(intern (format "slime-inspector-%s-face" face)) ,string))
+
+(defun slime-open-inspector (inspected-parts &optional point)
+ "Display INSPECTED-PARTS in a new inspector window.
+Optionally set point to POINT."
+ (with-current-buffer (slime-inspector-buffer)
+ (setq slime-buffer-connection (slime-current-connection))
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (destructuring-bind (&key id title content) inspected-parts
+ (macrolet ((fontify (face string)
+ `(slime-inspector-fontify ,face ,string)))
+ (slime-propertize-region
+ (list 'slime-part-number id
+ 'mouse-face 'highlight
+ 'face 'slime-inspector-value-face)
+ (insert title))
+ (while (eq (char-before) ?\n)
+ (backward-delete-char 1))
+ (insert "\n" (fontify label "--------------------") "\n")
+ (save-excursion
+ (mapc #'slime-inspector-insert-ispec content))
+ (pop-to-buffer (current-buffer))
+ (when point
+ (check-type point cons)
+ (ignore-errors
+ (goto-line (car point))
+ (move-to-column (cdr point)))))))))
+
+(defun slime-inspector-insert-ispec (ispec)
+ (if (stringp ispec)
+ (insert ispec)
+ (destructure-case ispec
+ ((:value string id)
+ (slime-propertize-region
+ (list 'slime-part-number id
+ 'mouse-face 'highlight
+ 'face 'slime-inspector-value-face)
+ (insert string)))
+ ((:action string id)
+ (slime-insert-propertized (list 'slime-action-number id
+ 'mouse-face 'highlight
+ 'face 'slime-inspector-action-face)
+ string)))))
+
+(defun slime-inspector-position ()
+ "Return a pair (Y-POSITION X-POSITION) representing the
+position of point in the current buffer."
+ ;; We make sure we return absolute coordinates even if the user has
+ ;; narrowed the buffer.
+ (save-restriction
+ (widen)
+ (cons (cond ((fboundp 'line-number)
+ (line-number)) ; XEmacs
+ ((fboundp 'line-number-at-pos)
+ (line-number-at-pos)) ; Recent GNU Emacs
+ (t (1+ (count-lines 1 (point-at-bol)))))
+ (current-column))))
+
+(defun slime-inspector-operate-on-point ()
+ "If point is on a value then recursivly call the inspector on
+ that value. If point is on an action then call that action."
+ (interactive)
+ (let ((part-number (get-text-property (point) 'slime-part-number))
+ (action-number (get-text-property (point) 'slime-action-number))
+ (opener (lexical-let ((point (slime-inspector-position)))
+ (lambda (parts)
+ (when parts
+ (slime-open-inspector parts point))))))
+ (cond (part-number
+ (slime-eval-async `(swank:inspect-nth-part ,part-number)
+ opener)
+ (push (slime-inspector-position) slime-inspector-mark-stack))
+ (action-number
+ (slime-eval-async `(swank::inspector-call-nth-action ,action-number)
+ opener)))))
+
+(defun slime-inspector-operate-on-click (event)
+ "Inspect the value at the clicked-at position or invoke an action."
+ (interactive "@e")
+ (let ((point (posn-point (event-end event))))
+ (cond ((and point
+ (or (get-text-property point 'slime-part-number)
+ (get-text-property point 'slime-action-number)))
+ (goto-char point)
+ (slime-inspector-operate-on-point))
+ (t
+ (error "No clickable part here")))))
+
+(defun slime-inspector-copy-down (number)
+ "Evaluate the slot at point via the REPL (to set `*')."
+ (interactive (list (or (get-text-property (point) 'slime-part-number)
+ (error "No part at point"))))
+ (slime-repl-send-string (format "%s" `(swank:inspector-nth-part ,number)))
+ (slime-repl))
+
+(defun slime-inspector-pop ()
+ (interactive)
+ (slime-eval-async
+ `(swank:inspector-pop)
+ (lambda (result)
+ (cond (result
+ (slime-open-inspector result (pop slime-inspector-mark-stack)))
+ (t
+ (message "No previous object")
+ (ding))))))
+
+(defun slime-inspector-next ()
+ (interactive)
+ (let ((result (slime-eval `(swank:inspector-next))))
+ (cond (result
+ (push (slime-inspector-position) slime-inspector-mark-stack)
+ (slime-open-inspector result))
+ (t (message "No next object")
+ (ding)))))
+
+(defun slime-inspector-quit ()
+ (interactive)
+ (slime-eval-async `(swank:quit-inspector))
+ (set-window-configuration slime-saved-window-config)
+ (kill-buffer (current-buffer)))
+
+(defun slime-find-inspectable-object (direction limit)
+ "Finds the next or previous inspectable object within the
+current buffer, depending on whether DIRECTION is 'NEXT or
+'PREV. LIMIT is the maximum or minimum position in the current
+buffer.
+
+Returns a list of two values: If an object could be found, the
+starting position of the found object and T is returned;
+otherwise LIMIT and NIL is returned.
+"
+ (let ((finder (ecase direction
+ (next 'next-single-property-change)
+ (prev 'previous-single-property-change))))
+ (let ((prop nil) (curpos (point)))
+ (while (and (not prop) (not (= curpos limit)))
+ (let ((newpos (funcall finder curpos 'slime-part-number nil limit)))
+ (setq prop (get-text-property newpos 'slime-part-number))
+ (setq curpos newpos)))
+ (list curpos (and prop t)))))
+
+(defun slime-inspector-next-inspectable-object (arg)
+ "Move point to the next inspectable object.
+With optional ARG, move across that many objects.
+If ARG is negative, move backwards."
+ (interactive "p")
+ (let ((maxpos (point-max)) (minpos (point-min))
+ (previously-wrapped-p nil))
+ ;; Forward.
+ (while (> arg 0)
+ (destructuring-bind (pos foundp)
+ (slime-find-inspectable-object 'next maxpos)
+ (if foundp
+ (progn (goto-char pos) (setq arg (1- arg))
+ (setq previously-wrapped-p nil))
+ (if (not previously-wrapped-p) ; cycle detection
+ (progn (goto-char minpos) (setq previously-wrapped-p t))
+ (error "No inspectable objects")))))
+ ;; Backward.
+ (while (< arg 0)
+ (destructuring-bind (pos foundp)
+ (slime-find-inspectable-object 'prev minpos)
+ ;; SLIME-OPEN-INSPECTOR inserts the title of an inspector page
+ ;; as a presentation at the beginning of the buffer; skip
+ ;; that. (Notice how this problem can not arise in ``Forward.'')
+ (if (and foundp (/= pos minpos))
+ (progn (goto-char pos) (setq arg (1+ arg))
+ (setq previously-wrapped-p nil))
+ (if (not previously-wrapped-p) ; cycle detection
+ (progn (goto-char maxpos) (setq previously-wrapped-p t))
+ (error "No inspectable objects")))))))
+
+
+(defun slime-inspector-previous-inspectable-object (arg)
+ "Move point to the previous inspectable object.
+With optional ARG, move across that many objects.
+If ARG is negative, move forwards."
+ (interactive "p")
+ (slime-inspector-next-inspectable-object (- arg)))
+
+(defun slime-inspector-describe ()
+ (interactive)
+ (slime-eval-describe `(swank:describe-inspectee)))
+
+(defun slime-inspector-pprint (part)
+ (interactive (list (or (get-text-property (point) 'slime-part-number)
+ (error "No part at point"))))
+ (slime-eval-describe `(swank:pprint-inspector-part ,part)))
+
+(defun slime-inspector-reinspect ()
+ (interactive)
+ (slime-eval-async `(swank:inspector-reinspect)
+ (lexical-let ((point (slime-inspector-position)))
+ (lambda (parts)
+ (slime-open-inspector parts point)))))
+
+(slime-define-keys slime-inspector-mode-map
+ ([return] 'slime-inspector-operate-on-point)
+ ((kbd "M-RET") 'slime-inspector-copy-down)
+ ("\C-m" 'slime-inspector-operate-on-point)
+ ([mouse-2] 'slime-inspector-operate-on-click)
+ ("l" 'slime-inspector-pop)
+ ("n" 'slime-inspector-next)
+ (" " 'slime-inspector-next)
+ ("d" 'slime-inspector-describe)
+ ("p" 'slime-inspector-pprint)
+ ("q" 'slime-inspector-quit)
+ ("g" 'slime-inspector-reinspect)
+ ("\C-i" 'slime-inspector-next-inspectable-object)
+ ([(shift tab)] 'slime-inspector-previous-inspectable-object) ; Emacs translates S-TAB
+ ([backtab] 'slime-inspector-previous-inspectable-object) ; to BACKTAB on X.
+ ("\M-." 'slime-edit-definition))
+
+
+;;;; Buffer selector
+
+(defvar slime-selector-methods nil
+ "List of buffer-selection methods for the `slime-select' command.
+Each element is a list (KEY DESCRIPTION FUNCTION).
+DESCRIPTION is a one-line description of what the key selects.")
+
+(defun slime-selector ()
+ "Select a new buffer by type, indicated by a single character.
+The user is prompted for a single character indicating the method by
+which to choose a new buffer. The `?' character describes the
+available methods.
+
+See `def-slime-selector-method' for defining new methods."
+ (interactive)
+ (message "Select [%s]: "
+ (apply #'string (mapcar #'car slime-selector-methods)))
+ (let* ((ch (save-window-excursion
+ (select-window (minibuffer-window))
+ (read-char)))
+ (method (find ch slime-selector-methods :key #'car)))
+ (cond ((null method)
+ (message "No method for character: ?\\%c" ch)
+ (ding)
+ (sleep-for 1)
+ (discard-input)
+ (slime-selector))
+ (t
+ (funcall (third method))))))
+
+(defmacro def-slime-selector-method (key description &rest body)
+ "Define a new `slime-select' buffer selection method.
+
+KEY is the key the user will enter to choose this method.
+
+DESCRIPTION is a one-line sentence describing how the method
+selects a buffer.
+
+BODY is a series of forms which are evaluated when the selector
+is chosen. The returned buffer is selected with
+switch-to-buffer."
+ `(setq slime-selector-methods
+ (sort* (cons (list ,key ,description
+ (lambda ()
+ (let ((buffer (progn , at body)))
+ (cond ((get-buffer buffer)
+ (switch-to-buffer buffer))
+ (t
+ (message "No such buffer: %S" buffer)
+ (ding))))))
+ (remove* ,key slime-selector-methods :key #'car))
+ #'< :key #'car)))
+
+(def-slime-selector-method ?? "Selector help buffer."
+ (ignore-errors (kill-buffer "*Select Help*"))
+ (with-current-buffer (get-buffer-create "*Select Help*")
+ (insert "Select Methods:\n\n")
+ (loop for (key line function) in slime-selector-methods
+ do (insert (format "%c:\t%s\n" key line)))
+ (help-mode)
+ (display-buffer (current-buffer) t)
+ (shrink-window-if-larger-than-buffer
+ (get-buffer-window (current-buffer))))
+ (slime-selector)
+ (current-buffer))
+
+(def-slime-selector-method ?r
+ "SLIME Read-Eval-Print-Loop."
+ (cond ((slime-current-connection)
+ (slime-output-buffer))
+ ((y-or-n-p "No connection: start Slime? ")
+ (slime))))
+
+(def-slime-selector-method ?i
+ "*inferior-lisp* buffer."
+ (cond ((and (slime-connected-p) (slime-process))
+ (process-buffer (slime-process)))
+ (t
+ "*inferior-lisp*")))
+
+(def-slime-selector-method ?v
+ "*slime-events* buffer."
+ slime-event-buffer-name)
+
+(def-slime-selector-method ?l
+ "most recently visited lisp-mode buffer."
+ (slime-recently-visited-buffer 'lisp-mode))
+
+(def-slime-selector-method ?d
+ "*sldb* buffer for the current connection."
+ (or (sldb-get-default-buffer)
+ (error "No debugger buffer")))
+
+(def-slime-selector-method ?e
+ "most recently visited emacs-lisp-mode buffer."
+ (slime-recently-visited-buffer 'emacs-lisp-mode))
+
+(def-slime-selector-method ?c
+ "SLIME connections buffer."
+ (slime-list-connections)
+ "*SLIME connections*")
+
+(def-slime-selector-method ?t
+ "SLIME threads buffer."
+ (slime-list-threads)
+ "*slime-threads*")
+
+(defun slime-recently-visited-buffer (mode)
+ "Return the most recently visited buffer whose major-mode is MODE.
+Only considers buffers that are not already visible."
+ (loop for buffer in (buffer-list)
+ when (and (with-current-buffer buffer (eq major-mode mode))
+ (not (string-match "^ " (buffer-name buffer)))
+ (null (get-buffer-window buffer 'visible)))
+ return buffer
+ finally (error "Can't find unshown buffer in %S" mode)))
+
+
+;;;; Editing commands
+
+
+
+;;;; Font Lock
+
+(defcustom slime-highlight-suppressed-forms t
+ "Display forms disabled by reader conditionals as comments."
+ :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil))
+ :group 'slime-mode)
+
+(defface slime-reader-conditional-face
+ (if (slime-face-inheritance-possible-p)
+ '((t (:inherit font-lock-comment-face)))
+ '((((background light)) (:foreground "DimGray" :bold t))
+ (((background dark)) (:foreground "LightGray" :bold t))))
+ "Face for compiler notes while selected."
+ :group 'slime-mode-faces)
+
+(defun slime-search-suppressed-forms (limit)
+ "Find reader conditionalized forms where the test is false."
+ (when (and slime-highlight-suppressed-forms
+ (slime-connected-p)
+ (re-search-forward "^\\([^;\n]*?[ \t(]\\)?#[-+]" limit t))
+ (ignore-errors
+ (let* ((start (- (point) 2))
+ (char (char-before))
+ (e (read (current-buffer)))
+ (val (slime-eval-feature-conditional e)))
+ (when (<= (point) limit)
+ (if (or (and (eq char ?+) (not val))
+ (and (eq char ?-) val))
+ (progn
+ (forward-sexp) (backward-sexp)
+ (slime-forward-sexp)
+ (assert (<= (point) limit))
+ (let ((md (match-data)))
+ (fill md nil)
+ (setf (first md) start)
+ (setf (second md) (point))
+ (set-match-data md)
+ t))
+ (slime-search-suppressed-forms limit)))))))
+
+(defun slime-activate-font-lock-magic ()
+ (if (featurep 'xemacs)
+ (let ((pattern `((slime-search-suppressed-forms
+ (0 slime-reader-conditional-face t)))))
+ (dolist (sym '(lisp-font-lock-keywords
+ lisp-font-lock-keywords-1
+ lisp-font-lock-keywords-2))
+ (set sym (append (symbol-value sym) pattern))))
+ (font-lock-add-keywords
+ 'lisp-mode
+ `((slime-search-suppressed-forms 0 ,''slime-reader-conditional-face t)))))
+
+(when slime-highlight-suppressed-forms
+ (slime-activate-font-lock-magic))
+
+
+;;;; Indentation
+
+(defun slime-update-indentation ()
+ "Update indentation for all macros defined in the Lisp system."
+ (interactive)
+ (slime-eval-async '(swank:update-indentation-information)))
+
+(defvar slime-indentation-update-hooks)
+
+(defun slime-handle-indentation-update (alist)
+ "Update Lisp indent information.
+
+ALIST is a list of (SYMBOL-NAME . INDENT-SPEC) of proposed indentation
+settings for `common-lisp-indent-function'. The appropriate property
+is setup, unless the user already set one explicitly."
+ (dolist (info alist)
+ (let ((symbol (intern (car info)))
+ (indent (cdr info)))
+ ;; Does the symbol have an indentation value that we set?
+ (when (equal (get symbol 'common-lisp-indent-function)
+ (get symbol 'slime-indent))
+ (put symbol 'slime-indent indent)
+ (put symbol 'common-lisp-indent-function indent))
+ (run-hook-with-args 'slime-indentation-update-hooks symbol indent))))
+
+
+;;;; Contrib modules
+
+(defvar slime-required-modules '())
+
+(defun slime-require (module)
+ (assert (keywordp module))
+ (pushnew module slime-required-modules)
+ (when (slime-connected-p)
+ (slime-load-contribs)))
+
+(defun slime-load-contribs ()
+ (let ((needed (remove-if (lambda (s)
+ (member (subseq (symbol-name s) 1)
+ (mapcar #'downcase (slime-lisp-modules))))
+ slime-required-modules)))
+ (when needed
+ (slime-eval-async `(swank:swank-require ',needed)
+ (lambda (new-modules)
+ (setf (slime-lisp-modules) new-modules))))))
+
+
+;;;;; Pull-down menu
+
+(defvar slime-easy-menu
+ (let ((C '(slime-connected-p)))
+ `("SLIME"
+ [ "Edit Definition..." slime-edit-definition ,C ]
+ [ "Return From Definition" slime-pop-find-definition-stack ,C ]
+ [ "Complete Symbol" slime-complete-symbol ,C ]
+ [ "Show REPL" slime-switch-to-output-buffer ,C ]
+ "--"
+ ("Evaluation"
+ [ "Eval Defun" slime-eval-defun ,C ]
+ [ "Eval Last Expression" slime-eval-last-expression ,C ]
+ [ "Eval And Pretty-Print" slime-pprint-eval-last-expression ,C ]
+ [ "Eval Region" slime-eval-region ,C ]
+ [ "Interactive Eval..." slime-interactive-eval ,C ]
+ [ "Edit Lisp Value..." slime-edit-value ,C ]
+ [ "Call Defun" slime-call-defun ,C ])
+ ("Debugging"
+ [ "Macroexpand Once..." slime-macroexpand-1 ,C ]
+ [ "Macroexpand All..." slime-macroexpand-all ,C ]
+ [ "Create Trace Buffer" slime-redirect-trace-output ,C ]
+ [ "Toggle Trace..." slime-toggle-trace-fdefinition ,C ]
+ [ "Untrace All" slime-untrace-all ,C]
+ [ "Disassemble..." slime-disassemble-symbol ,C ]
+ [ "Inspect..." slime-inspect ,C ])
+ ("Compilation"
+ [ "Compile Defun" slime-compile-defun ,C ]
+ [ "Compile/Load File" slime-compile-and-load-file ,C ]
+ [ "Compile File" slime-compile-file ,C ]
+ [ "Compile Region" slime-compile-region ,C ]
+ "--"
+ [ "Next Note" slime-next-note t ]
+ [ "Previous Note" slime-previous-note t ]
+ [ "Remove Notes" slime-remove-notes t ]
+ [ "List Notes" slime-list-compiler-notes ,C ])
+ ("Cross Reference"
+ [ "Who Calls..." slime-who-calls ,C ]
+ [ "Who References... " slime-who-references ,C ]
+ [ "Who Sets..." slime-who-sets ,C ]
+ [ "Who Binds..." slime-who-binds ,C ]
+ [ "Who Macroexpands..." slime-who-macroexpands ,C ]
+ [ "Who Specializes..." slime-who-specializes ,C ]
+ [ "List Callers..." slime-list-callers ,C ]
+ [ "List Callees..." slime-list-callees ,C ]
+ [ "Next Location" slime-next-location t ])
+ ("Editing"
+ [ "Check Parens" check-parens t]
+ [ "Update Indentation" slime-update-indentation ,C]
+ [ "Select Buffer" slime-selector t])
+ ("Profiling"
+ [ "Toggle Profiling..." slime-toggle-profile-fdefinition ,C ]
+ [ "Profile Package" slime-profile-package ,C]
+ [ "Unprofile All" slime-unprofile-all ,C ]
+ [ "Show Profiled" slime-profiled-functions ,C ]
+ "--"
+ [ "Report" slime-profile-report ,C ]
+ [ "Reset Counters" slime-profile-reset ,C ])
+ ("Documentation"
+ [ "Describe Symbol..." slime-describe-symbol ,C ]
+ [ "Apropos..." slime-apropos ,C ]
+ [ "Apropos all..." slime-apropos-all ,C ]
+ [ "Apropos Package..." slime-apropos-package ,C ]
+ [ "Hyperspec..." slime-hyperspec-lookup t ])
+ "--"
+ [ "Interrupt Command" slime-interrupt ,C ]
+ [ "Abort Async. Command" slime-quit ,C ]
+ [ "Sync Package & Directory" slime-sync-package-and-default-directory ,C]
+ [ "Set Package in REPL" slime-repl-set-package ,C])))
+
+(defvar slime-repl-easy-menu
+ (let ((C '(slime-connected-p)))
+ `("REPL"
+ [ "Send Input" slime-repl-return ,C ]
+ [ "Close and Send Input " slime-repl-closing-return ,C ]
+ [ "Interrupt Lisp process" slime-interrupt ,C ]
+ "--"
+ [ "Previous Input" slime-repl-previous-input t ]
+ [ "Next Input" slime-repl-next-input t ]
+ [ "Goto Previous Prompt " slime-repl-previous-prompt t ]
+ [ "Goto Next Prompt " slime-repl-next-prompt t ]
+ [ "Clear Last Output" slime-repl-clear-output t ]
+ [ "Clear Buffer " slime-repl-clear-buffer t ]
+ [ "Kill Current Input" slime-repl-kill-input t ])))
+
+(defvar slime-sldb-easy-menu
+ (let ((C '(slime-connected-p)))
+ `("SLDB"
+ [ "Next Frame" sldb-down t ]
+ [ "Previous Frame" sldb-up t ]
+ [ "Toggle Frame Details" sldb-toggle-details t ]
+ [ "Next Frame (Details)" sldb-details-down t ]
+ [ "Previous Frame (Details)" sldb-details-up t ]
+ "--"
+ [ "Eval Expression..." slime-interactive-eval ,C ]
+ [ "Eval in Frame..." sldb-eval-in-frame ,C ]
+ [ "Eval in Frame (pretty print)..." sldb-pprint-eval-in-frame ,C ]
+ [ "Inspect In Frame..." sldb-inspect-in-frame ,C ]
+ [ "Inspect Condition Object" sldb-inspect-condition ,C ]
+ [ "Print Condition to REPL" sldb-print-condition t ]
+ "--"
+ [ "Restart Frame" sldb-restart-frame ,C ]
+ [ "Return from Frame..." sldb-return-from-frame ,C ]
+ ("Invoke Restart"
+ [ "Continue" sldb-continue ,C ]
+ [ "Abort" sldb-abort ,C ]
+ [ "Step" sldb-step ,C ]
+ [ "Step next" sldb-next ,C ]
+ [ "Step out" sldb-out ,C ]
+ )
+ "--"
+ [ "Quit (throw)" sldb-quit ,C ]
+ [ "Break With Default Debugger" sldb-break-with-default-debugger ,C ])))
+
+(easy-menu-define menubar-slime slime-mode-map "SLIME" slime-easy-menu)
+
+(defun slime-add-easy-menu ()
+ (easy-menu-add slime-easy-menu 'slime-mode-map))
+
+(add-hook 'slime-mode-hook 'slime-add-easy-menu)
+
+(defun slime-repl-add-easy-menu ()
+ (easy-menu-define menubar-slime-repl slime-repl-mode-map
+ "REPL" slime-repl-easy-menu)
+ (easy-menu-define menubar-slime slime-repl-mode-map
+ "SLIME" slime-easy-menu)
+ (easy-menu-add slime-repl-easy-menu 'slime-repl-mode-map))
+
+(add-hook 'slime-repl-mode-hook 'slime-repl-add-easy-menu)
+
+(defun slime-sldb-add-easy-menu ()
+ (easy-menu-define menubar-slime-sldb
+ sldb-mode-map "SLDB" slime-sldb-easy-menu)
+ (easy-menu-add slime-sldb-easy-menu 'sldb-mode-map))
+
+(add-hook 'sldb-mode-hook 'slime-sldb-add-easy-menu)
+
+
+;;;; Cheat Sheet
+
+(defvar slime-cheat-sheet-table
+ '((:title "Editing lisp code"
+ :map slime-mode-map
+ :bindings ((slime-eval-defun "Evaluate current top level form")
+ (slime-compile-defun "Compile current top level form")
+ (slime-interactive-eval "Prompt for form and eval it")
+ (slime-compile-and-load-file "Compile and load current file")
+ (slime-sync-package-and-default-directory "Synch default package and directory with current buffer")
+ (slime-next-note "Next compiler note")
+ (slime-previous-note "Previous compiler note")
+ (slime-remove-notes "Remove notes")
+ slime-hyperspec-lookup))
+ (:title "Completion"
+ :map slime-mode-map
+ :bindings (slime-indent-and-complete-symbol
+ slime-fuzzy-complete-symbol))
+ (:title "At the REPL"
+ :map slime-repl-mode-map
+ :bindings (slime-repl-clear-buffer
+ slime-describe-symbol))
+ (:title "Within SLDB buffers"
+ :map sldb-mode-map
+ :bindings ((sldb-default-action "Do 'whatever' with thing at point")
+ (sldb-toggle-details "Toggle frame details visualization")
+ (sldb-quit "Quit to REPL")
+ (sldb-abort "Invoke ABORT restart")
+ (sldb-continue "Invoke CONTINUE restart (if available)")
+ (sldb-show-source "Jump to frame's source code")
+ (sldb-eval-in-frame "Evaluate in frame at point")
+ (sldb-inspect-in-frame "Evaluate in frame at point and inspect result")))
+ (:title "Within the Inspector"
+ :map slime-inspector-mode-map
+ :bindings ((slime-inspector-next-inspectable-object "Jump to next inspectable object")
+ (slime-inspector-operate-on-point "Inspect object or execute action at point")
+ (slime-inspector-reinspect "Reinspect current object")
+ (slime-inspector-pop "Return to previous object")
+ (slime-inspector-copy-down "Send object at point to REPL")
+ (slime-inspector-quit "Quit")))
+ (:title "Finding Definitions"
+ :map slime-mode-map
+ :bindings (slime-edit-definition
+ slime-pop-find-definition-stack))))
+
+(defun slime-cheat-sheet ()
+ (interactive)
+ (switch-to-buffer-other-frame (get-buffer-create "*SLIME Cheat Sheet*"))
+ (setq buffer-read-only nil)
+ (delete-region (point-min) (point-max))
+ (goto-char (point-min))
+ (insert "SLIME: The Superior Lisp Interaction Mode for Emacs (minor-mode).\n\n")
+ (dolist (mode slime-cheat-sheet-table)
+ (let ((title (getf mode :title))
+ (mode-map (getf mode :map))
+ (mode-keys (getf mode :bindings)))
+ (insert title)
+ (insert ":\n")
+ (insert (make-string (1+ (length title)) ?-))
+ (insert "\n")
+ (let ((keys '())
+ (descriptions '()))
+ (dolist (func mode-keys)
+ ;; func is eithor the function name or a list (NAME DESCRIPTION)
+ (push (if (symbolp func)
+ (prin1-to-string func)
+ (second func))
+ descriptions)
+ (let ((all-bindings (where-is-internal (if (symbolp func)
+ func
+ (first func))
+ (symbol-value mode-map)))
+ (key-bindings '()))
+ (dolist (binding all-bindings)
+ (when (and (vectorp binding)
+ (integerp (aref binding 0)))
+ (push binding key-bindings)))
+ (push (mapconcat 'key-description key-bindings " or ") keys)))
+ (loop
+ with key-length = (apply 'max (mapcar 'length keys))
+ with desc-length = (apply 'max (mapcar 'length descriptions))
+ for key in (nreverse keys)
+ for desc in (nreverse descriptions)
+ do (insert desc)
+ do (insert (make-string (- desc-length (length desc)) ? ))
+ do (insert " => ")
+ do (insert (if (string= "" key)
+ "<not on any key>"
+ key))
+ do (insert "\n")
+ finally do (insert "\n")))))
+ (setq buffer-read-only t)
+ (goto-char (point-min)))
+
+
+;;;; Test suite
+
+(defstruct (slime-test (:conc-name slime-test.))
+ name fname args doc inputs fails-for)
+
+(defvar slime-tests '()
+ "Names of test functions.")
+
+(defvar slime-test-debug-on-error nil
+ "*When non-nil debug errors in test cases.")
+
+(defvar slime-total-tests nil
+ "Total number of tests executed during a test run.")
+
+(defvar slime-failed-tests nil
+ "Total number of failed tests during a test run.")
+
+(defvar slime-expected-failures nil
+ "Total number of expected failures during a test run")
+
+(defvar slime-test-buffer-name "*Tests*"
+ "The name of the buffer used to display test results.")
+
+
+;; dynamically bound during a single test
+(defvar slime-current-test)
+(defvar slime-unexpected-failures)
+
+
+;;;;; Execution engine
+
+(defun slime-run-tests ()
+ "Run the test suite.
+The results are presented in an outline-mode buffer, with the tests
+that succeeded initially folded away."
+ (interactive)
+ (assert (not (slime-busy-p)))
+ (slime-create-test-results-buffer)
+ (unwind-protect
+ (slime-execute-tests)
+ (pop-to-buffer slime-test-buffer-name)
+ (goto-char (point-min))
+ (hide-body)
+ ;; Expose failed tests
+ (dolist (o (overlays-in (point-min) (point-max)))
+ (when (overlay-get o 'slime-failed-test)
+ (goto-char (overlay-start o))
+ (show-subtree)))))
+
+(defun slime-run-one-test (name)
+ "Ask for the name of a test and then execute the test."
+ (interactive (list (slime-read-test-name)))
+ (let ((test (find name slime-tests :key #'slime-test.name)))
+ (assert test)
+ (let ((slime-tests (list test)))
+ (slime-run-tests))))
+
+(defun slime-read-test-name ()
+ (let ((alist (mapcar (lambda (test)
+ (list (symbol-name (slime-test.name test))))
+ slime-tests)))
+ (read (completing-read "Test: " alist nil t))))
+
+(defun slime-test-should-fail-p (test)
+ (member (slime-lisp-implementation-name)
+ (slime-test.fails-for test)))
+
+(defun slime-execute-tests ()
+ "Execute each test case with each input.
+Return the number of failed tests."
+ (save-window-excursion
+ (let ((slime-total-tests 0)
+ (slime-expected-passes 0)
+ (slime-unexpected-failures 0)
+ (slime-expected-failures 0))
+ (dolist (slime-current-test slime-tests)
+ (with-struct (slime-test. name (function fname) inputs)
+ slime-current-test
+ (slime-test-heading 1 "%s" name)
+ (dolist (input inputs)
+ (incf slime-total-tests)
+ (message "%s: %s" name input)
+ (slime-test-heading 2 "input: %s" input)
+ (if slime-test-debug-on-error
+ (let ((debug-on-error t)
+ (debug-on-quit t))
+ (apply function input))
+ (condition-case err
+ (apply function input)
+ (error
+ (cond ((slime-test-should-fail-p slime-current-test)
+ (incf slime-expected-failures)
+ (slime-test-failure "ERROR (expected)"
+ (format "%S" err)))
+ (t
+ (incf slime-unexpected-failures)
+ (slime-print-check-error err)))))))))
+ (let ((summary (cond ((and (zerop slime-expected-failures)
+ (zerop slime-unexpected-failures))
+ (format "All %S tests completed successfully."
+ slime-total-tests))
+ (t
+ (format "Failed on %S (%S expected) of %S tests."
+ (+ slime-expected-failures
+ slime-unexpected-failures)
+ slime-expected-failures
+ slime-total-tests)))))
+ (save-excursion
+ (with-current-buffer slime-test-buffer-name
+ (goto-char (point-min))
+ (insert summary "\n\n")))
+ (message "%s" summary)
+ slime-unexpected-failures))))
+
+(defun slime-batch-test (results-file)
+ "Run the test suite in batch-mode.
+Exits Emacs when finished. The exit code is the number of failed tests."
+ (let ((slime-test-debug-on-error nil))
+ (slime)
+ ;; Block until we are up and running.
+ (while (not (slime-connected-p))
+ (sit-for 1))
+ (slime-sync-to-top-level 5)
+ (switch-to-buffer "*scratch*")
+ (let ((failed-tests (slime-run-tests)))
+ (with-current-buffer slime-test-buffer-name
+ (slime-delete-hidden-outline-text)
+ (goto-char (point-min))
+ (insert "-*- outline -*-\n\n")
+ (write-file results-file))
+ (kill-emacs failed-tests))))
+
+
+;;;;; Results buffer creation and output
+
+(defun slime-create-test-results-buffer ()
+ "Create and initialize the buffer for test suite results."
+ (ignore-errors (kill-buffer slime-test-buffer-name))
+ (with-current-buffer (get-buffer-create slime-test-buffer-name)
+ (erase-buffer)
+ (outline-mode)
+ (set (make-local-variable 'outline-regexp) "\\*+")
+ (slime-set-truncate-lines)))
+
+(defun slime-delete-hidden-outline-text ()
+ "Delete the hidden parts of an outline-mode buffer."
+ (loop do (when (eq (get-char-property (point) 'invisible) 'outline)
+ (delete-region (point)
+ (next-single-char-property-change (point)
+ 'invisible)))
+ until (eobp)
+ do (goto-char (next-single-char-property-change (point) 'invisible))))
+
+(defun slime-test-heading (level format &rest args)
+ "Output a test suite heading.
+LEVEL gives the depth of nesting: 1 for top-level, 2 for a subheading, etc."
+ (with-current-buffer slime-test-buffer-name
+ (goto-char (point-max))
+ (insert (make-string level ?*)
+ " "
+ (apply 'format format args)
+ "\n")))
+
+(defun slime-test-failure (keyword string)
+ "Output a failure message from the test suite.
+KEYWORD names the type of failure and STRING describes the reason."
+ (with-current-buffer slime-test-buffer-name
+ (goto-char (point-max))
+ (let ((start (point)))
+ (insert keyword ": ")
+ (let ((overlay (make-overlay start (point))))
+ (overlay-put overlay 'slime-failed-test t)
+ (overlay-put overlay 'face 'bold)))
+ (insert string "\n")))
+
+(defun slime-test-message (string)
+ "Output a message from the test suite."
+ (with-current-buffer slime-test-buffer-name
+ (goto-char (point-max))
+ (insert string "\n")))
+
+
+;;;;; Macros for defining test cases
+
+(defmacro def-slime-test (name args doc inputs &rest body)
+ "Define a test case.
+NAME ::= SYMBOL | (SYMBOL (FAILS-FOR*)) is a symbol naming the test.
+ARGS is a lambda-list.
+DOC is a docstring.
+INPUTS is a list of argument lists, each tested separately.
+BODY is the test case. The body can use `slime-check' to test
+conditions (assertions)."
+ (multiple-value-bind (name fails-for) (etypecase name
+ (symbol (values name '()))
+ (cons name))
+ (let ((fname (intern (format "slime-test-%s" name))))
+ `(progn
+ (defun ,fname ,args
+ ,doc
+ (slime-sync)
+ , at body)
+ (setq slime-tests
+ (append (remove* ',name slime-tests :key 'slime-test.name)
+ (list (make-slime-test :name ',name :fname ',fname
+ :fails-for ',fails-for
+ :inputs ,inputs))))))))
+
+(defmacro slime-check (test-name &rest body)
+ "Check a condition (assertion.)
+TEST-NAME can be a symbol, a string, or a (FORMAT-STRING . ARGS) list.
+BODY returns true if the check succeeds."
+ (let ((check-name (gensym "check-name-")))
+ `(let ((,check-name ,(typecase test-name
+ (symbol (symbol-name test-name))
+ (string test-name)
+ (cons `(format , at test-name)))))
+ (if (progn , at body)
+ (slime-print-check-ok ,check-name)
+ (cond ((slime-test-should-fail-p slime-current-test)
+ (incf slime-expected-failures)
+ (slime-test-failure "FAIL (expected)" ,check-name))
+ (t
+ (incf slime-unexpected-failures)
+ (slime-print-check-failed ,check-name)))
+ (when slime-test-debug-on-error
+ (debug (format "Check failed: %S" ,check-name)))))))
+
+(defun slime-print-check-ok (test-name)
+ (slime-test-message test-name))
+
+(defun slime-print-check-failed (test-name)
+ (slime-test-failure "FAILED" test-name))
+
+(defun slime-print-check-error (reason)
+ (slime-test-failure "ERROR" (format "%S" reason)))
+
+(put 'def-slime-test 'lisp-indent-function 4)
+(put 'slime-check 'lisp-indent-function 1)
+
+
+;;;;; Test case definitions
+
+;; Clear out old tests.
+(setq slime-tests nil)
+
+(defun slime-check-top-level (&optional test-name)
+ (slime-accept-process-output nil 0.001)
+ (slime-check "At the top level (no debugging or pending RPCs)"
+ (slime-at-top-level-p)))
+
+(defun slime-at-top-level-p ()
+ (and (not (sldb-get-default-buffer))
+ (null (slime-rex-continuations))))
+
+(defun slime-wait-condition (name predicate timeout)
+ (let ((end (time-add (current-time) (seconds-to-time timeout))))
+ (while (not (funcall predicate))
+ (cond ((time-less-p end (current-time))
+ (error "Timeout waiting for condition: %S" name))
+ (t
+ ;; XXX if a process-filter enters a recursive-edit, we
+ ;; hang forever
+ (save-excursion
+ (slime-accept-process-output nil 0.1)))))))
+
+(defun slime-sync-to-top-level (timeout)
+ (slime-wait-condition "top-level" #'slime-at-top-level-p timeout))
+
+;; XXX: unused function
+(defun slime-check-sldb-level (expected)
+ (let ((sldb-level (when-let (sldb (sldb-get-default-buffer))
+ (with-current-buffer sldb
+ sldb-level))))
+ (slime-check ("SLDB level (%S) is %S" expected sldb-level)
+ (equal expected sldb-level))))
+
+(defun slime-test-expect (name expected actual &optional test)
+ (when (stringp expected) (setq expected (substring-no-properties expected)))
+ (when (stringp actual) (setq actual (substring-no-properties actual)))
+ (slime-check ("%s:\nexpected: [%S]\n actual: [%S]" name expected actual)
+ (funcall (or test #'equal) expected actual)))
+
+(defun sldb-level ()
+ (when-let (sldb (sldb-get-default-buffer))
+ (with-current-buffer sldb
+ sldb-level)))
+
+(defun slime-sldb-level= (level)
+ (when-let (sldb (sldb-get-default-buffer))
+ (with-current-buffer sldb
+ (equal sldb-level level))))
+
+(def-slime-test narrowing
+ ()
+ "Check that narrowing is properly sustained."
+ '(())
+ (slime-check-top-level)
+ (let ((random-buffer-name (symbol-name (gensym)))
+ (defun-pos) (tmpbuffer))
+ (with-temp-buffer
+ (dotimes (i 100) (insert (format ";;; %d. line\n" i)))
+ (setq tmpbuffer (current-buffer))
+ (setq defun-pos (point))
+ (insert (concat "(defun __foo__ (x y)" "\n"
+ " 'nothing)" "\n"))
+ (dotimes (i 100) (insert (format ";;; %d. line\n" (+ 100 i))))
+ (slime-check "Checking that newly created buffer is not narrowed."
+ (not (slime-buffer-narrowed-p)))
+
+ (goto-char defun-pos)
+ (narrow-to-defun)
+ (slime-check "Checking that narrowing succeeded."
+ (slime-buffer-narrowed-p))
+
+ (slime-with-output-to-temp-buffer (random-buffer-name) nil
+ (slime-check ("Checking that we're in Slime's temp buffer `%s'" random-buffer-name)
+ (equal (buffer-name (current-buffer)) random-buffer-name))
+ (slime-temp-buffer-quit))
+ (kill-buffer random-buffer-name)
+ (slime-check ("Checking that we've got back from `%s'" random-buffer-name)
+ (and (eq (current-buffer) tmpbuffer)
+ (= (point) defun-pos)))
+
+ (slime-check "Checking that narrowing sustained after quitting Slime's temp buffer."
+ (slime-buffer-narrowed-p))
+
+ (let ((slime-buffer-package "SWANK")
+ (symbol '*buffer-package*))
+ (slime-edit-definition (symbol-name symbol))
+ (slime-check ("Checking that we've got M-. into swank.lisp." symbol)
+ (string= (file-name-nondirectory (buffer-file-name))
+ "swank.lisp"))
+ (slime-pop-find-definition-stack)
+ (slime-check ("Checking that we've got back.")
+ (and (eq (current-buffer) tmpbuffer)
+ (= (point) defun-pos)))
+
+ (slime-check "Checking that narrowing sustained after M-,"
+ (slime-buffer-narrowed-p)))
+ ))
+ (slime-check-top-level))
+
+
+(def-slime-test find-definition
+ (name buffer-package snippet)
+ "Find the definition of a function or macro in swank.lisp."
+ '(("read-from-emacs" "SWANK" "(defun read-from-emacs ")
+ ("swank::read-from-emacs" "CL-USER" "(defun read-from-emacs ")
+ ("swank:start-server" "CL-USER" "(defun start-server "))
+ (switch-to-buffer "*scratch*") ; not buffer of definition
+ (slime-check-top-level)
+ (let ((orig-buffer (current-buffer))
+ (orig-pos (point))
+ (enable-local-variables nil) ; don't get stuck on -*- eval: -*-
+ (slime-buffer-package buffer-package))
+ (slime-edit-definition name)
+ ;; Postconditions
+ (slime-check ("Definition of `%S' is in swank.lisp." name)
+ (string= (file-name-nondirectory (buffer-file-name)) "swank.lisp"))
+ (slime-check "Definition now at point." (looking-at snippet))
+ (slime-pop-find-definition-stack)
+ (slime-check "Returning from definition restores original buffer/position."
+ (and (eq orig-buffer (current-buffer))
+ (= orig-pos (point)))))
+ (slime-check-top-level))
+
+(def-slime-test complete-symbol
+ (prefix expected-completions)
+ "Find the completions of a symbol-name prefix."
+ '(("cl:compile" (("cl:compile" "cl:compile-file" "cl:compile-file-pathname"
+ "cl:compiled-function" "cl:compiled-function-p" "cl:compiler-macro"
+ "cl:compiler-macro-function")
+ "cl:compile"))
+ ("cl:foobar" (nil ""))
+ ("swank::compile-file" (("swank::compile-file"
+ "swank::compile-file-for-emacs"
+ "swank::compile-file-if-needed"
+ "swank::compile-file-pathname")
+ "swank::compile-file"))
+ ("cl:m-v-l" (nil "")))
+ (let ((completions (slime-simple-completions prefix)))
+ (slime-test-expect "Completion set" expected-completions completions)))
+
+(def-slime-test arglist
+ ;; N.B. Allegro apparently doesn't return the default values of
+ ;; optional parameters. Thus the regexp in the start-server
+ ;; expected value. In a perfect world we'd find a way to smooth
+ ;; over this difference between implementations--perhaps by
+ ;; convincing Franz to provide a function that does what we want.
+ (function-name expected-arglist)
+ "Lookup the argument list for FUNCTION-NAME.
+Confirm that EXPECTED-ARGLIST is displayed."
+ '(("swank::operator-arglist" "(swank::operator-arglist name package)")
+ ("swank::create-socket" "(swank::create-socket host port)")
+ ("swank::emacs-connected" "(swank::emacs-connected )")
+ ("swank::compile-string-for-emacs"
+ "(swank::compile-string-for-emacs string buffer position directory)")
+ ("swank::connection.socket-io"
+ "(swank::connection.socket-io \\(struct\\(ure\\)?\\|object\\|instance\\))")
+ ("cl:lisp-implementation-type" "(cl:lisp-implementation-type )")
+ ("cl:class-name"
+ "(cl:class-name \\(class\\|object\\|instance\\|structure\\))"))
+ (slime-check-top-level)
+ (let ((arglist (slime-eval `(swank:operator-arglist ,function-name
+ "swank"))))
+ (slime-test-expect "Argument list is as expected"
+ expected-arglist (downcase arglist)
+ #'string-match))
+ (slime-check-top-level))
+
+(def-slime-test (compile-defun ("allegro" "lispworks" "clisp"))
+ (program subform)
+ "Compile PROGRAM containing errors.
+Confirm that SUBFORM is correctly located."
+ '(("(defun cl-user::foo () (cl-user::bar))" (cl-user::bar))
+ ("(defun cl-user::foo ()
+ #\\space
+ ;;Sdf
+ (cl-user::bar))"
+ (cl-user::bar))
+ ("(defun cl-user::foo ()
+ #+(or)skipped
+ #| #||#
+ #||# |#
+ (cl-user::bar))"
+ (cl-user::bar))
+ ("(defun cl-user::foo ()
+ (list `(1 ,(random 10) 2 ,@(random 10) 3 ,(cl-user::bar))))"
+ (cl-user::bar))
+ ("(defun cl-user::foo ()
+ \"\\\" bla bla \\\"\"
+ (cl-user::bar))"
+ (cl-user::bar))
+ ("(defun cl-user::foo ()
+ #.*log-events*
+ (cl-user::bar))"
+ (cl-user::bar))
+ ("#.'(defun x () (/ 1 0))
+ (defun foo ()
+ (cl-user::bar))
+
+ "
+ (cl-user::bar)))
+ (slime-check-top-level)
+ (with-temp-buffer
+ (lisp-mode)
+ (insert program)
+ (setq slime-buffer-package ":swank")
+ (slime-compile-string (buffer-string) 1)
+ (setq slime-buffer-package ":cl-user")
+ (slime-sync-to-top-level 5)
+ (goto-char (point-max))
+ (slime-previous-note)
+ (slime-check error-location-correct
+ (equal (read (current-buffer))
+ subform)))
+ (slime-check-top-level))
+
+(def-slime-test async-eval-debugging (depth)
+ "Test recursive debugging of asynchronous evaluation requests."
+ '((1) (2) (3))
+ (slime-check-top-level)
+ (lexical-let ((depth depth)
+ (debug-hook-max-depth 0))
+ (let ((debug-hook
+ (lambda ()
+ (with-current-buffer (sldb-get-default-buffer)
+ (when (> sldb-level debug-hook-max-depth)
+ (setq debug-hook-max-depth sldb-level)
+ (if (= sldb-level depth)
+ ;; We're at maximum recursion - time to unwind
+ (sldb-quit)
+ ;; Going down - enter another recursive debug
+ ;; Recursively debug.
+ (slime-eval-async 'no-such-variable)))))))
+ (let ((sldb-hook (cons debug-hook sldb-hook)))
+ (slime-eval-async 'no-such-variable)
+ (slime-sync-to-top-level 5)
+ (slime-check-top-level)
+ (slime-check ("Maximum depth reached (%S) is %S."
+ debug-hook-max-depth depth)
+ (= debug-hook-max-depth depth))))))
+
+(def-slime-test unwind-to-previous-sldb-level (level2 level1)
+ "Test recursive debugging and returning to lower SLDB levels."
+ '((2 1) (4 2))
+ (slime-check-top-level)
+ (lexical-let ((level2 level2)
+ (level1 level1)
+ (state 'enter)
+ (max-depth 0))
+ (let ((debug-hook
+ (lambda ()
+ (with-current-buffer (sldb-get-default-buffer)
+ (setq max-depth (max sldb-level max-depth))
+ (ecase state
+ (enter
+ (cond ((= sldb-level level2)
+ (setq state 'leave)
+ (sldb-invoke-restart (sldb-first-abort-restart)))
+ (t
+ (slime-eval-async `(cl:aref cl:nil ,sldb-level)))))
+ (leave
+ (cond ((= sldb-level level1)
+ (setq state 'ok)
+ (sldb-quit))
+ (t
+ (sldb-invoke-restart (sldb-first-abort-restart))
+ ))))))))
+ (let ((sldb-hook (cons debug-hook sldb-hook)))
+ (slime-eval-async `(cl:aref cl:nil 0))
+ (slime-sync-to-top-level 15)
+ (slime-check-top-level)
+ (slime-check ("Maximum depth reached (%S) is %S." max-depth level2)
+ (= max-depth level2))
+ (slime-check ("Final state reached.")
+ (eq state 'ok))))))
+
+(defun sldb-first-abort-restart ()
+ (let ((case-fold-search t))
+ (position-if (lambda (x) (string-match "abort" (car x))) sldb-restarts)))
+
+(def-slime-test loop-interrupt-quit
+ ()
+ "Test interrupting a loop."
+ '(())
+ (slime-check-top-level)
+ (slime-eval-async '(cl:loop) (lambda (_) ) "CL-USER")
+ (slime-accept-process-output nil 1)
+ (slime-check "In eval state." (slime-busy-p))
+ (slime-interrupt)
+ (slime-wait-condition "First interrupt" (lambda () (slime-sldb-level= 1)) 5)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-quit))
+ (slime-sync-to-top-level 5)
+ (slime-check-top-level))
+
+(def-slime-test loop-interrupt-continue-interrupt-quit
+ ()
+ "Test interrupting a previously interrupted but continued loop."
+ '(())
+ (slime-check-top-level)
+ (slime-eval-async '(cl:loop) (lambda (_) ) "CL-USER")
+ (sleep-for 1)
+ (slime-wait-condition "running" #'slime-busy-p 5)
+ (slime-interrupt)
+ (slime-wait-condition "First interrupt" (lambda () (slime-sldb-level= 1)) 5)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-continue))
+ (slime-wait-condition "running" (lambda ()
+ (and (slime-busy-p)
+ (not (sldb-get-default-buffer)))) 5)
+ (slime-interrupt)
+ (slime-wait-condition "Second interrupt" (lambda () (slime-sldb-level= 1)) 5)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-quit))
+ (slime-sync-to-top-level 5)
+ (slime-check-top-level))
+
+(def-slime-test interactive-eval
+ ()
+ "Test interactive eval and continuing from the debugger."
+ '(())
+ (slime-check-top-level)
+ (lexical-let ((done nil))
+ (let ((sldb-hook (lambda () (sldb-continue) (setq done t))))
+ (slime-interactive-eval
+ "(progn(cerror \"foo\" \"restart\")(cerror \"bar\" \"restart\")(+ 1 2))")
+ (while (not done) (slime-accept-process-output))
+ (slime-sync-to-top-level 5)
+ (slime-check-top-level)
+ (let ((message (current-message)))
+ (slime-check "Minibuffer contains: \"3\""
+ (equal "=> 3 (#x3, #o3, #b11)" message))))))
+
+(def-slime-test interrupt-bubbling-idiot
+ ()
+ "Test interrupting a loop that sends a lot of output to Emacs."
+ '(())
+ (slime-accept-process-output nil 1)
+ (slime-check-top-level)
+ (slime-eval-async '(cl:loop :for i :from 0 :do (cl:progn (cl:print i)
+ (cl:finish-output)))
+ (lambda (_) )
+ "CL-USER")
+ (sleep-for 1)
+ (slime-interrupt)
+ (slime-wait-condition "Debugger visible"
+ (lambda ()
+ (and (slime-sldb-level= 1)
+ (get-buffer-window (sldb-get-default-buffer))))
+ 30)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-quit))
+ (slime-sync-to-top-level 5))
+
+(def-slime-test package-updating
+ (package-name nicknames)
+ "Test if slime-lisp-package is updated."
+ '(("COMMON-LISP" ("CL"))
+ ("KEYWORD" ("" "KEYWORD"))
+ ("COMMON-LISP-USER" ("CL-USER")))
+ (with-current-buffer (slime-output-buffer)
+ (let ((p (slime-eval
+ `(swank:listener-eval
+ ,(format
+ "(cl:setq cl:*print-case* :upcase)
+ (cl:setq cl:*package* (cl:find-package %S))
+ (cl:package-name cl:*package*)" package-name))
+ (slime-lisp-package))))
+ (slime-check ("slime-lisp-package is %S." package-name)
+ (equal (slime-lisp-package) package-name))
+ (slime-check ("slime-lisp-package-prompt-string is in %S." nicknames)
+ (member (slime-lisp-package-prompt-string) nicknames)))))
+
+(def-slime-test repl-test
+ (input result-contents)
+ "Test simple commands in the minibuffer."
+ '(("(+ 1 2)" "SWANK> (+ 1 2)
+3
+SWANK> ")
+ ("(princ 10)" "SWANK> (princ 10)
+10
+10
+SWANK> ")
+ ("(princ 10)(princ 20)" "SWANK> (princ 10)(princ 20)
+1020
+20
+SWANK> ")
+ ("(dotimes (i 10 77) (princ i) (terpri))"
+ "SWANK> (dotimes (i 10 77) (princ i) (terpri))
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+77
+SWANK> "))
+ (with-current-buffer (slime-output-buffer)
+ (setf (slime-lisp-package-prompt-string) "SWANK"))
+ (kill-buffer (slime-output-buffer))
+ (with-current-buffer (slime-output-buffer)
+ (insert input)
+ (slime-test-expect "Buffer contains input"
+ (concat "SWANK> " input)
+ (buffer-string))
+ (call-interactively 'slime-repl-return)
+ (slime-sync-to-top-level 5)
+ (slime-test-expect "Buffer contains result"
+ result-contents (buffer-string))))
+
+(def-slime-test repl-return
+ (before after result-contents)
+ "Test if slime-repl-return sends the correct protion to Lisp even
+if point is not at the end of the line."
+ '(("(+ 1 2)" "" "SWANK> (+ 1 2)
+3
+SWANK> ")
+("(+ 1 " "2)" "SWANK> (+ 1 2)
+3
+SWANK> ")
+
+("(+ 1\n" "2)" "SWANK> (+ 1
+2)
+3
+SWANK> "))
+ (with-current-buffer (slime-output-buffer)
+ (setf (slime-lisp-package-prompt-string) "SWANK"))
+ (kill-buffer (slime-output-buffer))
+ (with-current-buffer (slime-output-buffer)
+ (insert before)
+ (save-excursion (insert after))
+ (slime-test-expect "Buffer contains input"
+ (concat "SWANK> " before after)
+ (buffer-string))
+ (call-interactively 'slime-repl-return)
+ (slime-sync-to-top-level 5)
+ (slime-test-expect "Buffer contains result"
+ result-contents (buffer-string))))
+
+(def-slime-test repl-read
+ (prompt input result-contents)
+ "Test simple commands in the minibuffer."
+ '(("(read-line)" "foo" "SWANK> (values (read-line))
+foo
+\"foo\"
+SWANK> ")
+ ("(read-char)" "1" "SWANK> (values (read-char))
+1
+#\\1
+SWANK> ")
+ ("(read)" "(+ 2 3
+4)" "SWANK> (values (read))
+\(+ 2 3
+4)
+\(+ 2 3 4)
+SWANK> "))
+ (slime-sync-to-top-level 2)
+ (with-current-buffer (slime-output-buffer)
+ (setf (slime-lisp-package-prompt-string) "SWANK"))
+ (kill-buffer (slime-output-buffer))
+ (with-current-buffer (slime-output-buffer)
+ (insert (format "(values %s)" prompt))
+ (call-interactively 'slime-repl-return)
+ (slime-wait-condition "reading" #'slime-reading-p 5)
+ (insert input)
+ (call-interactively 'slime-repl-return)
+ (slime-sync-to-top-level 5)
+ (slime-test-expect "Buffer contains result"
+ result-contents (buffer-string))))
+
+(def-slime-test repl-read-lines
+ (command inputs final-contents)
+ "Test reading multiple lines from the repl."
+ '(("(list (read-line) (read-line) (read-line))"
+ ("a" "b" "c")
+ "SWANK> (list (read-line) (read-line) (read-line))
+a
+b
+c
+\(\"a\" \"b\" \"c\")
+SWANK> "))
+ (when (slime-output-buffer)
+ (kill-buffer (slime-output-buffer)))
+ (with-current-buffer (slime-output-buffer)
+ (setf (slime-lisp-package-prompt-string) "SWANK")
+ (insert command)
+ (call-interactively 'slime-repl-return)
+ (dolist (input inputs)
+ (slime-wait-condition "reading" #'slime-reading-p 5)
+ (insert input)
+ (call-interactively 'slime-repl-return))
+ (slime-sync-to-top-level 5)
+ (slime-check "Buffer contains result"
+ (equal final-contents (buffer-string)))))
+
+(def-slime-test repl-type-ahead
+ (command input final-contents)
+ "Ensure that user input is preserved correctly.
+In particular, input inserted while waiting for a result."
+ '(("(sleep 1)" "foo" "SWANK> (sleep 1)
+NIL
+SWANK> foo"))
+ (when (slime-output-buffer)
+ (kill-buffer (slime-output-buffer)))
+ (setf (slime-lisp-package-prompt-string) "SWANK")
+ (with-current-buffer (slime-output-buffer)
+ (insert command)
+ (call-interactively 'slime-repl-return)
+ (insert input)
+ (slime-sync-to-top-level 5)
+ (slime-check "Buffer contains result"
+ (equal final-contents (buffer-string)))))
+
+(def-slime-test interactive-eval-output
+ (input result-contents visiblep)
+ "Test simple commands in the minibuffer."
+ '(("(+ 1 2)" ";;;; (+ 1 2) ...
+SWANK> " nil)
+ ("(princ 10)" ";;;; (princ 10) ...
+10
+SWANK> " t)
+ ("(princ \"ßäëïöüáéíóúàèìòùâêîôûãõøçðåæ\")"
+ ";;;; (princ \"ßäëïöüáéíóúàèìòùâêîôûãõøçðåæ\") ...
+ßäëïöüáéíóúàèìòùâêîôûãõøçðåæ
+SWANK> " t))
+ (when (and (fboundp 'string-to-multibyte)
+ (with-current-buffer (process-buffer (slime-connection))
+ enable-multibyte-characters))
+ (setq input (funcall 'string-to-multibyte input))
+ (setq result-contents (funcall 'string-to-multibyte result-contents)))
+ (with-current-buffer (slime-output-buffer)
+ (setf (slime-lisp-package-prompt-string) "SWANK"))
+ (kill-buffer (slime-output-buffer))
+ (with-current-buffer (slime-output-buffer)
+ (slime-interactive-eval input)
+ (slime-sync-to-top-level 5)
+ (slime-test-expect "Buffer contains result"
+ result-contents (buffer-string))
+ (slime-test-expect "Buffer visible?"
+ visiblep
+ (not (not (get-buffer-window (current-buffer)))))))
+
+(def-slime-test break
+ ()
+ "Test if BREAK invokes SLDB."
+ '(())
+ (slime-accept-process-output nil 1)
+ (slime-check-top-level)
+ (slime-compile-string (prin1-to-string '(cl:defun cl-user::foo ()
+ (cl:break)))
+ 0)
+ (slime-sync-to-top-level 2)
+ (slime-eval-async '(cl-user::foo))
+ (slime-wait-condition "Debugger visible"
+ (lambda ()
+ (and (slime-sldb-level= 1)
+ (get-buffer-window (sldb-get-default-buffer))))
+ 5)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-quit))
+ (slime-accept-process-output nil 1)
+ (slime-sync-to-top-level 5))
+
+(def-slime-test interrupt-at-toplevel
+ ()
+ "Let's see what happens if we send a user interrupt at toplevel."
+ '(())
+ (slime-check-top-level)
+ (slime-interrupt)
+ (slime-wait-condition "Debugger visible"
+ (lambda ()
+ (and (slime-sldb-level= 1)
+ (get-buffer-window (sldb-get-default-buffer))))
+ 5)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-quit))
+ (slime-sync-to-top-level 5))
+
+(def-slime-test interrupt-in-blocking-read
+ ()
+ "Let's see what happens if we interrupt a blocking read operation."
+ '(())
+ (slime-check-top-level)
+ (when (slime-output-buffer)
+ (setf (slime-lisp-package-prompt-string) "SWANK")
+ (kill-buffer (slime-output-buffer)))
+ (with-current-buffer (slime-output-buffer)
+ (insert "(read-char)")
+ (call-interactively 'slime-repl-return))
+ (slime-wait-condition "reading" #'slime-reading-p 5)
+ (slime-interrupt)
+ (slime-wait-condition "Debugger visible"
+ (lambda ()
+ (and (slime-sldb-level= 1)
+ (get-buffer-window (sldb-get-default-buffer))))
+ 5)
+ (with-current-buffer (sldb-get-default-buffer)
+ (sldb-continue))
+ (slime-wait-condition "reading" #'slime-reading-p 5)
+ (with-current-buffer (slime-output-buffer)
+ (insert "X")
+ (call-interactively 'slime-repl-return)
+ (slime-sync-to-top-level 5)
+ (slime-test-expect "Buffer contains result"
+ "SWANK> (read-char)
+X
+#\\X
+SWANK> " (buffer-string))))
+
+(def-slime-test disconnect
+ ()
+ "Close the connetion.
+Confirm that the subprocess continues gracefully.
+Reconnect afterwards."
+ '(())
+ (slime-check-top-level)
+ (let* ((c (slime-connection))
+ (p (slime-inferior-process c)))
+ (with-current-buffer (process-buffer p)
+ (erase-buffer))
+ (delete-process c)
+ (assert (equal (process-status c) 'closed) nil "Connection not closed")
+ (slime-accept-process-output nil 0.1)
+ (assert (equal (process-status p) 'run) nil "Subprocess not running")
+ (with-current-buffer (process-buffer p)
+ (assert (< (buffer-size) 500) nil "Unusual output"))
+ (slime-inferior-connect p (slime-inferior-lisp-args p))
+ (lexical-let ((hook nil))
+ (setq hook (lambda ()
+ (remove-hook 'slime-connected-hook hook)))
+ (add-hook 'slime-connected-hook hook)
+ (while (member hook slime-connected-hook)
+ (sit-for 0.5)
+ (slime-accept-process-output nil 0.1)))
+ (slime-test-expect "We are connected again" p (slime-inferior-process))))
+
+
+;;;; Utilities
+
+;;;;; Misc.
+
+(defun slime-length= (seq n)
+ "Test for whether SEQ contains N number of elements. I.e. it's equivalent
+ to (= (LENGTH SEQ) N), but besides being more concise, it may also be more
+ efficiently implemented."
+ (etypecase seq
+ (list
+ (let ((list seq))
+ (setq list (nthcdr (1- n) list))
+ (and list (null (cdr list)))))
+ (sequence
+ (= (length seq) n))))
+
+(defun slime-length> (seq n)
+ "Return non-nil if (> (length LIST) N)."
+ (etypecase seq
+ (list (nthcdr n seq))
+ (seq (> (length seq) n))))
+
+;;;;; Buffer related
+
+(defun slime-buffer-narrowed-p (&optional buffer)
+ "Returns T if BUFFER (or the current buffer respectively) is narrowed."
+ (with-current-buffer (or buffer (current-buffer))
+ (let ((beg (point-min))
+ (end (point-max))
+ (total (buffer-size)))
+ (or (/= beg 1) (/= end (1+ total))))))
+
+
+;;;;; Extracting Lisp forms from the buffer or user
+
+(defun slime-defun-at-point ()
+ "Return the text of the defun at point."
+ (apply #'buffer-substring-no-properties
+ (slime-region-for-defun-at-point)))
+
+(defvar slime-region-for-defun-function nil)
+
+(defun slime-region-for-defun-at-point ()
+ "Return the start and end position of the toplevel form at point."
+ (or (and slime-region-for-defun-function
+ (funcall slime-region-for-defun-function))
+ (save-excursion
+ (save-match-data
+ (end-of-defun)
+ (let ((end (point)))
+ (beginning-of-sexp)
+ (list (point) end))))))
+
+(defun slime-beginning-of-symbol ()
+ "Move point to the beginning of the current symbol."
+ (when (slime-point-moves-p
+ (while (slime-point-moves-p
+ (skip-syntax-backward "w_")
+ (when (eq (char-before) ?|)
+ (backward-char)))))
+ (when (eq (char-before) ?#) ; special case for things like "#<foo"
+ (forward-char))))
+
+(defun slime-end-of-symbol ()
+ "Move point to the end of the current symbol."
+ (while (slime-point-moves-p
+ (skip-syntax-forward "w_")
+ ;; | has the syntax as ", so we need to
+ ;; treat it manually rather than via syntax.
+ (when (looking-at "|")
+ (forward-char)))))
+
+(put 'slime-symbol 'end-op 'slime-end-of-symbol)
+(put 'slime-symbol 'beginning-op 'slime-beginning-of-symbol)
+
+(defun slime-symbol-start-pos ()
+ "Return the starting position of the symbol under point.
+The result is unspecified if there isn't a symbol under the point."
+ (save-excursion (slime-beginning-of-symbol) (point)))
+
+(defun slime-symbol-end-pos ()
+ (save-excursion (slime-end-of-symbol) (point)))
+
+(defun slime-symbol-name-at-point ()
+ "Return the name of the symbol at point, otherwise nil."
+ (save-restriction
+ ;; Don't be tricked into grabbing the REPL prompt.
+ (when (and (eq major-mode 'slime-repl-mode)
+ (>= (point) slime-repl-input-start-mark))
+ (narrow-to-region slime-repl-input-start-mark (point-max)))
+ (save-excursion
+ (let ((string (thing-at-point 'slime-symbol)))
+ (and string
+ ;; In Emacs20 (thing-at-point 'symbol) returns "" instead
+ ;; of nil when called from an empty (or
+ ;; narrowed-to-empty) buffer.
+ (not (equal string ""))
+ (substring-no-properties string))))))
+
+(defun slime-symbol-at-point ()
+ "Return the symbol at point, otherwise nil."
+ (let ((name (slime-symbol-name-at-point)))
+ (and name (intern name))))
+
+(defun slime-sexp-at-point ()
+ "Return the sexp at point as a string, otherwise nil."
+ (let ((string (thing-at-point 'sexp)))
+ (if string (substring-no-properties string) nil)))
+
+(defun slime-sexp-at-point-or-error ()
+ "Return the sexp at point as a string, othwise signal an error."
+ (or (slime-sexp-at-point)
+ (error "No expression at point.")))
+
+;;;; Portability library
+
+(when (featurep 'xemacs)
+ (require 'overlay))
+
+(defun slime-split-string (string &optional separators omit-nulls)
+ "This is like `split-string' in Emacs22, but also works in
+Emacs20 and 21."
+ (let ((splits (split-string string separators)))
+ (if omit-nulls
+ (setq splits (remove "" splits))
+ ;; SPLIT-STRING in Emacs before 22.x automatically removed nulls
+ ;; at beginning and end, so we gotta add them here again.
+ (when (or (slime-emacs-20-p) (slime-emacs-21-p))
+ (when (find (elt string 0) separators)
+ (push "" splits))
+ (when (find (elt string (1- (length string))) separators)
+ (setq splits (append splits (list ""))))))
+ splits))
+
+(defun slime-delete-and-extract-region (start end)
+ "Like `delete-and-extract-region' except that it is guaranteed
+to return a string. At least Emacs 21.3.50 returned `nil' on
+\(delete-and-extract-region (point) (point)), this function
+will return \"\"."
+ (let ((result (delete-and-extract-region start end)))
+ (if (null result)
+ ""
+ (assert (stringp result))
+ result)))
+
+(defmacro slime-defun-if-undefined (name &rest rest)
+ ;; We can't decide at compile time whether NAME is properly
+ ;; bound. So we delay the decision to runtime to ensure some
+ ;; definition
+ `(unless (fboundp ',name)
+ (defun ,name , at rest)))
+
+(put 'slime-defun-if-undefined 'lisp-indent-function 2)
+
+(defvar slime-accept-process-output-supports-floats
+ (ignore-errors (accept-process-output nil 0.0) t))
+
+(defun slime-accept-process-output (&optional process timeout)
+ "Like `accept-process-output' but the TIMEOUT argument can be a float."
+ (cond (slime-accept-process-output-supports-floats
+ (accept-process-output process timeout))
+ (t
+ (accept-process-output process
+ (if timeout (truncate timeout))
+ ;; Emacs 21 uses microsecs; Emacs 22 millisecs
+ (if timeout (truncate (* timeout 1000000)))))))
+
+(slime-defun-if-undefined next-single-char-property-change
+ (position prop &optional object limit)
+ (let ((limit (typecase limit
+ (null nil)
+ (marker (marker-position limit))
+ (t limit))))
+ (if (stringp object)
+ (or (next-single-property-change position prop object limit)
+ limit
+ (length object))
+ (with-current-buffer (or object (current-buffer))
+ (let ((initial-value (get-char-property position prop object))
+ (limit (or limit (point-max))))
+ (loop for pos = position then (next-char-property-change pos limit)
+ if (>= pos limit) return limit
+ if (not (eq initial-value
+ (get-char-property pos prop object)))
+ return pos))))))
+
+(slime-defun-if-undefined previous-single-char-property-change
+ (position prop &optional object limit)
+ (let ((limit (typecase limit
+ (null nil)
+ (marker (marker-position limit))
+ (t limit))))
+ (if (stringp object)
+ (or (previous-single-property-change position prop object limit)
+ limit
+ (length object))
+ (with-current-buffer (or object (current-buffer))
+ (let ((limit (or limit (point-min))))
+ (if (<= position limit)
+ limit
+ (let ((initial-value (get-char-property (1- position)
+ prop object)))
+ (loop for pos = position then
+ (previous-char-property-change pos limit)
+ if (<= pos limit) return limit
+ if (not (eq initial-value
+ (get-char-property (1- pos) prop object)))
+ return pos))))))))
+
+(slime-defun-if-undefined next-char-property-change (position &optional limit)
+ (let ((tmp (next-overlay-change position)))
+ (when tmp
+ (setq tmp (min tmp limit)))
+ (next-property-change position nil tmp)))
+
+(slime-defun-if-undefined previous-char-property-change
+ (position &optional limit)
+ (let ((tmp (previous-overlay-change position)))
+ (when tmp
+ (setq tmp (max tmp limit)))
+ (previous-property-change position nil tmp)))
+
+(slime-defun-if-undefined substring-no-properties (string &optional start end)
+ (let* ((start (or start 0))
+ (end (or end (length string)))
+ (string (substring string start end)))
+ (set-text-properties 0 (- end start) nil string)
+ string))
+
+(slime-defun-if-undefined match-string-no-properties (num &optional string)
+ (if (match-beginning num)
+ (if string
+ (substring-no-properties string (match-beginning num)
+ (match-end num))
+ (buffer-substring-no-properties (match-beginning num)
+ (match-end num)))))
+
+(slime-defun-if-undefined set-window-text-height (window height)
+ (let ((delta (- height (window-text-height window))))
+ (unless (zerop delta)
+ (let ((window-min-height 1))
+ (if (and window (not (eq window (selected-window))))
+ (save-selected-window
+ (select-window window)
+ (enlarge-window delta))
+ (enlarge-window delta))))))
+
+(slime-defun-if-undefined window-text-height (&optional window)
+ (1- (window-height window)))
+
+(slime-defun-if-undefined subst-char-in-string (fromchar tochar string
+ &optional inplace)
+ "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
+Unless optional argument INPLACE is non-nil, return a new string."
+ (let ((i (length string))
+ (newstr (if inplace string (copy-sequence string))))
+ (while (> i 0)
+ (setq i (1- i))
+ (if (eq (aref newstr i) fromchar)
+ (aset newstr i tochar)))
+ newstr))
+
+(slime-defun-if-undefined count-screen-lines
+ (&optional beg end count-final-newline window)
+ (unless beg
+ (setq beg (point-min)))
+ (unless end
+ (setq end (point-max)))
+ (if (= beg end)
+ 0
+ (save-excursion
+ (save-restriction
+ (widen)
+ (narrow-to-region (min beg end)
+ (if (and (not count-final-newline)
+ (= ?\n (char-before (max beg end))))
+ (1- (max beg end))
+ (max beg end)))
+ (goto-char (point-min))
+ ;; XXX make this xemacs compatible
+ (1+ (vertical-motion (buffer-size) window))))))
+
+(slime-defun-if-undefined seconds-to-time (seconds)
+ "Convert SECONDS (a floating point number) to a time value."
+ (list (floor seconds 65536)
+ (floor (mod seconds 65536))
+ (floor (* (- seconds (ffloor seconds)) 1000000))))
+
+(slime-defun-if-undefined time-less-p (t1 t2)
+ "Say whether time value T1 is less than time value T2."
+ (or (< (car t1) (car t2))
+ (and (= (car t1) (car t2))
+ (< (nth 1 t1) (nth 1 t2)))))
+
+(slime-defun-if-undefined time-add (t1 t2)
+ "Add two time values. One should represent a time difference."
+ (let ((high (car t1))
+ (low (if (consp (cdr t1)) (nth 1 t1) (cdr t1)))
+ (micro (if (numberp (car-safe (cdr-safe (cdr t1))))
+ (nth 2 t1)
+ 0))
+ (high2 (car t2))
+ (low2 (if (consp (cdr t2)) (nth 1 t2) (cdr t2)))
+ (micro2 (if (numberp (car-safe (cdr-safe (cdr t2))))
+ (nth 2 t2)
+ 0)))
+ ;; Add
+ (setq micro (+ micro micro2))
+ (setq low (+ low low2))
+ (setq high (+ high high2))
+
+ ;; Normalize
+ ;; `/' rounds towards zero while `mod' returns a positive number,
+ ;; so we can't rely on (= a (+ (* 100 (/ a 100)) (mod a 100))).
+ (setq low (+ low (/ micro 1000000) (if (< micro 0) -1 0)))
+ (setq micro (mod micro 1000000))
+ (setq high (+ high (/ low 65536) (if (< low 0) -1 0)))
+ (setq low (logand low 65535))
+
+ (list high low micro)))
+
+(slime-defun-if-undefined line-beginning-position (&optional n)
+ (save-excursion
+ (beginning-of-line n)
+ (point)))
+
+(slime-defun-if-undefined line-end-position (&optional n)
+ (save-excursion
+ (end-of-line n)
+ (point)))
+
+(slime-defun-if-undefined check-parens ()
+ "Verify that parentheses in the current buffer are balanced.
+If they are not, position point at the first syntax error found."
+ (interactive)
+ (let ((saved-point (point))
+ (state (parse-partial-sexp (point-min) (point-max) -1)))
+ (destructuring-bind (depth innermost-start last-terminated-start
+ in-string in-comment after-quote
+ minimum-depth comment-style
+ comment-or-string-start &rest _) state
+ (cond ((and (zerop depth)
+ (not in-string)
+ (or (not in-comment)
+ (and (eq comment-style nil)
+ (eobp)))
+ (not after-quote))
+ (goto-char saved-point)
+ (message "All parentheses appear to be balanced."))
+ ((plusp depth)
+ (goto-char innermost-start)
+ (error "Missing )"))
+ ((minusp depth)
+ (error "Extra )"))
+ (in-string
+ (goto-char comment-or-string-start)
+ (error "String not terminated"))
+ (in-comment
+ (goto-char comment-or-string-start)
+ (error "Comment not terminated"))
+ (after-quote
+ (error "After quote"))
+ (t (error "Shouldn't happen: parsing state: %S" state))))))
+
+(slime-defun-if-undefined read-directory-name (prompt
+ &optional dir default-dirname
+ mustmatch initial)
+ (unless dir
+ (setq dir default-directory))
+ (unless default-dirname
+ (setq default-dirname
+ (if initial (concat dir initial) default-directory)))
+ (let ((file (read-file-name prompt dir default-dirname mustmatch initial)))
+ (setq file (file-name-as-directory (expand-file-name file)))
+ (cond ((file-directory-p file)
+ file)
+ (t
+ (error "Not a directory: %s" file)))))
+
+(slime-defun-if-undefined check-coding-system (coding-system)
+ (or (eq coding-system 'binary)
+ (error "No such coding system: %S" coding-system)))
+
+(slime-defun-if-undefined process-coding-system (process)
+ '(binary . binary))
+
+(slime-defun-if-undefined set-process-coding-system
+ (process &optional decoding encoding))
+
+(unless (boundp 'temporary-file-directory)
+ (defvar temporary-file-directory
+ (file-name-as-directory
+ (cond ((memq system-type '(ms-dos windows-nt))
+ (or (getenv "TEMP") (getenv "TMPDIR") (getenv "TMP") "c:/temp"))
+ ((memq system-type '(vax-vms axp-vms))
+ (or (getenv "TMPDIR") (getenv "TMP")
+ (getenv "TEMP") "SYS$SCRATCH:"))
+ (t
+ (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "/tmp"))))
+ "The directory for writing temporary files."))
+
+(unless (fboundp 'with-temp-message)
+ (defmacro with-temp-message (message &rest body)
+ (let ((current-message (make-symbol "current-message"))
+ (temp-message (make-symbol "with-temp-message")))
+ `(let ((,temp-message ,message)
+ (,current-message))
+ (unwind-protect
+ (progn
+ (when ,temp-message
+ (setq ,current-message (current-message))
+ (message "%s" ,temp-message))
+ , at body)
+ (and ,temp-message ,current-message
+ (message "%s" ,current-message)))))))
+
+(defun slime-emacs-20-p ()
+ (and (not (featurep 'xemacs))
+ (= emacs-major-version 20)))
+
+(defun slime-emacs-21-p ()
+ (and (not (featurep 'xemacs))
+ (= emacs-major-version 21)))
+
+(when (featurep 'xemacs)
+ (add-hook 'sldb-hook 'sldb-xemacs-emulate-point-entered-hook))
+
+(defun sldb-xemacs-emulate-point-entered-hook ()
+ (add-hook (make-local-variable 'post-command-hook)
+ 'sldb-xemacs-post-command-hook))
+
+(defun sldb-xemacs-post-command-hook ()
+ (when (get-text-property (point) 'point-entered)
+ (funcall (get-text-property (point) 'point-entered))))
+
+(slime-defun-if-undefined with-selected-window (window &rest body)
+ `(save-selected-window
+ (select-window ,window)
+ , at body))
+
+;;; Stuff only available in XEmacs
+(slime-defun-if-undefined add-local-hook (hook function &optional append)
+ (make-local-hook hook)
+ (add-hook hook function append t))
+
+(slime-defun-if-undefined remove-local-hook (hook function)
+ (if (local-variable-p hook (current-buffer))
+ (remove-hook hook function t)))
+
+;;;; Some "nice" backward compatiblity bindings for lusers.
+
+(defvar slime-obsolete-commands
+ '(("\C-c\M-i" (slime repl) slime-fuzzy-complete-symbol)
+ ;; Don't shadow bindings in lisp-mode-map
+ ;;("\M-\C-a" (slime) slime-beginning-of-defun)
+ ;;("\M-\C-e" (slime) slime-end-of-defun)
+ ("\C-c\M-q" (slime) slime-reindent-defun)
+ ("\C-c\C-s" (slime) slime-complete-form)
+ ;; (nil nil slime-close-all-parens-in-sexp)
+ ))
+
+(defun slime-bind-obsolete-commands ()
+ (loop for (key maps command) in slime-obsolete-commands do
+ (dolist (m maps) (slime-bind-obsolete-command m key command))))
+
+(defun slime-bind-obsolete-command (map key command)
+ (let ((map (ecase map
+ (slime slime-mode-map)
+ (repl slime-repl-mode-map))))
+ (unless (lookup-key map key)
+ (define-key map key `(lambda (&rest _)
+ (interactive)
+ (slime-upgrade-notice ',command))))))
+
+(slime-bind-obsolete-commands)
+
+(defun slime-upgrade-notice (command)
+ (slime-timebomb (format "The command `%s' has been moved to contrib.
+Please consult the README file in the contrib directory for details.
+
+To fetch the contrib directoy use: cvs update -d"
+ command)
+ 15))
+
+;;;;; ... with gratuitous bloat
+
+(defun slime-timebomb (message timeout)
+ (with-current-buffer (generate-new-buffer "*warning*")
+ (insert message "\n\n")
+ (slime-timebomb-progress (point-marker) timeout)
+ (goto-char (point-min))
+ (pop-to-buffer (current-buffer))))
+
+(defun slime-timebomb-progress (mark timeout)
+ (let ((buffer (marker-buffer mark)))
+ (cond ((not (buffer-live-p buffer)))
+ ((zerop timeout) (kill-buffer buffer))
+ (t (with-current-buffer buffer
+ (save-excursion
+ (delete-region mark (point-max))
+ (goto-char mark)
+ (slime-timebomb-message timeout))
+ (run-with-timer 1 nil
+ 'slime-timebomb-progress mark (1- timeout)))))))
+
+(defun slime-timebomb-message (timeout)
+ (slime-insert-propertized
+ (list 'face (if (zerop (mod timeout 2)) 'highlight 'default))
+ (format "This message will destroy itself in %d seconds." timeout)))
+
+
+;;;; Finishing up
+
+(require 'bytecomp)
+(let ((byte-compile-warnings '()))
+ (mapc #'byte-compile
+ '(slime-alistify
+ slime-log-event
+ slime-events-buffer
+ slime-write-string
+ slime-output-buffer
+ slime-connection-output-buffer
+ slime-output-filter
+ slime-repl-show-maximum-output
+ slime-process-available-input
+ slime-dispatch-event
+ slime-net-filter
+ slime-net-have-input-p
+ slime-net-decode-length
+ slime-net-read
+ slime-print-apropos
+ slime-show-note-counts
+ slime-insert-propertized
+ slime-tree-insert)))
+
+(provide 'slime)
+(run-hooks 'slime-load-hook)
+
+;; Local Variables:
+;; outline-regexp: ";;;;+"
+;; indent-tabs-mode: nil
+;; coding: latin-1-unix!
+;; unibyte: t
+;; compile-command: "emacs -batch -L . -eval '(byte-compile-file \"slime.el\")' ; rm -v slime.elc"
+;; End:
+;;; slime.el ends here
Added: branches/bos/thirdparty/emacs/slime/swank-abcl.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-abcl.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,571 @@
+;;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;*"; -*-
+;;;
+;;; swank-abcl.lisp --- Armedbear CL specific code for SLIME.
+;;;
+;;; Adapted from swank-acl.lisp, Andras Simon, 2004
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+(in-package :swank-backend)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (require :collect) ;just so that it doesn't spoil the flying letters
+ (require :pprint))
+
+(defun sys::break (&optional (format-control "BREAK called")
+ &rest format-arguments)
+ (let ((*saved-backtrace* (backtrace-as-list-ignoring-swank-calls)))
+ (with-simple-restart (continue "Return from BREAK.")
+ (invoke-debugger
+ (sys::%make-condition 'simple-condition
+ (list :format-control format-control
+ :format-arguments format-arguments))))
+ nil))
+
+(defimplementation make-fn-streams (input-fn output-fn)
+ (let* ((output (ext:make-slime-output-stream output-fn))
+ (input (ext:make-slime-input-stream input-fn output)))
+ (values input output)))
+
+(defimplementation call-with-compilation-hooks (function)
+ (funcall function))
+
+;;; swank-mop
+
+;;dummies and definition
+
+(defclass standard-slot-definition ()())
+
+;(defun class-finalized-p (class) t)
+
+(defun slot-definition-documentation (slot) #+nil (documentation slot 't))
+(defun slot-definition-type (slot) t)
+(defun class-prototype (class))
+(defun generic-function-declarations (gf))
+(defun specializer-direct-methods (spec) (mop::class-direct-methods spec))
+
+(defun slot-definition-name (slot)
+ (mop::%slot-definition-name slot))
+
+(defun class-slots (class)
+ (mop::%class-slots class))
+
+(defun method-generic-function (method)
+ (mop::%method-generic-function method))
+
+(defun method-function (method)
+ (mop::%method-function method))
+
+(defun slot-boundp-using-class (class object slotdef)
+ (system::slot-boundp object (slot-definition-name slotdef)))
+
+(defun slot-value-using-class (class object slotdef)
+ (system::slot-value object (slot-definition-name slotdef)))
+
+(import-to-swank-mop
+ '( ;; classes
+ cl:standard-generic-function
+ standard-slot-definition ;;dummy
+ cl:method
+ cl:standard-class
+ ;; standard-class readers
+ mop::class-default-initargs
+ mop::class-direct-default-initargs
+ mop::class-direct-slots
+ mop::class-direct-subclasses
+ mop::class-direct-superclasses
+ mop::eql-specializer
+ mop::class-finalized-p
+ cl:class-name
+ mop::class-precedence-list
+ class-prototype ;;dummy
+ class-slots
+ specializer-direct-methods
+ ;; eql-specializer accessors
+ mop::eql-specializer-object
+ ;; generic function readers
+ mop::generic-function-argument-precedence-order
+ generic-function-declarations ;;dummy
+ mop::generic-function-lambda-list
+ mop::generic-function-methods
+ mop::generic-function-method-class
+ mop::generic-function-method-combination
+ mop::generic-function-name
+ ;; method readers
+ method-generic-function
+ method-function
+ mop::method-lambda-list
+ mop::method-specializers
+ mop::method-qualifiers
+ ;; slot readers
+ mop::slot-definition-allocation
+ slot-definition-documentation ;;dummy
+ mop::slot-definition-initargs
+ mop::slot-definition-initform
+ mop::slot-definition-initfunction
+ slot-definition-name
+ slot-definition-type ;;dummy
+ mop::slot-definition-readers
+ mop::slot-definition-writers
+ slot-boundp-using-class
+ slot-value-using-class
+ ))
+
+;;;; TCP Server
+
+
+(defimplementation preferred-communication-style ()
+ :spawn)
+
+
+
+(defimplementation create-socket (host port)
+ (ext:make-server-socket port))
+
+
+(defimplementation local-port (socket)
+ (java:jcall (java:jmethod "java.net.ServerSocket" "getLocalPort") socket))
+
+
+(defimplementation close-socket (socket)
+ (ext:server-socket-close socket))
+
+(defimplementation accept-connection (socket
+ &key external-format buffering timeout)
+ (declare (ignore buffering timeout external-format))
+ (ext:get-socket-stream (ext:socket-accept socket)))
+
+;;;; Unix signals
+
+(defimplementation call-without-interrupts (fn)
+ (funcall fn))
+
+(defimplementation getpid ()
+ (if (not (find :unix *features*))
+ 0
+ (let* ((runtime
+ (java:jstatic "getRuntime" "java.lang.Runtime"))
+ (command
+ (java:jnew-array-from-array
+ "java.lang.String" #("sh" "-c" "echo $PPID")))
+ (runtime-exec-jmethod
+ ;; Complicated because java.lang.Runtime.exec() is
+ ;; overloaded on a non-primitive type (array of
+ ;; java.lang.String), so we have to use the actual parameter
+ ;; instance to get java.lang.Class
+ (java:jmethod "java.lang.Runtime" "exec"
+ (java:jcall
+ (java:jmethod "java.lang.Object" "getClass")
+ command)))
+ (process
+ (java:jcall runtime-exec-jmethod runtime command))
+ (output
+ (java:jcall (java:jmethod "java.lang.Process" "getInputStream")
+ process)))
+ (java:jcall (java:jmethod "java.lang.Process" "waitFor") process)
+ (loop
+ :with b
+ :do (setq b
+ (java:jcall (java:jmethod "java.io.InputStream" "read")
+ output))
+ :until (member b '(-1 #x0a)) ; Either EOF or LF
+ :collecting (code-char b) :into result
+ :finally (return
+ (values
+ (parse-integer (coerce result 'string))))))))
+
+(defimplementation lisp-implementation-type-name ()
+ "armedbear")
+
+(defimplementation set-default-directory (directory)
+ (let ((dir (sys::probe-directory directory)))
+ (when dir (setf *default-pathname-defaults* dir))
+ (namestring dir)))
+
+
+;;;; Misc
+
+(defimplementation arglist (fun)
+ (cond ((symbolp fun)
+ (multiple-value-bind (arglist present) (sys::arglist fun)
+ (if present arglist :not-available)))
+ (t :not-available)))
+
+(defimplementation function-name (function)
+ (nth-value 2 (function-lambda-expression function)))
+
+(defimplementation macroexpand-all (form)
+ (macroexpand form))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (flet ((doc (kind &optional (sym symbol))
+ (or (documentation sym kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (when (boundp symbol)
+ (doc 'variable)))
+ (maybe-push
+ :function (if (fboundp symbol)
+ (doc 'function)))
+ (maybe-push
+ :class (if (find-class symbol nil)
+ (doc 'class)))
+ result)))
+
+
+(defimplementation describe-definition (symbol namespace)
+ (ecase namespace
+ (:variable
+ (describe symbol))
+ ((:function :generic-function)
+ (describe (symbol-function symbol)))
+ (:class
+ (describe (find-class symbol)))))
+
+(defimplementation describe-definition (symbol namespace)
+ (ecase namespace
+ (:variable
+ (describe symbol))
+ ((:function :generic-function)
+ (describe (symbol-function symbol)))
+ (:class
+ (describe (find-class symbol)))))
+
+
+;;;; Debugger
+
+(defvar *sldb-topframe*)
+
+(defun backtrace-as-list-ignoring-swank-calls ()
+ (let ((list (ext:backtrace-as-list)))
+ (subseq list (1+ (or (position (intern "SWANK-DEBUGGER-HOOK" 'swank) list :key 'car) -1)))))
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (let ((*sldb-topframe* (car (backtrace-as-list-ignoring-swank-calls)) #+nil (excl::int-newest-frame)))
+ (funcall debugger-loop-fn)))
+
+(defun nth-frame (index)
+ (nth index (backtrace-as-list-ignoring-swank-calls)))
+
+(defimplementation compute-backtrace (start end)
+ (let ((end (or end most-positive-fixnum)))
+ (subseq (backtrace-as-list-ignoring-swank-calls) start end)))
+
+(defimplementation print-frame (frame stream)
+ (write-string (string-trim '(#\space #\newline)
+ (prin1-to-string frame))
+ stream))
+
+(defimplementation frame-locals (index)
+ `(,(list :name "??" :id 0 :value "??")))
+
+
+(defimplementation frame-catch-tags (index)
+ (declare (ignore index))
+ nil)
+
+#+nil
+(defimplementation disassemble-frame (index)
+ (disassemble (debugger:frame-function (nth-frame index))))
+
+(defimplementation frame-source-location-for-emacs (index)
+ (list :error (format nil "Cannot find source for frame: ~A"
+ (nth-frame index))))
+
+#+nil
+(defimplementation eval-in-frame (form frame-number)
+ (debugger:eval-form-in-context
+ form
+ (debugger:environment-of-frame (nth-frame frame-number))))
+
+#+nil
+(defimplementation return-from-frame (frame-number form)
+ (let ((frame (nth-frame frame-number)))
+ (multiple-value-call #'debugger:frame-return
+ frame (debugger:eval-form-in-context
+ form
+ (debugger:environment-of-frame frame)))))
+
+;;; XXX doesn't work for frames with arguments
+#+nil
+(defimplementation restart-frame (frame-number)
+ (let ((frame (nth-frame frame-number)))
+ (debugger:frame-retry frame (debugger:frame-function frame))))
+
+;;;; Compiler hooks
+
+(defvar *buffer-name* nil)
+(defvar *buffer-start-position*)
+(defvar *buffer-string*)
+(defvar *compile-filename*)
+
+(in-package :swank-backend)
+
+(defun handle-compiler-warning (condition)
+ (let ((loc nil));(getf (slot-value condition 'excl::plist) :loc)))
+ (unless (member condition *abcl-signaled-conditions*) ; filter condition signaled more than once.
+ (push condition *abcl-signaled-conditions*)
+ (signal (make-condition
+ 'compiler-condition
+ :original-condition condition
+ :severity :warning
+ :message (format nil "~A" condition)
+ :location (cond (*buffer-name*
+ (make-location
+ (list :buffer *buffer-name*)
+ (list :position *buffer-start-position*)))
+ (loc
+ (destructuring-bind (file . pos) loc
+ (make-location
+ (list :file (namestring (truename file)))
+ (list :position (1+ pos)))))
+ (t
+ (make-location
+ (list :file *compile-filename*)
+ (list :position 1)))))))))
+
+(defvar *abcl-signaled-conditions*)
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (declare (ignore external-format))
+ (let ((jvm::*resignal-compiler-warnings* t)
+ (*abcl-signaled-conditions* nil))
+ (handler-bind ((warning #'handle-compiler-warning))
+ (let ((*buffer-name* nil)
+ (*compile-filename* filename))
+ (multiple-value-bind (fn warn fail) (compile-file filename)
+ (when (and load-p (not fail))
+ (load fn)))))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (let ((jvm::*resignal-compiler-warnings* t)
+ (*abcl-signaled-conditions* nil))
+ (handler-bind ((warning #'handle-compiler-warning))
+ (let ((*buffer-name* buffer)
+ (*buffer-start-position* position)
+ (*buffer-string* string))
+ (funcall (compile nil (read-from-string
+ (format nil "(~S () ~A)" 'lambda string))))))))
+
+#|
+;;;; Definition Finding
+
+(defun find-fspec-location (fspec type)
+ (let ((file (excl::fspec-pathname fspec type)))
+ (etypecase file
+ (pathname
+ (let ((start (scm:find-definition-in-file fspec type file)))
+ (make-location (list :file (namestring (truename file)))
+ (if start
+ (list :position (1+ start))
+ (list :function-name (string fspec))))))
+ ((member :top-level)
+ (list :error (format nil "Defined at toplevel: ~A" fspec)))
+ (null
+ (list :error (format nil "Unkown source location for ~A" fspec))))))
+
+(defun fspec-definition-locations (fspec)
+ (let ((defs (excl::find-multiple-definitions fspec)))
+ (loop for (fspec type) in defs
+ collect (list fspec (find-fspec-location fspec type)))))
+
+(defimplementation find-definitions (symbol)
+ (fspec-definition-locations symbol))
+
+|#
+
+(defun source-location (symbol)
+ (when (pathnamep (ext:source-pathname symbol))
+ `(((,symbol)
+ (:location
+ (:file ,(namestring (ext:source-pathname symbol)))
+ (:position ,(or (ext:source-file-position symbol) 0) t)
+ (:snippet nil))))))
+
+
+(defimplementation find-definitions (symbol)
+ (source-location symbol))
+
+#|
+Uncomment this if you have patched xref.lisp, as in
+http://article.gmane.org/gmane.lisp.slime.devel/2425
+Also, make sure that xref.lisp is loaded by modifying the armedbear
+part of *sysdep-pathnames* in swank.loader.lisp.
+
+;;;; XREF
+(setq pxref:*handle-package-forms* '(cl:in-package))
+
+(defmacro defxref (name function)
+ `(defimplementation ,name (name)
+ (xref-results (,function name))))
+
+(defxref who-calls pxref:list-callers)
+(defxref who-references pxref:list-readers)
+(defxref who-binds pxref:list-setters)
+(defxref who-sets pxref:list-setters)
+(defxref list-callers pxref:list-callers)
+(defxref list-callees pxref:list-callees)
+
+(defun xref-results (symbols)
+ (let ((xrefs '()))
+ (dolist (symbol symbols)
+ (push (list symbol (cadar (source-location symbol))) xrefs))
+ xrefs))
+|#
+
+;;;; Inspecting
+
+(defclass abcl-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'abcl-inspector))
+
+(defmethod inspect-for-emacs ((slot mop::slot-definition)
+ (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values "A slot."
+ `("Name: " (:value ,(mop::%slot-definition-name slot))
+ (:newline)
+ "Documentation:" (:newline)
+ ,@(when (slot-definition-documentation slot)
+ `((:value ,(slot-definition-documentation slot)) (:newline)))
+ "Initialization:" (:newline)
+ " Args: " (:value ,(mop::%slot-definition-initargs slot)) (:newline)
+ " Form: " ,(if (mop::%slot-definition-initfunction slot)
+ `(:value ,(mop::%slot-definition-initform slot))
+ "#<unspecified>") (:newline)
+ " Function: " (:value ,(mop::%slot-definition-initfunction slot))
+ (:newline))))
+
+(defmethod inspect-for-emacs ((f function) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values "A function."
+ `(,@(when (function-name f)
+ `("Name: "
+ ,(princ-to-string (function-name f)) (:newline)))
+ ,@(multiple-value-bind (args present)
+ (sys::arglist f)
+ (when present `("Argument list: " ,(princ-to-string args) (:newline))))
+ (:newline)
+ #+nil,@(when (documentation f t)
+ `("Documentation:" (:newline) ,(documentation f t) (:newline)))
+ ,@(when (function-lambda-expression f)
+ `("Lambda expression:"
+ (:newline) ,(princ-to-string (function-lambda-expression f)) (:newline))))))
+
+#|
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (let* ((class (class-of o))
+ (slots (mop::class-slots class)))
+ (values (format nil "~A~% is a ~A" o class)
+ (mapcar (lambda (slot)
+ (let ((name (mop::slot-definition-name slot)))
+ (cons (princ-to-string name)
+ (slot-value o name))))
+ slots))))
+|#
+
+;;;; Multithreading
+
+(defimplementation startup-multiprocessing ()
+ #+nil(mp:start-scheduler))
+
+(defimplementation spawn (fn &key name)
+ (ext:make-thread (lambda () (funcall fn)) :name name))
+
+(defvar *thread-props-lock* (ext:make-thread-lock))
+
+(defvar *thread-props* (make-hash-table) ; should be a weak table
+ "A hashtable mapping threads to a plist.")
+
+(defvar *thread-id-counter* 0)
+
+(defimplementation thread-id (thread)
+ (ext:with-thread-lock (*thread-props-lock*)
+ (or (getf (gethash thread *thread-props*) 'id)
+ (setf (getf (gethash thread *thread-props*) 'id)
+ (incf *thread-id-counter*)))))
+
+(defimplementation find-thread (id)
+ (find id (all-threads)
+ :key (lambda (thread)
+ (getf (gethash thread *thread-props*) 'id))))
+
+(defimplementation thread-name (thread)
+ (ext:thread-name thread))
+
+(defimplementation thread-status (thread)
+ (format nil "Thread is ~:[dead~;alive~]" (ext:thread-alive-p thread)))
+
+(defimplementation make-lock (&key name)
+ (ext:make-thread-lock))
+
+(defimplementation call-with-lock-held (lock function)
+ (ext:with-thread-lock (lock) (funcall function)))
+
+(defimplementation current-thread ()
+ (ext:current-thread))
+
+(defimplementation all-threads ()
+ (copy-list (ext:mapcar-threads #'identity)))
+
+(defimplementation interrupt-thread (thread fn)
+ (ext:interrupt-thread thread fn))
+
+(defimplementation kill-thread (thread)
+ (ext:destroy-thread thread))
+
+(defun mailbox (thread)
+ "Return THREAD's mailbox."
+ (ext:with-thread-lock (*thread-props-lock*)
+ (or (getf (gethash thread *thread-props*) 'mailbox)
+ (setf (getf (gethash thread *thread-props*) 'mailbox)
+ (ext:make-mailbox)))))
+
+(defimplementation send (thread object)
+ (ext:mailbox-send (mailbox thread) object))
+
+(defimplementation receive ()
+ (ext:mailbox-read (mailbox (ext:current-thread))))
+
+;;; Auto-flush streams
+
+;; XXX race conditions
+(defvar *auto-flush-streams* '())
+
+(defvar *auto-flush-thread* nil)
+
+(defimplementation make-stream-interactive (stream)
+ (setq *auto-flush-streams* (adjoin stream *auto-flush-streams*))
+ (unless *auto-flush-thread*
+ (setq *auto-flush-thread*
+ (ext:make-thread #'flush-streams
+ :name "auto-flush-thread"))))
+
+(defun flush-streams ()
+ (loop
+ (setq *auto-flush-streams*
+ (remove-if (lambda (x)
+ (not (and (open-stream-p x)
+ (output-stream-p x))))
+ *auto-flush-streams*))
+ (mapc #'finish-output *auto-flush-streams*)
+ (sleep 0.15)))
+
+(defimplementation quit-lisp ()
+ (ext:exit))
+
+;; WORKAROUND: call/initialize accessors at load time
+(let ((c (make-condition 'compiler-condition
+ :original-condition nil
+ :severity ':note :message "" :location nil))
+ (slots `(severity message short-message references location)))
+ (dolist (slot slots)
+ (funcall slot c)))
Added: branches/bos/thirdparty/emacs/slime/swank-allegro.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-allegro.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,774 @@
+;;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;* "; -*-
+;;;
+;;; swank-allegro.lisp --- Allegro CL specific code for SLIME.
+;;;
+;;; Created 2003
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+(in-package :swank-backend)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (require :sock)
+ (require :process))
+
+(import-from :excl *gray-stream-symbols* :swank-backend)
+
+;;; swank-mop
+
+(import-swank-mop-symbols :clos '(:slot-definition-documentation))
+
+(defun swank-mop:slot-definition-documentation (slot)
+ (documentation slot t))
+
+
+;;;; TCP Server
+
+(defimplementation preferred-communication-style ()
+ :spawn)
+
+(defimplementation create-socket (host port)
+ (socket:make-socket :connect :passive :local-port port
+ :local-host host :reuse-address t))
+
+(defimplementation local-port (socket)
+ (socket:local-port socket))
+
+(defimplementation close-socket (socket)
+ (close socket))
+
+(defimplementation accept-connection (socket &key external-format buffering
+ timeout)
+ (declare (ignore buffering timeout))
+ (let ((s (socket:accept-connection socket :wait t)))
+ (when external-format
+ (setf (stream-external-format s) external-format))
+ s))
+
+(defvar *external-format-to-coding-system*
+ '((:iso-8859-1
+ "latin-1" "latin-1-unix" "iso-latin-1-unix"
+ "iso-8859-1" "iso-8859-1-unix")
+ (:utf-8 "utf-8" "utf-8-unix")
+ (:euc-jp "euc-jp" "euc-jp-unix")
+ (:us-ascii "us-ascii" "us-ascii-unix")
+ (:emacs-mule "emacs-mule" "emacs-mule-unix")))
+
+(defimplementation find-external-format (coding-system)
+ (let ((e (rassoc-if (lambda (x) (member coding-system x :test #'equal))
+ *external-format-to-coding-system*)))
+ (and e (excl:crlf-base-ef
+ (excl:find-external-format (car e)
+ :try-variant t)))))
+
+(defimplementation format-sldb-condition (c)
+ (princ-to-string c))
+
+(defimplementation call-with-syntax-hooks (fn)
+ (funcall fn))
+
+;;;; Unix signals
+
+(defimplementation call-without-interrupts (fn)
+ (excl:without-interrupts (funcall fn)))
+
+(defimplementation getpid ()
+ (excl::getpid))
+
+(defimplementation lisp-implementation-type-name ()
+ "allegro")
+
+(defimplementation set-default-directory (directory)
+ (let* ((dir (namestring (truename (merge-pathnames directory)))))
+ (setf *default-pathname-defaults* (pathname (excl:chdir dir)))
+ dir))
+
+(defimplementation default-directory ()
+ (namestring (excl:current-directory)))
+
+;;;; Misc
+
+(defimplementation arglist (symbol)
+ (handler-case (excl:arglist symbol)
+ (simple-error () :not-available)))
+
+(defimplementation macroexpand-all (form)
+ (excl::walk form))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (flet ((doc (kind &optional (sym symbol))
+ (or (documentation sym kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (when (boundp symbol)
+ (doc 'variable)))
+ (maybe-push
+ :function (if (fboundp symbol)
+ (doc 'function)))
+ (maybe-push
+ :class (if (find-class symbol nil)
+ (doc 'class)))
+ result)))
+
+(defimplementation describe-definition (symbol namespace)
+ (ecase namespace
+ (:variable
+ (describe symbol))
+ ((:function :generic-function)
+ (describe (symbol-function symbol)))
+ (:class
+ (describe (find-class symbol)))))
+
+(defimplementation make-stream-interactive (stream)
+ (setf (interactive-stream-p stream) t))
+
+;;;; Debugger
+
+(defvar *sldb-topframe*)
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (let ((*sldb-topframe* (find-topframe))
+ (excl::*break-hook* nil))
+ (funcall debugger-loop-fn)))
+
+(defimplementation sldb-break-at-start (fname)
+ ;; :print-before is kind of mis-used but we just want to stuff our break form
+ ;; somewhere. This does not work for setf, :before and :after methods, which
+ ;; need special syntax in the trace call, see ACL's doc/debugging.htm chapter 10.
+ (eval `(trace (,fname
+ :print-before
+ ((break "Function start breakpoint of ~A" ',fname)))))
+ `(:ok ,(format nil "Set breakpoint at start of ~S" fname)))
+
+(defun find-topframe ()
+ (let ((skip-frames 3))
+ (do ((f (excl::int-newest-frame) (next-frame f))
+ (i 0 (1+ i)))
+ ((= i skip-frames) f))))
+
+(defun next-frame (frame)
+ (let ((next (excl::int-next-older-frame frame)))
+ (cond ((not next) nil)
+ ((debugger:frame-visible-p next) next)
+ (t (next-frame next)))))
+
+(defun nth-frame (index)
+ (do ((frame *sldb-topframe* (next-frame frame))
+ (i index (1- i)))
+ ((zerop i) frame)))
+
+(defimplementation compute-backtrace (start end)
+ (let ((end (or end most-positive-fixnum)))
+ (loop for f = (nth-frame start) then (next-frame f)
+ for i from start below end
+ while f
+ collect f)))
+
+(defimplementation print-frame (frame stream)
+ (debugger:output-frame stream frame :moderate))
+
+(defimplementation frame-locals (index)
+ (let ((frame (nth-frame index)))
+ (loop for i from 0 below (debugger:frame-number-vars frame)
+ collect (list :name (debugger:frame-var-name frame i)
+ :id 0
+ :value (debugger:frame-var-value frame i)))))
+
+(defimplementation frame-var-value (frame var)
+ (let ((frame (nth-frame frame)))
+ (debugger:frame-var-value frame var)))
+
+(defimplementation frame-catch-tags (index)
+ (declare (ignore index))
+ nil)
+
+(defimplementation disassemble-frame (index)
+ (disassemble (debugger:frame-function (nth-frame index))))
+
+(defimplementation frame-source-location-for-emacs (index)
+ (let* ((frame (nth-frame index))
+ (expr (debugger:frame-expression frame))
+ (fspec (first expr)))
+ (second (first (fspec-definition-locations fspec)))))
+
+(defimplementation eval-in-frame (form frame-number)
+ (let ((frame (nth-frame frame-number)))
+ ;; let-bind lexical variables
+ (let ((vars (loop for i below (debugger:frame-number-vars frame)
+ for name = (debugger:frame-var-name frame i)
+ if (symbolp name)
+ collect `(,name ',(debugger:frame-var-value frame i)))))
+ (debugger:eval-form-in-context
+ `(let* ,vars ,form)
+ (debugger:environment-of-frame frame)))))
+
+(defimplementation return-from-frame (frame-number form)
+ (let ((frame (nth-frame frame-number)))
+ (multiple-value-call #'debugger:frame-return
+ frame (debugger:eval-form-in-context
+ form
+ (debugger:environment-of-frame frame)))))
+
+(defimplementation restart-frame (frame-number)
+ (let ((frame (nth-frame frame-number)))
+ (cond ((debugger:frame-retryable-p frame)
+ (apply #'debugger:frame-retry frame (debugger:frame-function frame)
+ (cdr (debugger:frame-expression frame))))
+ (t "Frame is not retryable"))))
+
+;;;; Compiler hooks
+
+(defvar *buffer-name* nil)
+(defvar *buffer-start-position*)
+(defvar *buffer-string*)
+(defvar *compile-filename* nil)
+
+(defun compiler-note-p (object)
+ (member (type-of object) '(excl::compiler-note compiler::compiler-note)))
+
+(defun compiler-undefined-functions-called-warning-p (object)
+ (typep object 'excl:compiler-undefined-functions-called-warning))
+
+(deftype compiler-note ()
+ `(satisfies compiler-note-p))
+
+(defun signal-compiler-condition (&rest args)
+ (signal (apply #'make-condition 'compiler-condition args)))
+
+(defun handle-compiler-warning (condition)
+ (declare (optimize (debug 3) (speed 0) (space 0)))
+ (cond ((and (not *buffer-name*)
+ (compiler-undefined-functions-called-warning-p condition))
+ (handle-undefined-functions-warning condition))
+ (t
+ (signal-compiler-condition
+ :original-condition condition
+ :severity (etypecase condition
+ (warning :warning)
+ (compiler-note :note))
+ :message (format nil "~A" condition)
+ :location (location-for-warning condition)))))
+
+(defun location-for-warning (condition)
+ (let ((loc (getf (slot-value condition 'excl::plist) :loc)))
+ (cond (*buffer-name*
+ (make-location
+ (list :buffer *buffer-name*)
+ (list :position *buffer-start-position*)))
+ (loc
+ (destructuring-bind (file . pos) loc
+ (make-location
+ (list :file (namestring (truename file)))
+ (list :position (1+ pos)))))
+ (t
+ (list :error "No error location available.")))))
+
+(defun handle-undefined-functions-warning (condition)
+ (let ((fargs (slot-value condition 'excl::format-arguments)))
+ (loop for (fname . pos-file) in (car fargs) do
+ (loop for (pos file) in pos-file do
+ (signal-compiler-condition
+ :original-condition condition
+ :severity :warning
+ :message (format nil "Undefined function referenced: ~S"
+ fname)
+ :location (make-location (list :file file)
+ (list :position (1+ pos))))))))
+
+(defimplementation call-with-compilation-hooks (function)
+ (handler-bind ((warning #'handle-compiler-warning)
+ ;;(compiler-note #'handle-compiler-warning)
+ )
+ (funcall function)))
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (with-compilation-hooks ()
+ (let ((*buffer-name* nil)
+ (*compile-filename* filename))
+ (compile-file *compile-filename* :load-after-compile load-p
+ :external-format external-format))))
+
+(defun call-with-temp-file (fn)
+ (let ((tmpname (system:make-temp-file-name)))
+ (unwind-protect
+ (with-open-file (file tmpname :direction :output :if-exists :error)
+ (funcall fn file tmpname))
+ (delete-file tmpname))))
+
+(defun compile-from-temp-file (string)
+ (call-with-temp-file
+ (lambda (stream filename)
+ (write-string string stream)
+ (finish-output stream)
+ (let ((binary-filename
+ (excl:without-redefinition-warnings
+ ;; Suppress Allegro's redefinition warnings; they are
+ ;; pointless when we are compiling via a temporary
+ ;; file.
+ (compile-file filename :load-after-compile t))))
+ (when binary-filename
+ (delete-file binary-filename))))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ ;; We store the source buffer in excl::*source-pathname* as a string
+ ;; of the form <buffername>;<start-offset>. Quite ugly encoding, but
+ ;; the fasl file is corrupted if we use some other datatype.
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-start-position* position)
+ (*buffer-string* string)
+ (*default-pathname-defaults*
+ (if directory (merge-pathnames (pathname directory))
+ *default-pathname-defaults*)))
+ (compile-from-temp-file
+ (format nil "~S ~S~%~A"
+ `(in-package ,(package-name *package*))
+ `(eval-when (:compile-toplevel :load-toplevel)
+ (setq excl::*source-pathname*
+ ',(format nil "~A;~D" buffer position)))
+ string)))))
+
+;;;; Definition Finding
+
+(defun fspec-primary-name (fspec)
+ (etypecase fspec
+ (symbol fspec)
+ (list (fspec-primary-name (second fspec)))))
+
+;; If Emacs uses DOS-style eol conventions, \n\r are considered as a
+;; single character, but file-position counts them as two. Here we do
+;; our own conversion.
+(defun count-cr (file pos)
+ (let* ((bufsize 256)
+ (type '(unsigned-byte 8))
+ (buf (make-array bufsize :element-type type))
+ (cr-count 0))
+ (with-open-file (stream file :direction :input :element-type type)
+ (loop for bytes-read = (read-sequence buf stream) do
+ (incf cr-count (count (char-code #\return) buf
+ :end (min pos bytes-read)))
+ (decf pos bytes-read)
+ (when (<= pos 0)
+ (return cr-count))))))
+
+(defun find-definition-in-file (fspec type file top-level)
+ (let* ((part
+ (or (scm::find-definition-in-definition-group
+ fspec type (scm:section-file :file file)
+ :top-level top-level)
+ (scm::find-definition-in-definition-group
+ (fspec-primary-name fspec)
+ type (scm:section-file :file file)
+ :top-level top-level)))
+ (start (and part
+ (scm::source-part-start part)))
+ (pos (if start
+ (list :position (1+ (- start (count-cr file start))))
+ (list :function-name (string (fspec-primary-name fspec))))))
+ (make-location (list :file (namestring (truename file)))
+ pos)))
+
+(defun find-definition-in-buffer (filename)
+ (let ((pos (position #\; filename :from-end t)))
+ (make-location
+ (list :buffer (subseq filename 0 pos))
+ (list :position (parse-integer (subseq filename (1+ pos)))))))
+
+(defun find-fspec-location (fspec type file top-level)
+ (etypecase file
+ (pathname
+ (find-definition-in-file fspec type file top-level))
+ ((member :top-level)
+ (list :error (format nil "Defined at toplevel: ~A"
+ (fspec->string fspec))))
+ (string
+ (find-definition-in-buffer file))))
+
+(defun fspec->string (fspec)
+ (etypecase fspec
+ (symbol (let ((*package* (find-package :keyword)))
+ (prin1-to-string fspec)))
+ (list (format nil "(~A ~A)"
+ (prin1-to-string (first fspec))
+ (let ((*package* (find-package :keyword)))
+ (prin1-to-string (second fspec)))))))
+
+(defun fspec-definition-locations (fspec)
+ (cond
+ ((and (listp fspec)
+ (eql (car fspec) :top-level-form))
+ (destructuring-bind (top-level-form file &optional position) fspec
+ (list
+ (list (list nil fspec)
+ (make-location (list :buffer file)
+ (list :position position t))))))
+ ((and (listp fspec) (eq (car fspec) :internal))
+ (destructuring-bind (_internal next _n) fspec
+ (fspec-definition-locations next)))
+ (t
+ (let ((defs (excl::find-source-file fspec)))
+ (if (null defs)
+ (list
+ (list (list nil fspec)
+ (list :error
+ (format nil "Unknown source location for ~A"
+ (fspec->string fspec)))))
+ (loop for (fspec type file top-level) in defs
+ collect (list (list type fspec)
+ (find-fspec-location fspec type file top-level))))))))
+
+(defimplementation find-definitions (symbol)
+ (fspec-definition-locations symbol))
+
+;;;; XREF
+
+(defmacro defxref (name relation name1 name2)
+ `(defimplementation ,name (x)
+ (xref-result (xref:get-relation ,relation ,name1 ,name2))))
+
+(defxref who-calls :calls :wild x)
+(defxref calls-who :calls x :wild)
+(defxref who-references :uses :wild x)
+(defxref who-binds :binds :wild x)
+(defxref who-macroexpands :macro-calls :wild x)
+(defxref who-sets :sets :wild x)
+
+(defun xref-result (fspecs)
+ (loop for fspec in fspecs
+ append (fspec-definition-locations fspec)))
+
+;; list-callers implemented by groveling through all fbound symbols.
+;; Only symbols are considered. Functions in the constant pool are
+;; searched recursively. Closure environments are ignored at the
+;; moment (constants in methods are therefore not found).
+
+(defun map-function-constants (function fn depth)
+ "Call FN with the elements of FUNCTION's constant pool."
+ (do ((i 0 (1+ i))
+ (max (excl::function-constant-count function)))
+ ((= i max))
+ (let ((c (excl::function-constant function i)))
+ (cond ((and (functionp c)
+ (not (eq c function))
+ (plusp depth))
+ (map-function-constants c fn (1- depth)))
+ (t
+ (funcall fn c))))))
+
+(defun in-constants-p (fun symbol)
+ (map-function-constants fun
+ (lambda (c)
+ (when (eq c symbol)
+ (return-from in-constants-p t)))
+ 3))
+
+(defun function-callers (name)
+ (let ((callers '()))
+ (do-all-symbols (sym)
+ (when (fboundp sym)
+ (let ((fn (fdefinition sym)))
+ (when (in-constants-p fn name)
+ (push sym callers)))))
+ callers))
+
+(defimplementation list-callers (name)
+ (xref-result (function-callers name)))
+
+(defimplementation list-callees (name)
+ (let ((result '()))
+ (map-function-constants (fdefinition name)
+ (lambda (c)
+ (when (fboundp c)
+ (push c result)))
+ 2)
+ (xref-result result)))
+
+;;;; Profiling
+
+;; Per-function profiling based on description in
+;; http://www.franz.com/support/documentation/8.0/doc/runtime-analyzer.htm#data-collection-control-2
+
+(defvar *profiled-functions* ())
+(defvar *profile-depth* 0)
+
+(defmacro with-redirected-y-or-n-p (&body body)
+ ;; If the profiler is restarted when the data from the previous
+ ;; session is not reported yet, the user is warned via Y-OR-N-P.
+ ;; As the CL:Y-OR-N-P question is (for some reason) not directly
+ ;; sent to the Slime user, the function CL:Y-OR-N-P is temporarily
+ ;; overruled.
+ `(let* ((pkg (find-package "common-lisp"))
+ (saved-pdl (excl::package-definition-lock pkg))
+ (saved-ynp (symbol-function 'cl:y-or-n-p)))
+
+ (setf (excl::package-definition-lock pkg) nil
+ (symbol-function 'cl:y-or-n-p) (symbol-function
+ (find-symbol "y-or-n-p-in-emacs"
+ "swank")))
+ (unwind-protect
+ (progn , at body)
+
+ (setf (symbol-function 'cl:y-or-n-p) saved-ynp
+ (excl::package-definition-lock pkg) saved-pdl))))
+
+(defun start-acl-profiler ()
+ (with-redirected-y-or-n-p
+ (prof:start-profiler :type :time :count t
+ :start-sampling-p nil :verbose nil)))
+(defun acl-profiler-active-p ()
+ (not (eq (prof:profiler-status :verbose nil) :inactive)))
+
+(defun stop-acl-profiler ()
+ (prof:stop-profiler :verbose nil))
+
+(excl:def-fwrapper profile-fwrapper (&rest args)
+ ;; Ensures sampling is done during the execution of the function,
+ ;; taking into account recursion.
+ (declare (ignore args))
+ (cond ((zerop *profile-depth*)
+ (let ((*profile-depth* (1+ *profile-depth*)))
+ (prof:start-sampling)
+ (unwind-protect (excl:call-next-fwrapper)
+ (prof:stop-sampling))))
+ (t
+ (excl:call-next-fwrapper))))
+
+(defimplementation profile (fname)
+ (unless (acl-profiler-active-p)
+ (start-acl-profiler))
+ (excl:fwrap fname 'profile-fwrapper 'profile-fwrapper)
+ (push fname *profiled-functions*))
+
+(defimplementation profiled-functions ()
+ *profiled-functions*)
+
+(defimplementation unprofile (fname)
+ (excl:funwrap fname 'profile-fwrapper)
+ (setq *profiled-functions* (remove fname *profiled-functions*)))
+
+(defimplementation profile-report ()
+ (prof:show-flat-profile :verbose nil)
+ (when *profiled-functions*
+ (start-acl-profiler)))
+
+(defimplementation profile-reset ()
+ (when (acl-profiler-active-p)
+ (stop-acl-profiler)
+ (start-acl-profiler))
+ "Reset profiling counters.")
+
+;;;; Inspecting
+
+(defclass acl-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'acl-inspector))
+
+(defmethod inspect-for-emacs ((f function) inspector)
+ inspector
+ (values "A function."
+ (append
+ (label-value-line "Name" (function-name f))
+ `("Formals" ,(princ-to-string (arglist f)) (:newline))
+ (let ((doc (documentation (excl::external-fn_symdef f) 'function)))
+ (when doc
+ `("Documentation:" (:newline) ,doc))))))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ inspector
+ (values "A value." (allegro-inspect o)))
+
+(defmethod inspect-for-emacs ((o function) (inspector backend-inspector))
+ inspector
+ (values "A function." (allegro-inspect o)))
+
+(defmethod inspect-for-emacs ((o standard-object)
+ (inspector backend-inspector))
+ inspector
+ (values (format nil "~A is a standard-object." o) (allegro-inspect o)))
+
+(defun allegro-inspect (o)
+ (loop for (d dd) on (inspect::inspect-ctl o)
+ append (frob-allegro-field-def o d)
+ until (eq d dd)))
+
+(defun frob-allegro-field-def (object def)
+ (with-struct (inspect::field-def- name type access) def
+ (ecase type
+ ((:unsigned-word :unsigned-byte :unsigned-natural
+ :unsigned-long :unsigned-half-long
+ :unsigned-3byte)
+ (label-value-line name (inspect::component-ref-v object access type)))
+ ((:lisp :value)
+ (label-value-line name (inspect::component-ref object access)))
+ (:indirect
+ (destructuring-bind (prefix count ref set) access
+ (declare (ignore set prefix))
+ (loop for i below (funcall count object)
+ append (label-value-line (format nil "~A-~D" name i)
+ (funcall ref object i))))))))
+
+;;;; Multithreading
+
+(defimplementation initialize-multiprocessing (continuation)
+ (mp:start-scheduler)
+ (funcall continuation))
+
+(defimplementation spawn (fn &key name)
+ (mp:process-run-function name fn))
+
+(defvar *id-lock* (mp:make-process-lock :name "id lock"))
+(defvar *thread-id-counter* 0)
+
+(defimplementation thread-id (thread)
+ (mp:with-process-lock (*id-lock*)
+ (or (getf (mp:process-property-list thread) 'id)
+ (setf (getf (mp:process-property-list thread) 'id)
+ (incf *thread-id-counter*)))))
+
+(defimplementation find-thread (id)
+ (find id mp:*all-processes*
+ :key (lambda (p) (getf (mp:process-property-list p) 'id))))
+
+(defimplementation thread-name (thread)
+ (mp:process-name thread))
+
+(defimplementation thread-status (thread)
+ (format nil "~A ~D" (mp:process-whostate thread)
+ (mp:process-priority thread)))
+
+(defimplementation make-lock (&key name)
+ (mp:make-process-lock :name name))
+
+(defimplementation call-with-lock-held (lock function)
+ (mp:with-process-lock (lock) (funcall function)))
+
+(defimplementation current-thread ()
+ mp:*current-process*)
+
+(defimplementation all-threads ()
+ (copy-list mp:*all-processes*))
+
+(defimplementation interrupt-thread (thread fn)
+ (mp:process-interrupt thread fn))
+
+(defimplementation kill-thread (thread)
+ (mp:process-kill thread))
+
+(defvar *mailbox-lock* (mp:make-process-lock :name "mailbox lock"))
+
+(defstruct (mailbox (:conc-name mailbox.))
+ (mutex (mp:make-process-lock :name "process mailbox"))
+ (queue '() :type list))
+
+(defun mailbox (thread)
+ "Return THREAD's mailbox."
+ (mp:with-process-lock (*mailbox-lock*)
+ (or (getf (mp:process-property-list thread) 'mailbox)
+ (setf (getf (mp:process-property-list thread) 'mailbox)
+ (make-mailbox)))))
+
+(defimplementation send (thread message)
+ (let* ((mbox (mailbox thread))
+ (mutex (mailbox.mutex mbox)))
+ (mp:process-wait-with-timeout
+ "yielding before sending" 0.1
+ (lambda ()
+ (mp:with-process-lock (mutex)
+ (< (length (mailbox.queue mbox)) 10))))
+ (mp:with-process-lock (mutex)
+ (setf (mailbox.queue mbox)
+ (nconc (mailbox.queue mbox) (list message))))))
+
+(defimplementation receive ()
+ (let* ((mbox (mailbox mp:*current-process*))
+ (mutex (mailbox.mutex mbox)))
+ (mp:process-wait "receive" #'mailbox.queue mbox)
+ (mp:with-process-lock (mutex)
+ (pop (mailbox.queue mbox)))))
+
+(defimplementation quit-lisp ()
+ (excl:exit 0 :quiet t))
+
+
+;;Trace implementations
+;;In Allegro 7.0, we have:
+;; (trace <name>)
+;; (trace ((method <name> <qualifier>? (<specializer>+))))
+;; (trace ((labels <name> <label-name>)))
+;; (trace ((labels (method <name> (<specializer>+)) <label-name>)))
+;; <name> can be a normal name or a (setf name)
+
+(defimplementation toggle-trace (spec)
+ (ecase (car spec)
+ ((setf)
+ (toggle-trace-aux spec))
+ (:defgeneric (toggle-trace-generic-function-methods (second spec)))
+ ((setf :defmethod :labels :flet)
+ (toggle-trace-aux (process-fspec-for-allegro spec)))
+ (:call
+ (destructuring-bind (caller callee) (cdr spec)
+ (toggle-trace-aux callee
+ :inside (list (process-fspec-for-allegro caller)))))))
+
+(defun tracedp (fspec)
+ (member fspec (eval '(trace)) :test #'equal))
+
+(defun toggle-trace-aux (fspec &rest args)
+ (cond ((tracedp fspec)
+ (eval `(untrace ,fspec))
+ (format nil "~S is now untraced." fspec))
+ (t
+ (eval `(trace (,fspec , at args)))
+ (format nil "~S is now traced." fspec))))
+
+(defun toggle-trace-generic-function-methods (name)
+ (let ((methods (mop:generic-function-methods (fdefinition name))))
+ (cond ((tracedp name)
+ (eval `(untrace ,name))
+ (dolist (method methods (format nil "~S is now untraced." name))
+ (excl:funtrace (mop:method-function method))))
+ (t
+ (eval `(trace (,name)))
+ (dolist (method methods (format nil "~S is now traced." name))
+ (excl:ftrace (mop:method-function method)))))))
+
+(defun process-fspec-for-allegro (fspec)
+ (cond ((consp fspec)
+ (ecase (first fspec)
+ ((setf) fspec)
+ ((:defun :defgeneric) (second fspec))
+ ((:defmethod) `(method ,@(rest fspec)))
+ ((:labels) `(labels ,(process-fspec-for-allegro (second fspec))
+ ,(third fspec)))
+ ((:flet) `(flet ,(process-fspec-for-allegro (second fspec))
+ ,(third fspec)))))
+ (t
+ fspec)))
+
+
+;;;; Weak hashtables
+
+(defimplementation make-weak-key-hash-table (&rest args)
+ (apply #'make-hash-table :weak-keys t args))
+
+(defimplementation make-weak-value-hash-table (&rest args)
+ (apply #'make-hash-table :values :weak args))
+
+(defimplementation hash-table-weakness (hashtable)
+ (cond ((excl:hash-table-weak-keys hashtable) :key)
+ ((eq (excl:hash-table-values hashtable) :weak) :value)))
+
+
+
+;;;; Character names
+
+(defimplementation character-completion-set (prefix matchp)
+ (loop for name being the hash-keys of excl::*name-to-char-table*
+ when (funcall matchp prefix name)
+ collect (string-capitalize name)))
Added: branches/bos/thirdparty/emacs/slime/swank-backend.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-backend.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,1077 @@
+;;; -*- Mode: lisp; indent-tabs-mode: nil; outline-regexp: ";;;;;*" -*-
+;;;
+;;; slime-backend.lisp --- SLIME backend interface.
+;;;
+;;; Created by James Bielman in 2003. Released into the public domain.
+;;;
+;;;; Frontmatter
+;;;
+;;; This file defines the functions that must be implemented
+;;; separately for each Lisp. Each is declared as a generic function
+;;; for which swank-<implementation>.lisp provides methods.
+
+(defpackage :swank-backend
+ (:use :common-lisp)
+ (:export #:sldb-condition
+ #:original-condition
+ #:compiler-condition
+ #:message
+ #:short-message
+ #:condition
+ #:severity
+ #:with-compilation-hooks
+ #:location
+ #:location-p
+ #:location-buffer
+ #:location-position
+ #:position-p
+ #:position-pos
+ #:print-output-to-string
+ #:quit-lisp
+ #:references
+ #:unbound-slot-filler
+ #:declaration-arglist
+ #:type-specifier-arglist
+ ;; inspector related symbols
+ #:inspector
+ #:backend-inspector
+ #:inspect-for-emacs
+ #:raw-inspection
+ #:fancy-inspection
+ #:label-value-line
+ #:label-value-line*
+ #:with-struct
+ ))
+
+(defpackage :swank-mop
+ (:use)
+ (:export
+ ;; classes
+ #:standard-generic-function
+ #:standard-slot-definition
+ #:standard-method
+ #:standard-class
+ #:eql-specializer
+ #:eql-specializer-object
+ ;; standard-class readers
+ #:class-default-initargs
+ #:class-direct-default-initargs
+ #:class-direct-slots
+ #:class-direct-subclasses
+ #:class-direct-superclasses
+ #:class-finalized-p
+ #:class-name
+ #:class-precedence-list
+ #:class-prototype
+ #:class-slots
+ #:specializer-direct-methods
+ ;; generic function readers
+ #:generic-function-argument-precedence-order
+ #:generic-function-declarations
+ #:generic-function-lambda-list
+ #:generic-function-methods
+ #:generic-function-method-class
+ #:generic-function-method-combination
+ #:generic-function-name
+ ;; method readers
+ #:method-generic-function
+ #:method-function
+ #:method-lambda-list
+ #:method-specializers
+ #:method-qualifiers
+ ;; slot readers
+ #:slot-definition-allocation
+ #:slot-definition-documentation
+ #:slot-definition-initargs
+ #:slot-definition-initform
+ #:slot-definition-initfunction
+ #:slot-definition-name
+ #:slot-definition-type
+ #:slot-definition-readers
+ #:slot-definition-writers
+ #:slot-boundp-using-class
+ #:slot-value-using-class
+ #:slot-makunbound-using-class
+ ;; generic function protocol
+ #:compute-applicable-methods-using-classes
+ #:finalize-inheritance))
+
+(in-package :swank-backend)
+
+
+;;;; Metacode
+
+(defparameter *interface-functions* '()
+ "The names of all interface functions.")
+
+(defparameter *unimplemented-interfaces* '()
+ "List of interface functions that are not implemented.
+DEFINTERFACE adds to this list and DEFIMPLEMENTATION removes.")
+
+(defmacro definterface (name args documentation &rest default-body)
+ "Define an interface function for the backend to implement.
+A function is defined with NAME, ARGS, and DOCUMENTATION. This
+function first looks for a function to call in NAME's property list
+that is indicated by 'IMPLEMENTATION; failing that, it looks for a
+function indicated by 'DEFAULT. If neither is present, an error is
+signaled.
+
+If a DEFAULT-BODY is supplied, then a function with the same body and
+ARGS will be added to NAME's property list as the property indicated
+by 'DEFAULT.
+
+Backends implement these functions using DEFIMPLEMENTATION."
+ (check-type documentation string "a documentation string")
+ (assert (every #'symbolp args) ()
+ "Complex lambda-list not supported: ~S ~S" name args)
+ (labels ((gen-default-impl ()
+ `(setf (get ',name 'default) (lambda ,args , at default-body)))
+ (args-as-list (args)
+ (destructuring-bind (req opt key rest) (parse-lambda-list args)
+ `(, at req , at opt
+ ,@(loop for k in key append `(,(kw k) ,k))
+ ,@(or rest '(())))))
+ (parse-lambda-list (args)
+ (parse args '(&optional &key &rest)
+ (make-array 4 :initial-element nil)))
+ (parse (args keywords vars)
+ (cond ((null args)
+ (reverse (map 'list #'reverse vars)))
+ ((member (car args) keywords)
+ (parse (cdr args) (cdr (member (car args) keywords)) vars))
+ (t (push (car args) (aref vars (length keywords)))
+ (parse (cdr args) keywords vars))))
+ (kw (s) (intern (string s) :keyword)))
+ `(progn
+ (defun ,name ,args
+ ,documentation
+ (let ((f (or (get ',name 'implementation)
+ (get ',name 'default))))
+ (cond (f (apply f ,@(args-as-list args)))
+ (t (error "~S not implementated" ',name)))))
+ (pushnew ',name *interface-functions*)
+ ,(if (null default-body)
+ `(pushnew ',name *unimplemented-interfaces*)
+ (gen-default-impl))
+ ;; see <http://www.franz.com/support/documentation/6.2/doc/pages/variables/compiler/s_cltl1-compile-file-toplevel-compatibility-p_s.htm>
+ (eval-when (:compile-toplevel :load-toplevel :execute)
+ (export ',name :swank-backend))
+ ',name)))
+
+(defmacro defimplementation (name args &body body)
+ (assert (every #'symbolp args) ()
+ "Complex lambda-list not supported: ~S ~S" name args)
+ `(progn
+ (setf (get ',name 'implementation) (lambda ,args , at body))
+ (if (member ',name *interface-functions*)
+ (setq *unimplemented-interfaces*
+ (remove ',name *unimplemented-interfaces*))
+ (warn "DEFIMPLEMENTATION of undefined interface (~S)" ',name))
+ ',name))
+
+(defun warn-unimplemented-interfaces ()
+ "Warn the user about unimplemented backend features.
+The portable code calls this function at startup."
+ (warn "These Swank interfaces are unimplemented:~% ~A"
+ (sort (copy-list *unimplemented-interfaces*) #'string<)))
+
+(defun import-to-swank-mop (symbol-list)
+ (dolist (sym symbol-list)
+ (let* ((swank-mop-sym (find-symbol (symbol-name sym) :swank-mop)))
+ (when swank-mop-sym
+ (unintern swank-mop-sym :swank-mop))
+ (import sym :swank-mop)
+ (export sym :swank-mop))))
+
+(defun import-swank-mop-symbols (package except)
+ "Import the mop symbols from PACKAGE to SWANK-MOP.
+EXCEPT is a list of symbol names which should be ignored."
+ (do-symbols (s :swank-mop)
+ (unless (member s except :test #'string=)
+ (let ((real-symbol (find-symbol (string s) package)))
+ (assert real-symbol () "Symbol ~A not found in package ~A" s package)
+ (unintern s :swank-mop)
+ (import real-symbol :swank-mop)
+ (export real-symbol :swank-mop)))))
+
+(defvar *gray-stream-symbols*
+ '(:fundamental-character-output-stream
+ :stream-write-char
+ :stream-fresh-line
+ :stream-force-output
+ :stream-finish-output
+ :fundamental-character-input-stream
+ :stream-read-char
+ :stream-listen
+ :stream-unread-char
+ :stream-clear-input
+ :stream-line-column
+ :stream-read-char-no-hang
+ ;; STREAM-LINE-LENGTH is an extension to gray streams that's apparently
+ ;; supported by CMUCL, OpenMCL, SBCL and SCL.
+ #+(or cmu openmcl sbcl scl)
+ :stream-line-length))
+
+(defun import-from (package symbol-names &optional (to-package *package*))
+ "Import the list of SYMBOL-NAMES found in the package PACKAGE."
+ (dolist (name symbol-names)
+ (multiple-value-bind (symbol found) (find-symbol (string name) package)
+ (assert found () "Symbol ~A not found in package ~A" name package)
+ (import symbol to-package))))
+
+
+;;;; Utilities
+
+(defmacro with-struct ((conc-name &rest names) obj &body body)
+ "Like with-slots but works only for structs."
+ (flet ((reader (slot) (intern (concatenate 'string
+ (symbol-name conc-name)
+ (symbol-name slot))
+ (symbol-package conc-name))))
+ (let ((tmp (gensym "OO-")))
+ ` (let ((,tmp ,obj))
+ (symbol-macrolet
+ ,(loop for name in names collect
+ (typecase name
+ (symbol `(,name (,(reader name) ,tmp)))
+ (cons `(,(first name) (,(reader (second name)) ,tmp)))
+ (t (error "Malformed syntax in WITH-STRUCT: ~A" name))))
+ , at body)))))
+
+
+;;;; TCP server
+
+(definterface create-socket (host port)
+ "Create a listening TCP socket on interface HOST and port PORT .")
+
+(definterface local-port (socket)
+ "Return the local port number of SOCKET.")
+
+(definterface close-socket (socket)
+ "Close the socket SOCKET.")
+
+(definterface accept-connection (socket &key external-format
+ buffering timeout)
+ "Accept a client connection on the listening socket SOCKET.
+Return a stream for the new connection.")
+
+(definterface add-sigio-handler (socket fn)
+ "Call FN whenever SOCKET is readable.")
+
+(definterface remove-sigio-handlers (socket)
+ "Remove all sigio handlers for SOCKET.")
+
+(definterface add-fd-handler (socket fn)
+ "Call FN when Lisp is waiting for input and SOCKET is readable.")
+
+(definterface remove-fd-handlers (socket)
+ "Remove all fd-handlers for SOCKET.")
+
+(definterface preferred-communication-style ()
+ "Return one of the symbols :spawn, :sigio, :fd-handler, or NIL."
+ nil)
+
+(definterface set-stream-timeout (stream timeout)
+ "Set the 'stream 'timeout. The timeout is either the real number
+ specifying the timeout in seconds or 'nil for no timeout."
+ (declare (ignore stream timeout))
+ nil)
+
+;;; Base condition for networking errors.
+(define-condition network-error (simple-error) ())
+
+(definterface emacs-connected ()
+ "Hook called when the first connection from Emacs is established.
+Called from the INIT-FN of the socket server that accepts the
+connection.
+
+This is intended for setting up extra context, e.g. to discover
+that the calling thread is the one that interacts with Emacs."
+ nil)
+
+
+;;;; Unix signals
+
+(defconstant +sigint+ 2)
+
+(definterface call-without-interrupts (fn)
+ "Call FN in a context where interrupts are disabled."
+ (funcall fn))
+
+(definterface getpid ()
+ "Return the (Unix) process ID of this superior Lisp.")
+
+(definterface lisp-implementation-type-name ()
+ "Return a short name for the Lisp implementation."
+ (lisp-implementation-type))
+
+(definterface default-directory ()
+ "Return the default directory."
+ (directory-namestring (truename *default-pathname-defaults*)))
+
+(definterface set-default-directory (directory)
+ "Set the default directory.
+This is used to resolve filenames without directory component."
+ (setf *default-pathname-defaults* (truename (merge-pathnames directory)))
+ (default-directory))
+
+(definterface call-with-syntax-hooks (fn)
+ "Call FN with hooks to handle special syntax."
+ (funcall fn))
+
+(definterface default-readtable-alist ()
+ "Return a suitable initial value for SWANK:*READTABLE-ALIST*."
+ '())
+
+(definterface quit-lisp ()
+ "Exit the current lisp image.")
+
+
+;;;; Compilation
+
+(definterface call-with-compilation-hooks (func)
+ "Call FUNC with hooks to record compiler conditions.")
+
+(defmacro with-compilation-hooks ((&rest ignore) &body body)
+ "Execute BODY as in CALL-WITH-COMPILATION-HOOKS."
+ (declare (ignore ignore))
+ `(call-with-compilation-hooks (lambda () (progn , at body))))
+
+(definterface swank-compile-string (string &key buffer position directory)
+ "Compile source from STRING. During compilation, compiler
+conditions must be trapped and resignalled as COMPILER-CONDITIONs.
+
+If supplied, BUFFER and POSITION specify the source location in Emacs.
+
+Additionally, if POSITION is supplied, it must be added to source
+positions reported in compiler conditions.
+
+If DIRECTORY is specified it may be used by certain implementations to
+rebind *DEFAULT-PATHNAME-DEFAULTS* which may improve the recording of
+source information.")
+
+(definterface swank-compile-file (filename load-p external-format)
+ "Compile FILENAME signalling COMPILE-CONDITIONs.
+If LOAD-P is true, load the file after compilation.
+EXTERNAL-FORMAT is a value returned by find-external-format or
+:default.")
+
+(deftype severity ()
+ '(member :error :read-error :warning :style-warning :note))
+
+;; Base condition type for compiler errors, warnings and notes.
+(define-condition compiler-condition (condition)
+ ((original-condition
+ ;; The original condition thrown by the compiler if appropriate.
+ ;; May be NIL if a compiler does not report using conditions.
+ :type (or null condition)
+ :initarg :original-condition
+ :accessor original-condition)
+
+ (severity :type severity
+ :initarg :severity
+ :accessor severity)
+
+ (message :initarg :message
+ :accessor message)
+
+ (short-message :initarg :short-message
+ :initform nil
+ :accessor short-message)
+
+ (references :initarg :references
+ :initform nil
+ :accessor references)
+
+ (location :initarg :location
+ :accessor location)))
+
+(definterface find-external-format (coding-system)
+ "Return a \"external file format designator\" for CODING-SYSTEM.
+CODING-SYSTEM is Emacs-style coding system name (a string),
+e.g. \"latin-1-unix\"."
+ (if (equal coding-system "iso-latin-1-unix")
+ :default
+ nil))
+
+(definterface guess-external-format (filename)
+ "Detect the external format for the file with name FILENAME.
+Return nil if the file contains no special markers."
+ ;; Look for a Emacs-style -*- coding: ... -*- or Local Variable: section.
+ (with-open-file (s filename :if-does-not-exist nil
+ :external-format (or (find-external-format "latin-1-unix")
+ :default))
+ (if s
+ (or (let* ((line (read-line s nil))
+ (p (search "-*-" line)))
+ (when p
+ (let* ((start (+ p (length "-*-")))
+ (end (search "-*-" line :start2 start)))
+ (when end
+ (%search-coding line start end)))))
+ (let* ((len (file-length s))
+ (buf (make-string (min len 3000))))
+ (file-position s (- len (length buf)))
+ (read-sequence buf s)
+ (let ((start (search "Local Variables:" buf :from-end t))
+ (end (search "End:" buf :from-end t)))
+ (and start end (< start end)
+ (%search-coding buf start end))))))))
+
+(defun %search-coding (str start end)
+ (let ((p (search "coding:" str :start2 start :end2 end)))
+ (when p
+ (incf p (length "coding:"))
+ (loop while (and (< p end)
+ (member (aref str p) '(#\space #\tab)))
+ do (incf p))
+ (let ((end (position-if (lambda (c) (find c '(#\space #\tab #\newline)))
+ str :start p)))
+ (find-external-format (subseq str p end))))))
+
+
+;;;; Streams
+
+(definterface make-fn-streams (input-fn output-fn)
+ "Return character input and output streams backended by functions.
+When input is needed, INPUT-FN is called with no arguments to
+return a string.
+When output is ready, OUTPUT-FN is called with the output as its
+argument.
+
+Output should be forced to OUTPUT-FN before calling INPUT-FN.
+
+The streams are returned as two values.")
+
+(definterface make-stream-interactive (stream)
+ "Do any necessary setup to make STREAM work interactively.
+This is called for each stream used for interaction with the user
+\(e.g. *standard-output*). An implementation could setup some
+implementation-specific functions to control output flushing at the
+like."
+ (declare (ignore stream))
+ nil)
+
+
+;;;; Documentation
+
+(definterface arglist (name)
+ "Return the lambda list for the symbol NAME. NAME can also be
+a lisp function object, on lisps which support this.
+
+The result can be a list or the :not-available keyword if the
+arglist cannot be determined."
+ (declare (ignore name))
+ :not-available)
+
+(defgeneric declaration-arglist (decl-identifier)
+ (:documentation
+ "Return the argument list of the declaration specifier belonging to the
+declaration identifier DECL-IDENTIFIER. If the arglist cannot be determined,
+the keyword :NOT-AVAILABLE is returned.
+
+The different SWANK backends can specialize this generic function to
+include implementation-dependend declaration specifiers, or to provide
+additional information on the specifiers defined in ANSI Common Lisp.")
+ (:method (decl-identifier)
+ (case decl-identifier
+ (dynamic-extent '(&rest vars))
+ (ignore '(&rest vars))
+ (ignorable '(&rest vars))
+ (special '(&rest vars))
+ (inline '(&rest function-names))
+ (notinline '(&rest function-name))
+ (optimize '(&any compilation-speed debug safety space speed))
+ (type '(type-specifier &rest args))
+ (ftype '(type-specifier &rest function-names))
+ (otherwise
+ (flet ((typespec-p (symbol) (member :type (describe-symbol-for-emacs symbol))))
+ (cond ((and (symbolp decl-identifier) (typespec-p decl-identifier))
+ '(&rest vars))
+ ((and (listp decl-identifier) (typespec-p (first decl-identifier)))
+ '(&rest vars))
+ (t :not-available)))))))
+
+(defgeneric type-specifier-arglist (typespec-operator)
+ (:documentation
+ "Return the argument list of the type specifier belonging to
+TYPESPEC-OPERATOR.. If the arglist cannot be determined, the keyword
+:NOT-AVAILABLE is returned.
+
+The different SWANK backends can specialize this generic function to
+include implementation-dependend declaration specifiers, or to provide
+additional information on the specifiers defined in ANSI Common Lisp.")
+ (:method (typespec-operator)
+ (declare (special *type-specifier-arglists*)) ; defined at end of file.
+ (typecase typespec-operator
+ (symbol (or (cdr (assoc typespec-operator *type-specifier-arglists*))
+ :not-available))
+ (t :not-available))))
+
+(definterface function-name (function)
+ "Return the name of the function object FUNCTION.
+
+The result is either a symbol, a list, or NIL if no function name is available."
+ (declare (ignore function))
+ nil)
+
+(definterface macroexpand-all (form)
+ "Recursively expand all macros in FORM.
+Return the resulting form.")
+
+(definterface compiler-macroexpand-1 (form &optional env)
+ "Call the compiler-macro for form.
+If FORM is a function call for which a compiler-macro has been
+defined, invoke the expander function using *macroexpand-hook* and
+return the results and T. Otherwise, return the original form and
+NIL."
+ (let ((fun (and (consp form) (compiler-macro-function (car form)))))
+ (if fun
+ (let ((result (funcall *macroexpand-hook* fun form env)))
+ (values result (not (eq result form))))
+ (values form nil))))
+
+(definterface compiler-macroexpand (form &optional env)
+ "Repetitively call `compiler-macroexpand-1'."
+ (labels ((frob (form expanded)
+ (multiple-value-bind (new-form newly-expanded)
+ (compiler-macroexpand-1 form env)
+ (if newly-expanded
+ (frob new-form t)
+ (values new-form expanded)))))
+ (frob form env)))
+
+(definterface describe-symbol-for-emacs (symbol)
+ "Return a property list describing SYMBOL.
+
+The property list has an entry for each interesting aspect of the
+symbol. The recognised keys are:
+
+ :VARIABLE :FUNCTION :SETF :SPECIAL-OPERATOR :MACRO :COMPILER-MACRO
+ :TYPE :CLASS :ALIEN-TYPE :ALIEN-STRUCT :ALIEN-UNION :ALIEN-ENUM
+
+The value of each property is the corresponding documentation string,
+or :NOT-DOCUMENTED. It is legal to include keys not listed here (but
+slime-print-apropos in Emacs must know about them).
+
+Properties should be included if and only if they are applicable to
+the symbol. For example, only (and all) fbound symbols should include
+the :FUNCTION property.
+
+Example:
+\(describe-symbol-for-emacs 'vector)
+ => (:CLASS :NOT-DOCUMENTED
+ :TYPE :NOT-DOCUMENTED
+ :FUNCTION \"Constructs a simple-vector from the given objects.\")")
+
+(definterface describe-definition (name type)
+ "Describe the definition NAME of TYPE.
+TYPE can be any value returned by DESCRIBE-SYMBOL-FOR-EMACS.
+
+Return a documentation string, or NIL if none is available.")
+
+
+;;;; Debugging
+
+(definterface install-debugger-globally (function)
+ "Install FUNCTION as the debugger for all threads/processes. This
+usually involves setting *DEBUGGER-HOOK* and, if the implementation
+permits, hooking into BREAK as well."
+ (setq *debugger-hook* function))
+
+(definterface call-with-debugging-environment (debugger-loop-fn)
+ "Call DEBUGGER-LOOP-FN in a suitable debugging environment.
+
+This function is called recursively at each debug level to invoke the
+debugger loop. The purpose is to setup any necessary environment for
+other debugger callbacks that will be called within the debugger loop.
+
+For example, this is a reasonable place to compute a backtrace, switch
+to safe reader/printer settings, and so on.")
+
+(definterface call-with-debugger-hook (hook fun)
+ "Call FUN and use HOOK as debugger hook.
+
+HOOK should be called for both BREAK and INVOKE-DEBUGGER."
+ (let ((*debugger-hook* hook))
+ (funcall fun)))
+
+(define-condition sldb-condition (condition)
+ ((original-condition
+ :initarg :original-condition
+ :accessor original-condition))
+ (:report (lambda (condition stream)
+ (format stream "Condition in debugger code~@[: ~A~]"
+ (original-condition condition))))
+ (:documentation
+ "Wrapper for conditions that should not be debugged.
+
+When a condition arises from the internals of the debugger, it is not
+desirable to debug it -- we'd risk entering an endless loop trying to
+debug the debugger! Instead, such conditions can be reported to the
+user without (re)entering the debugger by wrapping them as
+`sldb-condition's."))
+
+(definterface compute-backtrace (start end)
+ "Return a list containing a backtrace of the condition current
+being debugged. The results are unspecified if this function is
+called outside the dynamic contour CALL-WITH-DEBUGGING-ENVIRONMENT.
+
+START and END are zero-based indices constraining the number of frames
+returned. Frame zero is defined as the frame which invoked the
+debugger. If END is nil, return the frames from START to the end of
+the stack.")
+
+(definterface compute-sane-restarts (condition)
+ "This is an opportunity for Lisps such as CLISP to remove
+unwanted restarts from the output of CL:COMPUTE-RESTARTS,
+otherwise it should simply call CL:COMPUTE-RESTARTS, which is
+what the default implementation does."
+ (compute-restarts condition))
+
+(definterface print-frame (frame stream)
+ "Print frame to stream.")
+
+(definterface frame-source-location-for-emacs (frame-number)
+ "Return the source location for FRAME-NUMBER.")
+
+(definterface frame-catch-tags (frame-number)
+ "Return a list of XXX list of what? catch tags for a debugger
+stack frame. The results are undefined unless this is called
+within the dynamic contour of a function defined by
+DEFINE-DEBUGGER-HOOK.")
+
+(definterface frame-locals (frame-number)
+ "Return a list of XXX local variable designators define me
+for a debugger stack frame. The results are undefined unless
+this is called within the dynamic contour of a function defined
+by DEFINE-DEBUGGER-HOOK.")
+
+(definterface frame-var-value (frame var)
+ "Return the value of VAR in FRAME.
+FRAME is the number of the frame in the backtrace.
+VAR is the number of the variable in the frame.")
+
+(definterface disassemble-frame (frame-number)
+ "Disassemble the code for the FRAME-NUMBER.
+The output should be written to standard output.
+FRAME-NUMBER is a non-negative integer.")
+
+(definterface eval-in-frame (form frame-number)
+ "Evaluate a Lisp form in the lexical context of a stack frame
+in the debugger. The results are undefined unless called in the
+dynamic contour of a function defined by DEFINE-DEBUGGER-HOOK.
+
+FRAME-NUMBER must be a positive integer with 0 indicating the
+frame which invoked the debugger.
+
+The return value is the result of evaulating FORM in the
+appropriate context.")
+
+(definterface return-from-frame (frame-number form)
+ "Unwind the stack to the frame FRAME-NUMBER and return the value(s)
+produced by evaluating FORM in the frame context to its caller.
+
+Execute any clean-up code from unwind-protect forms above the frame
+during unwinding.
+
+Return a string describing the error if it's not possible to return
+from the frame.")
+
+(definterface restart-frame (frame-number)
+ "Restart execution of the frame FRAME-NUMBER with the same arguments
+as it was called originally.")
+
+(definterface format-sldb-condition (condition)
+ "Format a condition for display in SLDB."
+ (princ-to-string condition))
+
+(definterface condition-extras (condition)
+ "Return a list of extra for the debugger.
+The allowed elements are of the form:
+ (:SHOW-FRAME-SOURCE frame-number)
+ (:REFERENCES &rest refs)
+"
+ (declare (ignore condition))
+ '())
+
+(definterface activate-stepping (frame-number)
+ "Prepare the frame FRAME-NUMBER for stepping.")
+
+(definterface sldb-break-on-return (frame-number)
+ "Set a breakpoint in the frame FRAME-NUMBER.")
+
+(definterface sldb-break-at-start (symbol)
+ "Set a breakpoint on the beginning of the function for SYMBOL.")
+
+(definterface sldb-stepper-condition-p (condition)
+ "Return true if SLDB was invoked due to a single-stepping condition,
+false otherwise. "
+ (declare (ignore condition))
+ nil)
+
+(definterface sldb-step-into ()
+ "Step into the current single-stepper form.")
+
+(definterface sldb-step-next ()
+ "Step to the next form in the current function.")
+
+(definterface sldb-step-out ()
+ "Stop single-stepping temporarily, but resume it once the current function
+returns.")
+
+
+;;;; Definition finding
+
+(defstruct (:location (:type list) :named
+ (:constructor make-location
+ (buffer position &optional hints)))
+ buffer position
+ ;; Hints is a property list optionally containing:
+ ;; :snippet SOURCE-TEXT
+ ;; This is a snippet of the actual source text at the start of
+ ;; the definition, which could be used in a text search.
+ hints)
+
+(defstruct (:error (:type list) :named (:constructor)) message)
+(defstruct (:file (:type list) :named (:constructor)) name)
+(defstruct (:buffer (:type list) :named (:constructor)) name)
+(defstruct (:position (:type list) :named (:constructor)) pos)
+
+(definterface find-definitions (name)
+ "Return a list ((DSPEC LOCATION) ...) for NAME's definitions.
+
+NAME is a \"definition specifier\".
+
+DSPEC is a \"definition specifier\" describing the
+definition, e.g., FOO or (METHOD FOO (STRING NUMBER)) or
+\(DEFVAR FOO).
+
+LOCATION is the source location for the definition.")
+
+(definterface buffer-first-change (filename)
+ "Called for effect the first time FILENAME's buffer is modified."
+ (declare (ignore filename))
+ nil)
+
+
+;;;; XREF
+
+(definterface who-calls (function-name)
+ "Return the call sites of FUNCTION-NAME (a symbol).
+The results is a list ((DSPEC LOCATION) ...).")
+
+(definterface calls-who (function-name)
+ "Return the call sites of FUNCTION-NAME (a symbol).
+The results is a list ((DSPEC LOCATION) ...).")
+
+(definterface who-references (variable-name)
+ "Return the locations where VARIABLE-NAME (a symbol) is referenced.
+See WHO-CALLS for a description of the return value.")
+
+(definterface who-binds (variable-name)
+ "Return the locations where VARIABLE-NAME (a symbol) is bound.
+See WHO-CALLS for a description of the return value.")
+
+(definterface who-sets (variable-name)
+ "Return the locations where VARIABLE-NAME (a symbol) is set.
+See WHO-CALLS for a description of the return value.")
+
+(definterface who-macroexpands (macro-name)
+ "Return the locations where MACRO-NAME (a symbol) is expanded.
+See WHO-CALLS for a description of the return value.")
+
+(definterface who-specializes (class-name)
+ "Return the locations where CLASS-NAME (a symbol) is specialized.
+See WHO-CALLS for a description of the return value.")
+
+;;; Simpler variants.
+
+(definterface list-callers (function-name)
+ "List the callers of FUNCTION-NAME.
+This function is like WHO-CALLS except that it is expected to use
+lower-level means. Whereas WHO-CALLS is usually implemented with
+special compiler support, LIST-CALLERS is usually implemented by
+groveling for constants in function objects throughout the heap.
+
+The return value is as for WHO-CALLS.")
+
+(definterface list-callees (function-name)
+ "List the functions called by FUNCTION-NAME.
+See LIST-CALLERS for a description of the return value.")
+
+
+;;;; Profiling
+
+;;; The following functions define a minimal profiling interface.
+
+(definterface profile (fname)
+ "Marks symbol FNAME for profiling.")
+
+(definterface profiled-functions ()
+ "Returns a list of profiled functions.")
+
+(definterface unprofile (fname)
+ "Marks symbol FNAME as not profiled.")
+
+(definterface unprofile-all ()
+ "Marks all currently profiled functions as not profiled."
+ (dolist (f (profiled-functions))
+ (unprofile f)))
+
+(definterface profile-report ()
+ "Prints profile report.")
+
+(definterface profile-reset ()
+ "Resets profile counters.")
+
+(definterface profile-package (package callers-p methods)
+ "Wrap profiling code around all functions in PACKAGE. If a function
+is already profiled, then unprofile and reprofile (useful to notice
+function redefinition.)
+
+If CALLERS-P is T names have counts of the most common calling
+functions recorded.
+
+When called with arguments :METHODS T, profile all methods of all
+generic functions having names in the given package. Generic functions
+themselves, that is, their dispatch functions, are left alone.")
+
+
+;;;; Inspector
+
+(defclass inspector ()
+ ()
+ (:documentation "Super class of inspector objects.
+
+Implementations should sub class in order to dispatch off of the
+inspect-for-emacs method."))
+
+(defclass backend-inspector (inspector) ())
+
+(definterface make-default-inspector ()
+ "Return an inspector object suitable for passing to inspect-for-emacs.")
+
+(defgeneric inspect-for-emacs (object inspector)
+ (:documentation
+ "Explain to Emacs how to inspect OBJECT.
+
+The argument INSPECTOR is an object representing how to get at
+the internals of OBJECT, it is usually an implementation specific
+class used simply for dispatching to the proper method.
+
+Returns two values: a string which will be used as the title of
+the inspector buffer and a list specifying how to render the
+object for inspection.
+
+Every element of the list must be either a string, which will be
+inserted into the buffer as is, or a list of the form:
+
+ (:value object &optional format) - Render an inspectable
+ object. If format is provided it must be a string and will be
+ rendered in place of the value, otherwise use princ-to-string.
+
+ (:newline) - Render a \\n
+
+ (:action label lambda &key (refresh t)) - Render LABEL (a text
+ string) which when clicked will call LAMBDA. If REFRESH is
+ non-NIL the currently inspected object will be re-inspected
+ after calling the lambda.
+
+ NIL - do nothing."))
+
+(defmethod inspect-for-emacs ((object t) (inspector t))
+ "Generic method for inspecting any kind of object.
+
+Since we don't know how to deal with OBJECT we simply dump the
+output of CL:DESCRIBE."
+ (declare (ignore inspector))
+ (values
+ "A value."
+ `("Type: " (:value ,(type-of object)) (:newline)
+ "Don't know how to inspect the object, dumping output of CL:DESCRIBE:"
+ (:newline) (:newline)
+ ,(with-output-to-string (desc) (describe object desc)))))
+
+;;; Utilities for inspector methods.
+;;;
+(defun label-value-line (label value &key (newline t))
+ "Create a control list which prints \"LABEL: VALUE\" in the inspector.
+If NEWLINE is non-NIL a `(:newline)' is added to the result."
+ (list* (princ-to-string label) ": " `(:value ,value)
+ (if newline '((:newline)) nil)))
+
+(defmacro label-value-line* (&rest label-values)
+ ` (append ,@(loop for (label value) in label-values
+ collect `(label-value-line ,label ,value))))
+
+(definterface describe-primitive-type (object)
+ "Return a string describing the primitive type of object."
+ (declare (ignore object))
+ "N/A")
+
+
+;;;; Multithreading
+;;;
+;;; The default implementations are sufficient for non-multiprocessing
+;;; implementations.
+
+(definterface initialize-multiprocessing (continuation)
+ "Initialize multiprocessing, if necessary and then invoke CONTINUATION.
+
+Depending on the impleimentaion, this function may never return."
+ (funcall continuation))
+
+(definterface spawn (fn &key name)
+ "Create a new thread to call FN.")
+
+(definterface thread-id (thread)
+ "Return an Emacs-parsable object to identify THREAD.
+
+Ids should be comparable with equal, i.e.:
+ (equal (thread-id <t1>) (thread-id <t2>)) <==> (eq <t1> <t2>)")
+
+(definterface find-thread (id)
+ "Return the thread for ID.
+ID should be an id previously obtained with THREAD-ID.
+Can return nil if the thread no longer exists.")
+
+(definterface thread-name (thread)
+ "Return the name of THREAD.
+
+Thread names are be single-line strings and are meaningful to the
+user. They do not have to be unique."
+ (declare (ignore thread))
+ "The One True Thread")
+
+(definterface thread-status (thread)
+ "Return a string describing THREAD's state."
+ (declare (ignore thread))
+ "")
+
+(definterface make-lock (&key name)
+ "Make a lock for thread synchronization.
+Only one thread may hold the lock (via CALL-WITH-LOCK-HELD) at a time."
+ (declare (ignore name))
+ :null-lock)
+
+(definterface call-with-lock-held (lock function)
+ "Call FUNCTION with LOCK held, queueing if necessary."
+ (declare (ignore lock)
+ (type function function))
+ (funcall function))
+
+(definterface make-recursive-lock (&key name)
+ "Make a lock for thread synchronization.
+Only one thread may hold the lock (via CALL-WITH-RECURSIVE-LOCK-HELD)
+at a time, but that thread may hold it more than once."
+ (cons nil (make-lock :name name)))
+
+(definterface call-with-recursive-lock-held (lock function)
+ "Call FUNCTION with LOCK held, queueing if necessary."
+ (if (eql (car lock) (current-thread))
+ (funcall function)
+ (call-with-lock-held (cdr lock)
+ (lambda ()
+ (unwind-protect
+ (progn
+ (setf (car lock) (current-thread))
+ (funcall function))
+ (setf (car lock) nil))))))
+
+(definterface current-thread ()
+ "Return the currently executing thread."
+ 0)
+
+(definterface all-threads ()
+ "Return a list of all threads.")
+
+(definterface thread-alive-p (thread)
+ "Test if THREAD is termintated."
+ (member thread (all-threads)))
+
+(definterface interrupt-thread (thread fn)
+ "Cause THREAD to execute FN.")
+
+(definterface kill-thread (thread)
+ "Kill THREAD."
+ (declare (ignore thread))
+ nil)
+
+(definterface send (thread object)
+ "Send OBJECT to thread THREAD.")
+
+(definterface receive ()
+ "Return the next message from current thread's mailbox.")
+
+(definterface toggle-trace (spec)
+ "Toggle tracing of the function(s) given with SPEC.
+SPEC can be:
+ (setf NAME) ; a setf function
+ (:defmethod NAME QUALIFIER... (SPECIALIZER...)) ; a specific method
+ (:defgeneric NAME) ; a generic function with all methods
+ (:call CALLER CALLEE) ; trace calls from CALLER to CALLEE.
+ (:labels TOPLEVEL LOCAL)
+ (:flet TOPLEVEL LOCAL) ")
+
+
+;;;; Weak datastructures
+
+(definterface make-weak-key-hash-table (&rest args)
+ "Like MAKE-HASH-TABLE, but weak w.r.t. the keys."
+ (apply #'make-hash-table args))
+
+(definterface make-weak-value-hash-table (&rest args)
+ "Like MAKE-HASH-TABLE, but weak w.r.t. the values."
+ (apply #'make-hash-table args))
+
+(definterface hash-table-weakness (hashtable)
+ "Return nil or one of :key :value :key-or-value :key-and-value"
+ (declare (ignore hashtable))
+ nil)
+
+
+;;;; Character names
+
+(definterface character-completion-set (prefix matchp)
+ "Return a list of names of characters that match PREFIX."
+ ;; Handle the standard and semi-standard characters.
+ (loop for name in '("Newline" "Space" "Tab" "Page" "Rubout"
+ "Linefeed" "Return" "Backspace")
+ when (funcall matchp prefix name)
+ collect name))
+
+
+(defparameter *type-specifier-arglists*
+ '((and . (&rest type-specifiers))
+ (array . (&optional element-type dimension-spec))
+ (base-string . (&optional size))
+ (bit-vector . (&optional size))
+ (complex . (&optional type-specifier))
+ (cons . (&optional car-typespec cdr-typespec))
+ (double-float . (&optional lower-limit upper-limit))
+ (eql . (object))
+ (float . (&optional lower-limit upper-limit))
+ (function . (&optional arg-typespec value-typespec))
+ (integer . (&optional lower-limit upper-limit))
+ (long-float . (&optional lower-limit upper-limit))
+ (member . (&rest eql-objects))
+ (mod . (n))
+ (not . (type-specifier))
+ (or . (&rest type-specifiers))
+ (rational . (&optional lower-limit upper-limit))
+ (real . (&optional lower-limit upper-limit))
+ (satisfies . (predicate-symbol))
+ (short-float . (&optional lower-limit upper-limit))
+ (signed-byte . (&optional size))
+ (simple-array . (&optional element-type dimension-spec))
+ (simple-base-string . (&optional size))
+ (simple-bit-vector . (&optional size))
+ (simple-string . (&optional size))
+ (single-float . (&optional lower-limit upper-limit))
+ (simple-vector . (&optional size))
+ (string . (&optional size))
+ (unsigned-byte . (&optional size))
+ (values . (&rest typespecs))
+ (vector . (&optional element-type size))
+ ))
Added: branches/bos/thirdparty/emacs/slime/swank-clisp.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-clisp.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,672 @@
+;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
+
+;;;; SWANK support for CLISP.
+
+;;;; Copyright (C) 2003, 2004 W. Jenkner, V. Sedach
+
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License as
+;;;; published by the Free Software Foundation; either version 2 of
+;;;; the License, or (at your option) any later version.
+
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+
+;;;; You should have received a copy of the GNU General Public
+;;;; License along with this program; if not, write to the Free
+;;;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;;;; MA 02111-1307, USA.
+
+;;; This is work in progress, but it's already usable. Many things
+;;; are adapted from other swank-*.lisp, in particular from
+;;; swank-allegro (I don't use allegro at all, but it's the shortest
+;;; one and I found Helmut Eller's code there enlightening).
+
+;;; This code will work better with recent versions of CLISP (say, the
+;;; last release or CVS HEAD) while it may not work at all with older
+;;; versions. It is reasonable to expect it to work on platforms with
+;;; a "SOCKET" package, in particular on GNU/Linux or Unix-like
+;;; systems, but also on Win32. This backend uses the portable xref
+;;; from the CMU AI repository and metering.lisp from CLOCC [1], which
+;;; are conveniently included in SLIME.
+
+;;; [1] http://cvs.sourceforge.net/viewcvs.py/clocc/clocc/src/tools/metering/
+
+(in-package :swank-backend)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ ;;(use-package "SOCKET")
+ (use-package "GRAY"))
+
+;;;; if this lisp has the complete CLOS then we use it, otherwise we
+;;;; build up a "fake" swank-mop and then override the methods in the
+;;;; inspector.
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (defvar *have-mop*
+ (and (find-package :clos)
+ (eql :external
+ (nth-value 1 (find-symbol (string ':standard-slot-definition)
+ :clos))))
+ "True in those CLISP images which have a complete MOP implementation."))
+
+#+#.(cl:if swank-backend::*have-mop* '(cl:and) '(cl:or))
+(progn
+ (import-swank-mop-symbols :clos '(:slot-definition-documentation))
+
+ (defun swank-mop:slot-definition-documentation (slot)
+ (clos::slot-definition-documentation slot)))
+
+#-#.(cl:if swank-backend::*have-mop* '(and) '(or))
+(defclass swank-mop:standard-slot-definition ()
+ ()
+ (:documentation
+ "Dummy class created so that swank.lisp will compile and load."))
+
+;; #+#.(cl:if (cl:find-package "LINUX") '(and) '(or))
+;; (progn
+;; (defmacro with-blocked-signals ((&rest signals) &body body)
+;; (ext:with-gensyms ("SIGPROCMASK" ret mask)
+;; `(multiple-value-bind (,ret ,mask)
+;; (linux:sigprocmask-set-n-save
+;; ,linux:SIG_BLOCK
+;; ,(do ((sigset (linux:sigset-empty)
+;; (linux:sigset-add sigset (the fixnum (pop signals)))))
+;; ((null signals) sigset)))
+;; (linux:check-res ,ret 'linux:sigprocmask-set-n-save)
+;; (unwind-protect
+;; (progn , at body)
+;; (linux:sigprocmask-set ,linux:SIG_SETMASK ,mask nil)))))
+
+;; (defimplementation call-without-interrupts (fn)
+;; (with-blocked-signals (#.linux:SIGINT) (funcall fn))))
+
+;; #+#.(cl:if (cl:find-package "LINUX") '(or) '(and))
+(defimplementation call-without-interrupts (fn)
+ (funcall fn))
+
+(let ((getpid (or (find-symbol "PROCESS-ID" :system)
+ ;; old name prior to 2005-03-01, clisp <= 2.33.2
+ (find-symbol "PROGRAM-ID" :system)
+ #+win32 ; integrated into the above since 2005-02-24
+ (and (find-package :win32) ; optional modules/win32
+ (find-symbol "GetCurrentProcessId" :win32)))))
+ (defimplementation getpid () ; a required interface
+ (cond
+ (getpid (funcall getpid))
+ #+win32 ((ext:getenv "PID")) ; where does that come from?
+ (t -1))))
+
+(defimplementation lisp-implementation-type-name ()
+ "clisp")
+
+(defimplementation set-default-directory (directory)
+ (setf (ext:default-directory) directory)
+ (namestring (setf *default-pathname-defaults* (ext:default-directory))))
+
+;;;; TCP Server
+
+(defimplementation create-socket (host port)
+ (declare (ignore host))
+ (socket:socket-server port))
+
+(defimplementation local-port (socket)
+ (socket:socket-server-port socket))
+
+(defimplementation close-socket (socket)
+ (socket:socket-server-close socket))
+
+(defimplementation accept-connection (socket
+ &key external-format buffering timeout)
+ (declare (ignore buffering timeout))
+ (socket:socket-accept socket
+ :buffered nil ;; XXX should be t
+ :element-type 'character
+ :external-format external-format))
+
+;;;; Coding systems
+
+(defvar *external-format-to-coding-system*
+ '(((:charset "iso-8859-1" :line-terminator :unix)
+ "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix")
+ ((:charset "iso-8859-1":latin-1)
+ "latin-1" "iso-latin-1" "iso-8859-1")
+ ((:charset "utf-8") "utf-8")
+ ((:charset "utf-8" :line-terminator :unix) "utf-8-unix")
+ ((:charset "euc-jp") "euc-jp")
+ ((:charset "euc-jp" :line-terminator :unix) "euc-jp-unix")
+ ((:charset "us-ascii") "us-ascii")
+ ((:charset "us-ascii" :line-terminator :unix) "us-ascii-unix")))
+
+(defimplementation find-external-format (coding-system)
+ (let ((args (car (rassoc-if (lambda (x)
+ (member coding-system x :test #'equal))
+ *external-format-to-coding-system*))))
+ (and args (apply #'ext:make-encoding args))))
+
+
+;;;; Swank functions
+
+(defimplementation arglist (fname)
+ (block nil
+ (or (ignore-errors
+ (let ((exp (function-lambda-expression fname)))
+ (and exp (return (second exp)))))
+ (ignore-errors
+ (return (ext:arglist fname)))
+ :not-available)))
+
+(defimplementation macroexpand-all (form)
+ (ext:expand-form form))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ "Return a plist describing SYMBOL.
+Return NIL if the symbol is unbound."
+ (let ((result ()))
+ (flet ((doc (kind)
+ (or (documentation symbol kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push :variable (when (boundp symbol) (doc 'variable)))
+ (when (fboundp symbol)
+ (maybe-push
+ ;; Report WHEN etc. as macros, even though they may be
+ ;; implemented as special operators.
+ (if (macro-function symbol) :macro
+ (typecase (fdefinition symbol)
+ (generic-function :generic-function)
+ (function :function)
+ ;; (type-of 'progn) -> ext:special-operator
+ (t :special-operator)))
+ (doc 'function)))
+ (when (or (get symbol 'system::setf-function) ; e.g. #'(setf elt)
+ (get symbol 'system::setf-expander)); defsetf
+ (maybe-push :setf (doc 'setf)))
+ (when (or (get symbol 'system::type-symbol); cf. clisp/src/describe.lisp
+ (get symbol 'system::defstruct-description)
+ (get symbol 'system::deftype-expander))
+ (maybe-push :type (doc 'type))) ; even for 'structure
+ (when (find-class symbol nil)
+ (maybe-push :class (doc 'type)))
+ ;; Let this code work compiled in images without FFI
+ (let ((types (load-time-value
+ (and (find-package "FFI")
+ (symbol-value
+ (find-symbol "*C-TYPE-TABLE*" "FFI"))))))
+ ;; Use ffi::*c-type-table* so as not to suffer the overhead of
+ ;; (ignore-errors (ffi:parse-c-type symbol)) for 99.9% of symbols
+ ;; which are not FFI type names.
+ (when (and types (nth-value 1 (gethash symbol types)))
+ ;; Maybe use (case (head (ffi:deparse-c-type)))
+ ;; to distinguish struct and union types?
+ (maybe-push :alien-type :not-documented)))
+ result)))
+
+(defimplementation describe-definition (symbol namespace)
+ (ecase namespace
+ (:variable (describe symbol))
+ (:macro (describe (macro-function symbol)))
+ (:function (describe (symbol-function symbol)))
+ (:class (describe (find-class symbol)))))
+
+(defun fspec-pathname (symbol)
+ (let ((path (documentation symbol 'sys::file))
+ lines)
+ (when (consp path)
+ (psetq path (car path)
+ lines (cdr path)))
+ (when (and path
+ (member (pathname-type path)
+ custom:*compiled-file-types* :test #'equal))
+ (setq path
+ (loop for suffix in custom:*source-file-types*
+ thereis (probe-file (make-pathname :defaults path
+ :type suffix)))))
+ (values path lines)))
+
+(defun fspec-location (fspec)
+ (multiple-value-bind (file lines)
+ (fspec-pathname fspec)
+ (cond (file
+ (multiple-value-bind (truename c) (ignore-errors (truename file))
+ (cond (truename
+ (make-location (list :file (namestring truename))
+ (if (consp lines)
+ (list* :line lines)
+ (list :function-name (string fspec)))))
+ (t (list :error (princ-to-string c))))))
+ (t (list :error (format nil "No source information available for: ~S"
+ fspec))))))
+
+(defimplementation find-definitions (name)
+ (list (list name (fspec-location name))))
+
+(defun trim-whitespace (string)
+ (string-trim #(#\newline #\space #\tab) string))
+
+(defvar *sldb-backtrace*)
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (let* (;;(sys::*break-count* (1+ sys::*break-count*))
+ ;;(sys::*driver* debugger-loop-fn)
+ ;;(sys::*fasoutput-stream* nil)
+ (*sldb-backtrace*
+ (nthcdr 3 (member (sys::the-frame) (sldb-backtrace)))))
+ (funcall debugger-loop-fn)))
+
+(defun nth-frame (index)
+ (nth index *sldb-backtrace*))
+
+(defun sldb-backtrace ()
+ "Return a list ((ADDRESS . DESCRIPTION) ...) of frames."
+ (do ((frames '())
+ (last nil frame)
+ (frame (sys::the-frame) (sys::frame-up-1 frame 1))) ; 1 = "all frames"
+ ((eq frame last) (nreverse frames))
+ (unless (boring-frame-p frame)
+ (push frame frames))))
+
+(defun boring-frame-p (frame)
+ (member (frame-type frame) '(stack-value bind-var bind-env)))
+
+(defun frame-to-string (frame)
+ (with-output-to-string (s)
+ (sys::describe-frame s frame)))
+
+(defun frame-type (frame)
+ ;; FIXME: should bind *print-length* etc. to small values.
+ (frame-string-type (frame-to-string frame)))
+
+(defvar *frame-prefixes*
+ '(("frame binding variables" bind-var)
+ ("<1> #<compiled-function" compiled-fun)
+ ("<1> #<system-function" sys-fun)
+ ("<1> #<special-operator" special-op)
+ ("EVAL frame" eval)
+ ("APPLY frame" apply)
+ ("compiled tagbody frame" compiled-tagbody)
+ ("compiled block frame" compiled-block)
+ ("block frame" block)
+ ("nested block frame" block)
+ ("tagbody frame" tagbody)
+ ("nested tagbody frame" tagbody)
+ ("catch frame" catch)
+ ("handler frame" handler)
+ ("unwind-protect frame" unwind-protect)
+ ("driver frame" driver)
+ ("frame binding environments" bind-env)
+ ("CALLBACK frame" callback)
+ ("- " stack-value)
+ ("<1> " fun)
+ ("<2> " 2nd-frame)))
+
+(defun frame-string-type (string)
+ (cadr (assoc-if (lambda (pattern) (is-prefix-p pattern string))
+ *frame-prefixes*)))
+
+(defimplementation compute-backtrace (start end)
+ (let* ((bt *sldb-backtrace*)
+ (len (length bt)))
+ (subseq bt start (min (or end len) len))))
+
+;;; CLISP's REPL sets up an ABORT restart that kills SWANK. Here we
+;;; can omit that restart so that users don't select it by mistake.
+(defimplementation compute-sane-restarts (condition)
+ ;; The outermost restart is specified to be the last element of the
+ ;; list, hopefully that's our unwanted ABORT restart.
+ (butlast (compute-restarts condition)))
+
+(defimplementation print-frame (frame stream)
+ (let ((str (frame-to-string frame)))
+ ;; (format stream "~A " (frame-string-type str))
+ (write-string (extract-frame-line str)
+ stream)))
+
+(defun extract-frame-line (frame-string)
+ (let ((s frame-string))
+ (trim-whitespace
+ (case (frame-string-type s)
+ ((eval special-op)
+ (string-match "EVAL frame .*for form \\(.*\\)" s 1))
+ (apply
+ (string-match "APPLY frame for call \\(.*\\)" s 1))
+ ((compiled-fun sys-fun fun)
+ (extract-function-name s))
+ (t s)))))
+
+(defun extract-function-name (string)
+ (let ((1st (car (split-frame-string string))))
+ (or (string-match (format nil "^<1>[ ~%]*#<[-A-Za-z]* \\(.*\\)>")
+ 1st
+ 1)
+ (string-match (format nil "^<1>[ ~%]*\\(.*\\)") 1st 1)
+ 1st)))
+
+(defun split-frame-string (string)
+ (let ((rx (format nil "~%\\(~{~A~^\\|~}\\)"
+ (mapcar #'car *frame-prefixes*))))
+ (loop for pos = 0 then (1+ (regexp:match-start match))
+ for match = (regexp:match rx string :start pos)
+ if match collect (subseq string pos (regexp:match-start match))
+ else collect (subseq string pos)
+ while match)))
+
+(defun string-match (pattern string n)
+ (let* ((match (nth-value n (regexp:match pattern string))))
+ (if match (regexp:match-string string match))))
+
+(defimplementation format-sldb-condition (condition)
+ (trim-whitespace (princ-to-string condition)))
+
+(defimplementation eval-in-frame (form frame-number)
+ (sys::eval-at (nth-frame frame-number) form))
+
+(defimplementation frame-locals (frame-number)
+ (let ((frame (nth-frame frame-number)))
+ (loop for i below (%frame-count-vars frame)
+ collect (list :name (%frame-var-name frame i)
+ :value (%frame-var-value frame i)
+ :id 0))))
+
+(defimplementation frame-var-value (frame var)
+ (%frame-var-value (nth-frame frame) var))
+
+;;; Interpreter-Variablen-Environment has the shape
+;;; NIL or #(v1 val1 ... vn valn NEXT-ENV).
+
+(defun %frame-count-vars (frame)
+ (cond ((sys::eval-frame-p frame)
+ (do ((venv (frame-venv frame) (next-venv venv))
+ (count 0 (+ count (/ (1- (length venv)) 2))))
+ ((not venv) count)))
+ ((member (frame-type frame) '(compiled-fun sys-fun fun special-op))
+ (length (%parse-stack-values frame)))
+ (t 0)))
+
+(defun %frame-var-name (frame i)
+ (cond ((sys::eval-frame-p frame)
+ (nth-value 0 (venv-ref (frame-venv frame) i)))
+ (t (format nil "~D" i))))
+
+(defun %frame-var-value (frame i)
+ (cond ((sys::eval-frame-p frame)
+ (let ((name (venv-ref (frame-venv frame) i)))
+ (multiple-value-bind (v c) (ignore-errors (sys::eval-at frame name))
+ (if c
+ (format-sldb-condition c)
+ v))))
+ ((member (frame-type frame) '(compiled-fun sys-fun fun special-op))
+ (let ((str (nth i (%parse-stack-values frame))))
+ (trim-whitespace (subseq str 2))))
+ (t (break "Not implemented"))))
+
+(defun frame-venv (frame)
+ (let ((env (sys::eval-at frame '(sys::the-environment))))
+ (svref env 0)))
+
+(defun next-venv (venv) (svref venv (1- (length venv))))
+
+(defun venv-ref (env i)
+ "Reference the Ith binding in ENV.
+Return two values: NAME and VALUE"
+ (let ((idx (* i 2)))
+ (if (< idx (1- (length env)))
+ (values (svref env idx) (svref env (1+ idx)))
+ (venv-ref (next-venv env) (- i (/ (1- (length env)) 2))))))
+
+(defun %parse-stack-values (frame)
+ (labels ((next (fp) (sys::frame-down-1 fp 1))
+ (parse (fp accu)
+ (let ((str (frame-to-string fp)))
+ (cond ((is-prefix-p "- " str)
+ (parse (next fp) (cons str accu)))
+ ((is-prefix-p "<1> " str)
+ ;;(when (eq (frame-type frame) 'compiled-fun)
+ ;; (pop accu))
+ (dolist (str (cdr (split-frame-string str)))
+ (when (is-prefix-p "- " str)
+ (push str accu)))
+ (nreverse accu))
+ (t (parse (next fp) accu))))))
+ (parse (next frame) '())))
+
+(defun is-prefix-p (pattern string)
+ (not (mismatch pattern string :end2 (min (length pattern)
+ (length string)))))
+
+(defimplementation frame-catch-tags (index)
+ (declare (ignore index))
+ nil)
+
+(defimplementation return-from-frame (index form)
+ (sys::return-from-eval-frame (nth-frame index) form))
+
+(defimplementation restart-frame (index)
+ (sys::redo-eval-frame (nth-frame index)))
+
+(defimplementation frame-source-location-for-emacs (index)
+ `(:error
+ ,(format nil "frame-source-location not implemented. (frame: ~A)"
+ (nth-frame index))))
+
+;;;; Profiling
+
+(defimplementation profile (fname)
+ (eval `(mon:monitor ,fname))) ;monitor is a macro
+
+(defimplementation profiled-functions ()
+ mon:*monitored-functions*)
+
+(defimplementation unprofile (fname)
+ (eval `(mon:unmonitor ,fname))) ;unmonitor is a macro
+
+(defimplementation unprofile-all ()
+ (mon:unmonitor))
+
+(defimplementation profile-report ()
+ (mon:report-monitoring))
+
+(defimplementation profile-reset ()
+ (mon:reset-all-monitoring))
+
+(defimplementation profile-package (package callers-p methods)
+ (declare (ignore callers-p methods))
+ (mon:monitor-all package))
+
+;;;; Handle compiler conditions (find out location of error etc.)
+
+(defmacro compile-file-frobbing-notes ((&rest args) &body body)
+ "Pass ARGS to COMPILE-FILE, send the compiler notes to
+*STANDARD-INPUT* and frob them in BODY."
+ `(let ((*error-output* (make-string-output-stream))
+ (*compile-verbose* t))
+ (multiple-value-prog1
+ (compile-file , at args)
+ (handler-case
+ (with-input-from-string
+ (*standard-input* (get-output-stream-string *error-output*))
+ , at body)
+ (sys::simple-end-of-file () nil)))))
+
+(defvar *orig-c-warn* (symbol-function 'system::c-warn))
+(defvar *orig-c-style-warn* (symbol-function 'system::c-style-warn))
+(defvar *orig-c-error* (symbol-function 'system::c-error))
+(defvar *orig-c-report-problems* (symbol-function 'system::c-report-problems))
+
+(defmacro dynamic-flet (names-functions &body body)
+ "(dynamic-flet ((NAME FUNCTION) ...) BODY ...)
+Execute BODY with NAME's function slot set to FUNCTION."
+ `(ext:letf* ,(loop for (name function) in names-functions
+ collect `((symbol-function ',name) ,function))
+ , at body))
+
+(defvar *buffer-name* nil)
+(defvar *buffer-offset*)
+
+(defun compiler-note-location ()
+ "Return the current compiler location."
+ (let ((lineno1 sys::*compile-file-lineno1*)
+ (lineno2 sys::*compile-file-lineno2*)
+ (file sys::*compile-file-truename*))
+ (cond ((and file lineno1 lineno2)
+ (make-location (list ':file (namestring file))
+ (list ':line lineno1)))
+ (*buffer-name*
+ (make-location (list ':buffer *buffer-name*)
+ (list ':position *buffer-offset*)))
+ (t
+ (list :error "No error location available")))))
+
+(defun signal-compiler-warning (cstring args severity orig-fn)
+ (signal (make-condition 'compiler-condition
+ :severity severity
+ :message (apply #'format nil cstring args)
+ :location (compiler-note-location)))
+ (apply orig-fn cstring args))
+
+(defun c-warn (cstring &rest args)
+ (signal-compiler-warning cstring args :warning *orig-c-warn*))
+
+(defun c-style-warn (cstring &rest args)
+ (dynamic-flet ((sys::c-warn *orig-c-warn*))
+ (signal-compiler-warning cstring args :style-warning *orig-c-style-warn*)))
+
+(defun c-error (cstring &rest args)
+ (signal-compiler-warning cstring args :error *orig-c-error*))
+
+(defimplementation call-with-compilation-hooks (function)
+ (handler-bind ((warning #'handle-notification-condition))
+ (dynamic-flet ((system::c-warn #'c-warn)
+ (system::c-style-warn #'c-style-warn)
+ (system::c-error #'c-error))
+ (funcall function))))
+
+(defun handle-notification-condition (condition)
+ "Handle a condition caused by a compiler warning."
+ (signal (make-condition 'compiler-condition
+ :original-condition condition
+ :severity :warning
+ :message (princ-to-string condition)
+ :location (compiler-note-location))))
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (with-compilation-hooks ()
+ (with-compilation-unit ()
+ (let ((fasl-file (compile-file filename
+ :external-format external-format)))
+ (when (and load-p fasl-file)
+ (load fasl-file))
+ nil))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-offset* position))
+ (funcall (compile nil (read-from-string
+ (format nil "(~S () ~A)" 'lambda string)))))))
+
+;;;; Portable XREF from the CMU AI repository.
+
+(setq pxref::*handle-package-forms* '(cl:in-package))
+
+(defmacro defxref (name function)
+ `(defimplementation ,name (name)
+ (xref-results (,function name))))
+
+(defxref who-calls pxref:list-callers)
+(defxref who-references pxref:list-readers)
+(defxref who-binds pxref:list-setters)
+(defxref who-sets pxref:list-setters)
+(defxref list-callers pxref:list-callers)
+(defxref list-callees pxref:list-callees)
+
+(defun xref-results (symbols)
+ (let ((xrefs '()))
+ (dolist (symbol symbols)
+ (push (list symbol (fspec-location symbol)) xrefs))
+ xrefs))
+
+(when (find-package :swank-loader)
+ (setf (symbol-function (intern "USER-INIT-FILE" :swank-loader))
+ (lambda ()
+ (let ((home (user-homedir-pathname)))
+ (and (ext:probe-directory home)
+ (probe-file (format nil "~A/.swank.lisp"
+ (namestring (truename home)))))))))
+
+;;; Don't set *debugger-hook* to nil on break.
+(ext:without-package-lock ()
+ (defun break (&optional (format-string "Break") &rest args)
+ (if (not sys::*use-clcs*)
+ (progn
+ (terpri *error-output*)
+ (apply #'format *error-output*
+ (concatenate 'string "*** - " format-string)
+ args)
+ (funcall ext:*break-driver* t))
+ (let ((condition
+ (make-condition 'simple-condition
+ :format-control format-string
+ :format-arguments args))
+ ;;(*debugger-hook* nil)
+ ;; Issue 91
+ )
+ (ext:with-restarts
+ ((continue
+ :report (lambda (stream)
+ (format stream (sys::text "Return from ~S loop")
+ 'break))
+ ()))
+ (with-condition-restarts condition (list (find-restart 'continue))
+ (invoke-debugger condition)))))
+ nil))
+
+;;;; Inspecting
+
+(defclass clisp-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector () (make-instance 'clisp-inspector))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (let* ((*print-array* nil) (*print-pretty* t)
+ (*print-circle* t) (*print-escape* t)
+ (*print-lines* custom:*inspect-print-lines*)
+ (*print-level* custom:*inspect-print-level*)
+ (*print-length* custom:*inspect-print-length*)
+ (sys::*inspect-all* (make-array 10 :fill-pointer 0 :adjustable t))
+ (tmp-pack (make-package (gensym "INSPECT-TMP-PACKAGE-")))
+ (*package* tmp-pack)
+ (sys::*inspect-unbound-value* (intern "#<unbound>" tmp-pack)))
+ (let ((inspection (sys::inspect-backend o)))
+ (values (format nil "~S~% ~A~{~%~A~}" o
+ (sys::insp-title inspection)
+ (sys::insp-blurb inspection))
+ (loop with count = (sys::insp-num-slots inspection)
+ for i below count
+ append (multiple-value-bind (value name)
+ (funcall (sys::insp-nth-slot inspection)
+ i)
+ `((:value ,name) " = " (:value ,value)
+ (:newline))))))))
+
+(defimplementation quit-lisp ()
+ #+lisp=cl (ext:quit)
+ #-lisp=cl (lisp:quit))
+
+;;;; Weak hashtables
+
+(defimplementation make-weak-key-hash-table (&rest args)
+ (apply #'make-hash-table :weak :key args))
+
+(defimplementation make-weak-value-hash-table (&rest args)
+ (apply #'make-hash-table :weak :value args))
+
+;;; Local Variables:
+;;; eval: (put 'compile-file-frobbing-notes 'lisp-indent-function 1)
+;;; eval: (put 'dynamic-flet 'common-lisp-indent-function 1)
+;;; End:
Added: branches/bos/thirdparty/emacs/slime/swank-cmucl.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-cmucl.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,2256 @@
+;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;+" -*-
+;;;
+;;; License: Public Domain
+;;;
+;;;; Introduction
+;;;
+;;; This is the CMUCL implementation of the `swank-backend' package.
+
+(in-package :swank-backend)
+
+(import-swank-mop-symbols :pcl '(:slot-definition-documentation))
+
+(defun swank-mop:slot-definition-documentation (slot)
+ (documentation slot t))
+
+;;;; "Hot fixes"
+;;;
+;;; Here are necessary bugfixes to the oldest supported version of
+;;; CMUCL (currently 18e). Any fixes placed here should also be
+;;; submitted to the `cmucl-imp' mailing list and confirmed as
+;;; good. When a new release is made that includes the fixes we should
+;;; promptly delete them from here. It is enough to be compatible with
+;;; the latest release.
+
+(in-package :lisp)
+
+;;; `READ-SEQUENCE' with large sequences has problems in 18e. This new
+;;; definition works better.
+
+#-cmu19
+(progn
+ (let ((s (find-symbol (string :*enable-package-locked-errors*) :lisp)))
+ (when s
+ (setf (symbol-value s) nil)))
+
+ (defun read-into-simple-string (s stream start end)
+ (declare (type simple-string s))
+ (declare (type stream stream))
+ (declare (type index start end))
+ (unless (subtypep (stream-element-type stream) 'character)
+ (error 'type-error
+ :datum (read-char stream nil #\Null)
+ :expected-type (stream-element-type stream)
+ :format-control "Trying to read characters from a binary stream."))
+ ;; Let's go as low level as it seems reasonable.
+ (let* ((numbytes (- end start))
+ (total-bytes 0))
+ ;; read-n-bytes may return fewer bytes than requested, so we need
+ ;; to keep trying.
+ (loop while (plusp numbytes) do
+ (let ((bytes-read (system:read-n-bytes stream s start numbytes nil)))
+ (when (zerop bytes-read)
+ (return-from read-into-simple-string total-bytes))
+ (incf total-bytes bytes-read)
+ (incf start bytes-read)
+ (decf numbytes bytes-read)))
+ total-bytes))
+
+ (let ((s (find-symbol (string :*enable-package-locked-errors*) :lisp)))
+ (when s
+ (setf (symbol-value s) t)))
+
+ )
+
+(in-package :swank-backend)
+
+
+;;;; TCP server
+;;;
+;;; In CMUCL we support all communication styles. By default we use
+;;; `:SIGIO' because it is the most responsive, but it's somewhat
+;;; dangerous: CMUCL is not in general "signal safe", and you don't
+;;; know for sure what you'll be interrupting. Both `:FD-HANDLER' and
+;;; `:SPAWN' are reasonable alternatives.
+
+(defimplementation preferred-communication-style ()
+ :sigio)
+
+#-(or darwin mips)
+(defimplementation create-socket (host port)
+ (let* ((addr (resolve-hostname host))
+ (addr (if (not (find-symbol "SOCKET-ERROR" :ext))
+ (ext:htonl addr)
+ addr)))
+ (ext:create-inet-listener port :stream :reuse-address t :host addr)))
+
+;; There seems to be a bug in create-inet-listener on Mac/OSX and Irix.
+#+(or darwin mips)
+(defimplementation create-socket (host port)
+ (declare (ignore host))
+ (ext:create-inet-listener port :stream :reuse-address t))
+
+(defimplementation local-port (socket)
+ (nth-value 1 (ext::get-socket-host-and-port (socket-fd socket))))
+
+(defimplementation close-socket (socket)
+ (let ((fd (socket-fd socket)))
+ (sys:invalidate-descriptor fd)
+ (ext:close-socket fd)))
+
+(defimplementation accept-connection (socket &key
+ external-format buffering timeout)
+ (declare (ignore timeout external-format))
+ (let ((buffering (or buffering :full)))
+ (make-socket-io-stream (ext:accept-tcp-connection socket) buffering)))
+
+;;;;; Sockets
+
+(defun socket-fd (socket)
+ "Return the filedescriptor for the socket represented by SOCKET."
+ (etypecase socket
+ (fixnum socket)
+ (sys:fd-stream (sys:fd-stream-fd socket))))
+
+(defun resolve-hostname (hostname)
+ "Return the IP address of HOSTNAME as an integer (in host byte-order)."
+ (let ((hostent (ext:lookup-host-entry hostname)))
+ (car (ext:host-entry-addr-list hostent))))
+
+(defun make-socket-io-stream (fd buffering)
+ "Create a new input/output fd-stream for FD."
+ (sys:make-fd-stream fd :input t :output t :element-type 'base-char
+ :buffering buffering))
+
+;;;;; Signal-driven I/O
+
+(defvar *sigio-handlers* '()
+ "List of (key . function) pairs.
+All functions are called on SIGIO, and the key is used for removing
+specific functions.")
+
+(defun set-sigio-handler ()
+ (sys:enable-interrupt :sigio (lambda (signal code scp)
+ (sigio-handler signal code scp))))
+
+(defun sigio-handler (signal code scp)
+ (declare (ignore signal code scp))
+ (mapc #'funcall (mapcar #'cdr *sigio-handlers*)))
+
+(defun fcntl (fd command arg)
+ "fcntl(2) - manipulate a file descriptor."
+ (multiple-value-bind (ok error) (unix:unix-fcntl fd command arg)
+ (unless ok (error "fcntl: ~A" (unix:get-unix-error-msg error)))))
+
+(defimplementation add-sigio-handler (socket fn)
+ (set-sigio-handler)
+ (let ((fd (socket-fd socket)))
+ (fcntl fd unix:f-setown (unix:unix-getpid))
+ (fcntl fd unix:f-setfl unix:fasync)
+ (push (cons fd fn) *sigio-handlers*)))
+
+(defimplementation remove-sigio-handlers (socket)
+ (let ((fd (socket-fd socket)))
+ (setf *sigio-handlers* (remove fd *sigio-handlers* :key #'car))
+ (sys:invalidate-descriptor fd)))
+
+;;;;; SERVE-EVENT
+
+(defimplementation add-fd-handler (socket fn)
+ (let ((fd (socket-fd socket)))
+ (sys:add-fd-handler fd :input (lambda (_) _ (funcall fn)))))
+
+(defimplementation remove-fd-handlers (socket)
+ (sys:invalidate-descriptor (socket-fd socket)))
+
+
+;;;; Stream handling
+;;; XXX: How come we don't use Gray streams in CMUCL too? -luke (15/May/2004)
+
+(defimplementation make-fn-streams (input-fn output-fn)
+ (let* ((output (make-slime-output-stream output-fn))
+ (input (make-slime-input-stream input-fn output)))
+ (values input output)))
+
+(defstruct (slime-output-stream
+ (:include lisp::lisp-stream
+ (lisp::misc #'sos/misc)
+ (lisp::out #'sos/out)
+ (lisp::sout #'sos/sout))
+ (:conc-name sos.)
+ (:print-function %print-slime-output-stream)
+ (:constructor make-slime-output-stream (output-fn)))
+ (output-fn nil :type function)
+ (buffer (make-string 8000) :type string)
+ (index 0 :type kernel:index)
+ (column 0 :type kernel:index)
+ (last-flush-time (get-internal-real-time) :type unsigned-byte))
+
+(defun %print-slime-output-stream (s stream d)
+ (declare (ignore d))
+ (print-unreadable-object (s stream :type t :identity t)))
+
+(defun sos/out (stream char)
+ (system:without-interrupts
+ (let ((buffer (sos.buffer stream))
+ (index (sos.index stream)))
+ (setf (schar buffer index) char)
+ (setf (sos.index stream) (1+ index))
+ (incf (sos.column stream))
+ (when (char= #\newline char)
+ (setf (sos.column stream) 0)
+ (force-output stream))
+ (when (= index (1- (length buffer)))
+ (finish-output stream)))
+ char))
+
+(defun sos/sout (stream string start end)
+ (system:without-interrupts
+ (loop for i from start below end
+ do (sos/out stream (aref string i)))))
+
+(defun log-stream-op (stream operation)
+ stream operation
+ #+(or)
+ (progn
+ (format sys:*tty* "~S @ ~D ~A~%" operation
+ (sos.index stream)
+ (/ (- (get-internal-real-time) (sos.last-flush-time stream))
+ (coerce internal-time-units-per-second 'double-float)))
+ (finish-output sys:*tty*)))
+
+(defun sos/misc (stream operation &optional arg1 arg2)
+ (declare (ignore arg1 arg2))
+ (case operation
+ (:finish-output
+ (log-stream-op stream operation)
+ (system:without-interrupts
+ (let ((end (sos.index stream)))
+ (unless (zerop end)
+ (let ((s (subseq (sos.buffer stream) 0 end)))
+ (setf (sos.index stream) 0)
+ (funcall (sos.output-fn stream) s))
+ (setf (sos.last-flush-time stream) (get-internal-real-time)))))
+ nil)
+ (:force-output
+ (log-stream-op stream operation)
+ (sos/misc-force-output stream)
+ nil)
+ (:charpos (sos.column stream))
+ (:line-length 75)
+ (:file-position nil)
+ (:element-type 'base-char)
+ (:get-command nil)
+ (:close nil)
+ (t (format *terminal-io* "~&~Astream: ~S~%" stream operation))))
+
+(defun sos/misc-force-output (stream)
+ (system:without-interrupts
+ (unless (or (zerop (sos.index stream))
+ (loop with buffer = (sos.buffer stream)
+ for i from 0 below (sos.index stream)
+ always (char= (aref buffer i) #\newline)))
+ (let ((last (sos.last-flush-time stream))
+ (now (get-internal-real-time)))
+ (when (> (/ (- now last)
+ (coerce internal-time-units-per-second 'double-float))
+ 0.1)
+ (finish-output stream))))))
+
+(defstruct (slime-input-stream
+ (:include string-stream
+ (lisp::in #'sis/in)
+ (lisp::misc #'sis/misc))
+ (:conc-name sis.)
+ (:print-function %print-slime-output-stream)
+ (:constructor make-slime-input-stream (input-fn sos)))
+ (input-fn nil :type function)
+ ;; We know our sibling output stream, so that we can force it before
+ ;; requesting input.
+ (sos nil :type slime-output-stream)
+ (buffer "" :type string)
+ (index 0 :type kernel:index))
+
+(defun sis/in (stream eof-errorp eof-value)
+ (finish-output (sis.sos stream))
+ (let ((index (sis.index stream))
+ (buffer (sis.buffer stream)))
+ (when (= index (length buffer))
+ (let ((string (funcall (sis.input-fn stream))))
+ (cond ((zerop (length string))
+ (return-from sis/in
+ (if eof-errorp
+ (error (make-condition 'end-of-file :stream stream))
+ eof-value)))
+ (t
+ (setf buffer string)
+ (setf (sis.buffer stream) buffer)
+ (setf index 0)))))
+ (prog1 (aref buffer index)
+ (setf (sis.index stream) (1+ index)))))
+
+(defun sis/misc (stream operation &optional arg1 arg2)
+ (declare (ignore arg2))
+ (ecase operation
+ (:file-position nil)
+ (:file-length nil)
+ (:unread (setf (aref (sis.buffer stream)
+ (decf (sis.index stream)))
+ arg1))
+ (:clear-input
+ (setf (sis.index stream) 0
+ (sis.buffer stream) ""))
+ (:listen (< (sis.index stream) (length (sis.buffer stream))))
+ (:charpos nil)
+ (:line-length nil)
+ (:get-command nil)
+ (:element-type 'base-char)
+ (:close nil)
+ (:interactive-p t)))
+
+
+;;;; Compilation Commands
+
+(defvar *previous-compiler-condition* nil
+ "Used to detect duplicates.")
+
+(defvar *previous-context* nil
+ "Previous compiler error context.")
+
+(defvar *buffer-name* nil
+ "The name of the Emacs buffer we are compiling from.
+NIL if we aren't compiling from a buffer.")
+
+(defvar *buffer-start-position* nil)
+(defvar *buffer-substring* nil)
+
+(defimplementation call-with-compilation-hooks (function)
+ (let ((*previous-compiler-condition* nil)
+ (*previous-context* nil)
+ (*print-readably* nil))
+ (handler-bind ((c::compiler-error #'handle-notification-condition)
+ (c::style-warning #'handle-notification-condition)
+ (c::warning #'handle-notification-condition))
+ (funcall function))))
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (declare (ignore external-format))
+ (clear-xref-info filename)
+ (with-compilation-hooks ()
+ (let ((*buffer-name* nil)
+ (ext:*ignore-extra-close-parentheses* nil))
+ (multiple-value-bind (output-file warnings-p failure-p)
+ (compile-file filename)
+ (unless failure-p
+ ;; Cache the latest source file for definition-finding.
+ (source-cache-get filename (file-write-date filename))
+ (when load-p (load output-file)))
+ (values output-file warnings-p failure-p)))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-start-position* position)
+ (*buffer-substring* string))
+ (with-input-from-string (stream string)
+ (ext:compile-from-stream
+ stream
+ :source-info `(:emacs-buffer ,buffer
+ :emacs-buffer-offset ,position
+ :emacs-buffer-string ,string))))))
+
+
+;;;;; Trapping notes
+;;;
+;;; We intercept conditions from the compiler and resignal them as
+;;; `SWANK:COMPILER-CONDITION's.
+
+(defun handle-notification-condition (condition)
+ "Handle a condition caused by a compiler warning."
+ (unless (eq condition *previous-compiler-condition*)
+ (let ((context (c::find-error-context nil)))
+ (setq *previous-compiler-condition* condition)
+ (setq *previous-context* context)
+ (signal-compiler-condition condition context))))
+
+(defun signal-compiler-condition (condition context)
+ (signal (make-condition
+ 'compiler-condition
+ :original-condition condition
+ :severity (severity-for-emacs condition)
+ :short-message (brief-compiler-message-for-emacs condition)
+ :message (long-compiler-message-for-emacs condition context)
+ :location (if (read-error-p condition)
+ (read-error-location condition)
+ (compiler-note-location context)))))
+
+(defun severity-for-emacs (condition)
+ "Return the severity of CONDITION."
+ (etypecase condition
+ ((satisfies read-error-p) :read-error)
+ (c::compiler-error :error)
+ (c::style-warning :note)
+ (c::warning :warning)))
+
+(defun read-error-p (condition)
+ (eq (type-of condition) 'c::compiler-read-error))
+
+(defun brief-compiler-message-for-emacs (condition)
+ "Briefly describe a compiler error for Emacs.
+When Emacs presents the message it already has the source popped up
+and the source form highlighted. This makes much of the information in
+the error-context redundant."
+ (princ-to-string condition))
+
+(defun long-compiler-message-for-emacs (condition error-context)
+ "Describe a compiler error for Emacs including context information."
+ (declare (type (or c::compiler-error-context null) error-context))
+ (multiple-value-bind (enclosing source)
+ (if error-context
+ (values (c::compiler-error-context-enclosing-source error-context)
+ (c::compiler-error-context-source error-context)))
+ (format nil "~@[--> ~{~<~%--> ~1:;~A~> ~}~%~]~@[~{==>~%~A~^~%~}~]~A"
+ enclosing source condition)))
+
+(defun read-error-location (condition)
+ (let* ((finfo (car (c::source-info-current-file c::*source-info*)))
+ (file (c::file-info-name finfo))
+ (pos (c::compiler-read-error-position condition)))
+ (cond ((and (eq file :stream) *buffer-name*)
+ (make-location (list :buffer *buffer-name*)
+ (list :position (+ *buffer-start-position* pos))))
+ ((and (pathnamep file) (not *buffer-name*))
+ (make-location (list :file (unix-truename file))
+ (list :position (1+ pos))))
+ (t (break)))))
+
+(defun compiler-note-location (context)
+ "Derive the location of a complier message from its context.
+Return a `location' record, or (:error REASON) on failure."
+ (if (null context)
+ (note-error-location)
+ (let ((file (c::compiler-error-context-file-name context))
+ (source (c::compiler-error-context-original-source context))
+ (path
+ (reverse (c::compiler-error-context-original-source-path context))))
+ (or (locate-compiler-note file source path)
+ (note-error-location)))))
+
+(defun note-error-location ()
+ "Pseudo-location for notes that can't be located."
+ (list :error "No error location available."))
+
+(defun locate-compiler-note (file source source-path)
+ (cond ((and (eq file :stream) *buffer-name*)
+ ;; Compiling from a buffer
+ (let ((position (+ *buffer-start-position*
+ (source-path-string-position
+ source-path *buffer-substring*))))
+ (make-location (list :buffer *buffer-name*)
+ (list :position position))))
+ ((and (pathnamep file) (null *buffer-name*))
+ ;; Compiling from a file
+ (make-location (list :file (unix-truename file))
+ (list :position
+ (1+ (source-path-file-position
+ source-path file)))))
+ ((and (eq file :lisp) (stringp source))
+ ;; No location known, but we have the source form.
+ ;; XXX How is this case triggered? -luke (16/May/2004)
+ ;; This can happen if the compiler needs to expand a macro
+ ;; but the macro-expander is not yet compiled. Calling the
+ ;; (interpreted) macro-expander triggers IR1 conversion of
+ ;; the lambda expression for the expander and invokes the
+ ;; compiler recursively.
+ (make-location (list :source-form source)
+ (list :position 1)))))
+
+(defun unix-truename (pathname)
+ (ext:unix-namestring (truename pathname)))
+
+
+;;;; XREF
+;;;
+;;; Cross-reference support is based on the standard CMUCL `XREF'
+;;; package. This package has some caveats: XREF information is
+;;; recorded during compilation and not preserved in fasl files, and
+;;; XREF recording is disabled by default. Redefining functions can
+;;; also cause duplicate references to accumulate, but
+;;; `swank-compile-file' will automatically clear out any old records
+;;; from the same filename.
+;;;
+;;; To enable XREF recording, set `c:*record-xref-info*' to true. To
+;;; clear out the XREF database call `xref:init-xref-database'.
+
+(defmacro defxref (name function)
+ `(defimplementation ,name (name)
+ (xref-results (,function name))))
+
+(defxref who-calls xref:who-calls)
+(defxref who-references xref:who-references)
+(defxref who-binds xref:who-binds)
+(defxref who-sets xref:who-sets)
+
+;;; More types of XREF information were added since 18e:
+;;;
+#+cmu19
+(progn
+ (defxref who-macroexpands xref:who-macroexpands)
+ ;; XXX
+ (defimplementation who-specializes (symbol)
+ (let* ((methods (xref::who-specializes (find-class symbol)))
+ (locations (mapcar #'method-location methods)))
+ (mapcar #'list methods locations))))
+
+(defun xref-results (contexts)
+ (mapcar (lambda (xref)
+ (list (xref:xref-context-name xref)
+ (resolve-xref-location xref)))
+ contexts))
+
+(defun resolve-xref-location (xref)
+ (let ((name (xref:xref-context-name xref))
+ (file (xref:xref-context-file xref))
+ (source-path (xref:xref-context-source-path xref)))
+ (cond ((and file source-path)
+ (let ((position (source-path-file-position source-path file)))
+ (make-location (list :file (unix-truename file))
+ (list :position (1+ position)))))
+ (file
+ (make-location (list :file (unix-truename file))
+ (list :function-name (string name))))
+ (t
+ `(:error ,(format nil "Unknown source location: ~S ~S ~S "
+ name file source-path))))))
+
+(defun clear-xref-info (namestring)
+ "Clear XREF notes pertaining to NAMESTRING.
+This is a workaround for a CMUCL bug: XREF records are cumulative."
+ (when c:*record-xref-info*
+ (let ((filename (truename namestring)))
+ (dolist (db (list xref::*who-calls*
+ #+cmu19 xref::*who-is-called*
+ #+cmu19 xref::*who-macroexpands*
+ xref::*who-references*
+ xref::*who-binds*
+ xref::*who-sets*))
+ (maphash (lambda (target contexts)
+ ;; XXX update during traversal?
+ (setf (gethash target db)
+ (delete filename contexts
+ :key #'xref:xref-context-file
+ :test #'equalp)))
+ db)))))
+
+
+;;;; Find callers and callees
+;;;
+;;; Find callers and callees by looking at the constant pool of
+;;; compiled code objects. We assume every fdefn object in the
+;;; constant pool corresponds to a call to that function. A better
+;;; strategy would be to use the disassembler to find actual
+;;; call-sites.
+
+(declaim (inline map-code-constants))
+(defun map-code-constants (code fn)
+ "Call FN for each constant in CODE's constant pool."
+ (check-type code kernel:code-component)
+ (loop for i from vm:code-constants-offset below (kernel:get-header-data code)
+ do (funcall fn (kernel:code-header-ref code i))))
+
+(defun function-callees (function)
+ "Return FUNCTION's callees as a list of functions."
+ (let ((callees '()))
+ (map-code-constants
+ (vm::find-code-object function)
+ (lambda (obj)
+ (when (kernel:fdefn-p obj)
+ (push (kernel:fdefn-function obj) callees))))
+ callees))
+
+(declaim (ext:maybe-inline map-allocated-code-components))
+(defun map-allocated-code-components (spaces fn)
+ "Call FN for each allocated code component in one of SPACES. FN
+receives the object as argument. SPACES should be a list of the
+symbols :dynamic, :static, or :read-only."
+ (dolist (space spaces)
+ (declare (inline vm::map-allocated-objects)
+ (optimize (ext:inhibit-warnings 3)))
+ (vm::map-allocated-objects
+ (lambda (obj header size)
+ (declare (type fixnum size) (ignore size))
+ (when (= vm:code-header-type header)
+ (funcall fn obj)))
+ space)))
+
+(declaim (ext:maybe-inline map-caller-code-components))
+(defun map-caller-code-components (function spaces fn)
+ "Call FN for each code component with a fdefn for FUNCTION in its
+constant pool."
+ (let ((function (coerce function 'function)))
+ (declare (inline map-allocated-code-components))
+ (map-allocated-code-components
+ spaces
+ (lambda (obj)
+ (map-code-constants
+ obj
+ (lambda (constant)
+ (when (and (kernel:fdefn-p constant)
+ (eq (kernel:fdefn-function constant)
+ function))
+ (funcall fn obj))))))))
+
+(defun function-callers (function &optional (spaces '(:read-only :static
+ :dynamic)))
+ "Return FUNCTION's callers. The result is a list of code-objects."
+ (let ((referrers '()))
+ (declare (inline map-caller-code-components))
+ ;;(ext:gc :full t)
+ (map-caller-code-components function spaces
+ (lambda (code) (push code referrers)))
+ referrers))
+
+(defun debug-info-definitions (debug-info)
+ "Return the defintions for a debug-info. This should only be used
+for code-object without entry points, i.e., byte compiled
+code (are theree others?)"
+ ;; This mess has only been tested with #'ext::skip-whitespace, a
+ ;; byte-compiled caller of #'read-char .
+ (check-type debug-info (and (not c::compiled-debug-info) c::debug-info))
+ (let ((name (c::debug-info-name debug-info))
+ (source (c::debug-info-source debug-info)))
+ (destructuring-bind (first) source
+ (ecase (c::debug-source-from first)
+ (:file
+ (list (list name
+ (make-location
+ (list :file (unix-truename (c::debug-source-name first)))
+ (list :function-name (string name))))))))))
+
+(defun code-component-entry-points (code)
+ "Return a list ((NAME LOCATION) ...) of function definitons for
+the code omponent CODE."
+ (let ((names '()))
+ (do ((f (kernel:%code-entry-points code) (kernel::%function-next f)))
+ ((not f))
+ (let ((name (kernel:%function-name f)))
+ (when (ext:valid-function-name-p name)
+ (push (list name (function-location f)) names))))
+ names))
+
+(defimplementation list-callers (symbol)
+ "Return a list ((NAME LOCATION) ...) of callers."
+ (let ((components (function-callers symbol))
+ (xrefs '()))
+ (dolist (code components)
+ (let* ((entry (kernel:%code-entry-points code))
+ (defs (if entry
+ (code-component-entry-points code)
+ ;; byte compiled stuff
+ (debug-info-definitions
+ (kernel:%code-debug-info code)))))
+ (setq xrefs (nconc defs xrefs))))
+ xrefs))
+
+(defimplementation list-callees (symbol)
+ (let ((fns (function-callees symbol)))
+ (mapcar (lambda (fn)
+ (list (kernel:%function-name fn)
+ (function-location fn)))
+ fns)))
+
+
+;;;; Resolving source locations
+;;;
+;;; Our mission here is to "resolve" references to code locations into
+;;; actual file/buffer names and character positions. The references
+;;; we work from come out of the compiler's statically-generated debug
+;;; information, such as `code-location''s and `debug-source''s. For
+;;; more details, see the "Debugger Programmer's Interface" section of
+;;; the CMUCL manual.
+;;;
+;;; The first step is usually to find the corresponding "source-path"
+;;; for the location. Once we have the source-path we can pull up the
+;;; source file and `READ' our way through to the right position. The
+;;; main source-code groveling work is done in
+;;; `swank-source-path-parser.lisp'.
+
+(defvar *debug-definition-finding* nil
+ "When true don't handle errors while looking for definitions.
+This is useful when debugging the definition-finding code.")
+
+(defvar *source-snippet-size* 256
+ "Maximum number of characters in a snippet of source code.
+Snippets at the beginning of definitions are used to tell Emacs what
+the definitions looks like, so that it can accurately find them by
+text search.")
+
+(defmacro safe-definition-finding (&body body)
+ "Execute BODY and return the source-location it returns.
+If an error occurs and `*debug-definition-finding*' is false, then
+return an error pseudo-location.
+
+The second return value is NIL if no error occurs, otherwise it is the
+condition object."
+ `(flet ((body () , at body))
+ (if *debug-definition-finding*
+ (body)
+ (handler-case (values (progn , at body) nil)
+ (error (c) (values `(:error ,(trim-whitespace (princ-to-string c)))
+ c))))))
+
+(defun trim-whitespace (string)
+ (string-trim #(#\newline #\space #\tab) string))
+
+(defun code-location-source-location (code-location)
+ "Safe wrapper around `code-location-from-source-location'."
+ (safe-definition-finding
+ (source-location-from-code-location code-location)))
+
+(defun source-location-from-code-location (code-location)
+ "Return the source location for CODE-LOCATION."
+ (let ((debug-fun (di:code-location-debug-function code-location)))
+ (when (di::bogus-debug-function-p debug-fun)
+ ;; Those lousy cheapskates! They've put in a bogus debug source
+ ;; because the code was compiled at a low debug setting.
+ (error "Bogus debug function: ~A" debug-fun)))
+ (let* ((debug-source (di:code-location-debug-source code-location))
+ (from (di:debug-source-from debug-source))
+ (name (di:debug-source-name debug-source)))
+ (ecase from
+ (:file
+ (location-in-file name code-location debug-source))
+ (:stream
+ (location-in-stream code-location debug-source))
+ (:lisp
+ ;; The location comes from a form passed to `compile'.
+ ;; The best we can do is return the form itself for printing.
+ (make-location
+ (list :source-form (with-output-to-string (*standard-output*)
+ (debug::print-code-location-source-form
+ code-location 100 t)))
+ (list :position 1))))))
+
+(defun location-in-file (filename code-location debug-source)
+ "Resolve the source location for CODE-LOCATION in FILENAME."
+ (let* ((code-date (di:debug-source-created debug-source))
+ (source-code (get-source-code filename code-date)))
+ (with-input-from-string (s source-code)
+ (make-location (list :file (unix-truename filename))
+ (list :position (1+ (code-location-stream-position
+ code-location s)))
+ `(:snippet ,(read-snippet s))))))
+
+(defun location-in-stream (code-location debug-source)
+ "Resolve the source location for a CODE-LOCATION from a stream.
+This only succeeds if the code was compiled from an Emacs buffer."
+ (unless (debug-source-info-from-emacs-buffer-p debug-source)
+ (error "The code is compiled from a non-SLIME stream."))
+ (let* ((info (c::debug-source-info debug-source))
+ (string (getf info :emacs-buffer-string))
+ (position (code-location-string-offset
+ code-location
+ string)))
+ (make-location
+ (list :buffer (getf info :emacs-buffer))
+ (list :position (+ (getf info :emacs-buffer-offset) position))
+ (list :snippet (with-input-from-string (s string)
+ (file-position s position)
+ (read-snippet s))))))
+
+;;;;; Function-name locations
+;;;
+(defun debug-info-function-name-location (debug-info)
+ "Return a function-name source-location for DEBUG-INFO.
+Function-name source-locations are a fallback for when precise
+positions aren't available."
+ (with-struct (c::debug-info- (fname name) source) debug-info
+ (with-struct (c::debug-source- info from name) (car source)
+ (ecase from
+ (:file
+ (make-location (list :file (namestring (truename name)))
+ (list :function-name (string fname))))
+ (:stream
+ (assert (debug-source-info-from-emacs-buffer-p (car source)))
+ (make-location (list :buffer (getf info :emacs-buffer))
+ (list :function-name (string fname))))
+ (:lisp
+ (make-location (list :source-form (princ-to-string (aref name 0)))
+ (list :position 1)))))))
+
+(defun debug-source-info-from-emacs-buffer-p (debug-source)
+ "Does the `info' slot of DEBUG-SOURCE contain an Emacs buffer location?
+This is true for functions that were compiled directly from buffers."
+ (info-from-emacs-buffer-p (c::debug-source-info debug-source)))
+
+(defun info-from-emacs-buffer-p (info)
+ (and info
+ (consp info)
+ (eq :emacs-buffer (car info))))
+
+
+;;;;; Groveling source-code for positions
+
+(defun code-location-stream-position (code-location stream)
+ "Return the byte offset of CODE-LOCATION in STREAM. Extract the
+toplevel-form-number and form-number from CODE-LOCATION and use that
+to find the position of the corresponding form.
+
+Finish with STREAM positioned at the start of the code location."
+ (let* ((location (debug::maybe-block-start-location code-location))
+ (tlf-offset (di:code-location-top-level-form-offset location))
+ (form-number (di:code-location-form-number location)))
+ (let ((pos (form-number-stream-position tlf-offset form-number stream)))
+ (file-position stream pos)
+ pos)))
+
+(defun form-number-stream-position (tlf-number form-number stream)
+ "Return the starting character position of a form in STREAM.
+TLF-NUMBER is the top-level-form number.
+FORM-NUMBER is an index into a source-path table for the TLF."
+ (multiple-value-bind (tlf position-map) (read-source-form tlf-number stream)
+ (let* ((path-table (di:form-number-translations tlf 0))
+ (source-path
+ (if (<= (length path-table) form-number) ; source out of sync?
+ (list 0) ; should probably signal a condition
+ (reverse (cdr (aref path-table form-number))))))
+ (source-path-source-position source-path tlf position-map))))
+
+(defun code-location-string-offset (code-location string)
+ "Return the byte offset of CODE-LOCATION in STRING.
+See CODE-LOCATION-STREAM-POSITION."
+ (with-input-from-string (s string)
+ (code-location-stream-position code-location s)))
+
+
+;;;; Finding definitions
+
+;;; There are a great many different types of definition for us to
+;;; find. We search for definitions of every kind and return them in a
+;;; list.
+
+(defimplementation find-definitions (name)
+ (append (function-definitions name)
+ (setf-definitions name)
+ (variable-definitions name)
+ (class-definitions name)
+ (type-definitions name)
+ (compiler-macro-definitions name)
+ (source-transform-definitions name)
+ (function-info-definitions name)
+ (ir1-translator-definitions name)))
+
+;;;;; Functions, macros, generic functions, methods
+;;;
+;;; We make extensive use of the compile-time debug information that
+;;; CMUCL records, in particular "debug functions" and "code
+;;; locations." Refer to the "Debugger Programmer's Interface" section
+;;; of the CMUCL manual for more details.
+
+(defun function-definitions (name)
+ "Return definitions for NAME in the \"function namespace\", i.e.,
+regular functions, generic functions, methods and macros.
+NAME can any valid function name (e.g, (setf car))."
+ (let ((macro? (and (symbolp name) (macro-function name)))
+ (special? (and (symbolp name) (special-operator-p name)))
+ (function? (and (ext:valid-function-name-p name)
+ (ext:info :function :definition name)
+ (if (symbolp name) (fboundp name) t))))
+ (cond (macro?
+ (list `((defmacro ,name)
+ ,(function-location (macro-function name)))))
+ (special?
+ (list `((:special-operator ,name)
+ (:error ,(format nil "Special operator: ~S" name)))))
+ (function?
+ (let ((function (fdefinition name)))
+ (if (genericp function)
+ (generic-function-definitions name function)
+ (list (list `(function ,name)
+ (function-location function)))))))))
+
+;;;;;; Ordinary (non-generic/macro/special) functions
+;;;
+;;; First we test if FUNCTION is a closure created by defstruct, and
+;;; if so extract the defstruct-description (`dd') from the closure
+;;; and find the constructor for the struct. Defstruct creates a
+;;; defun for the default constructor and we use that as an
+;;; approximation to the source location of the defstruct.
+;;;
+;;; For an ordinary function we return the source location of the
+;;; first code-location we find.
+;;;
+(defun function-location (function)
+ "Return the source location for FUNCTION."
+ (cond ((struct-closure-p function)
+ (struct-closure-location function))
+ ((c::byte-function-or-closure-p function)
+ (byte-function-location function))
+ (t
+ (compiled-function-location function))))
+
+(defun compiled-function-location (function)
+ "Return the location of a regular compiled function."
+ (multiple-value-bind (code-location error)
+ (safe-definition-finding (function-first-code-location function))
+ (cond (error (list :error (princ-to-string error)))
+ (t (code-location-source-location code-location)))))
+
+(defun function-first-code-location (function)
+ "Return the first code-location we can find for FUNCTION."
+ (and (function-has-debug-function-p function)
+ (di:debug-function-start-location
+ (di:function-debug-function function))))
+
+(defun function-has-debug-function-p (function)
+ (di:function-debug-function function))
+
+(defun function-code-object= (closure function)
+ (and (eq (vm::find-code-object closure)
+ (vm::find-code-object function))
+ (not (eq closure function))))
+
+(defun byte-function-location (fun)
+ "Return the location of the byte-compiled function FUN."
+ (etypecase fun
+ ((or c::hairy-byte-function c::simple-byte-function)
+ (let* ((di (kernel:%code-debug-info (c::byte-function-component fun))))
+ (if di
+ (debug-info-function-name-location di)
+ `(:error
+ ,(format nil "Byte-function without debug-info: ~a" fun)))))
+ (c::byte-closure
+ (byte-function-location (c::byte-closure-function fun)))))
+
+;;; Here we deal with structure accessors. Note that `dd' is a
+;;; "defstruct descriptor" structure in CMUCL. A `dd' describes a
+;;; `defstruct''d structure.
+
+(defun struct-closure-p (function)
+ "Is FUNCTION a closure created by defstruct?"
+ (or (function-code-object= function #'kernel::structure-slot-accessor)
+ (function-code-object= function #'kernel::structure-slot-setter)
+ (function-code-object= function #'kernel::%defstruct)))
+
+(defun struct-closure-location (function)
+ "Return the location of the structure that FUNCTION belongs to."
+ (assert (struct-closure-p function))
+ (safe-definition-finding
+ (dd-location (struct-closure-dd function))))
+
+(defun struct-closure-dd (function)
+ "Return the defstruct-definition (dd) of FUNCTION."
+ (assert (= (kernel:get-type function) vm:closure-header-type))
+ (flet ((find-layout (function)
+ (sys:find-if-in-closure
+ (lambda (x)
+ (let ((value (if (di::indirect-value-cell-p x)
+ (c:value-cell-ref x)
+ x)))
+ (when (kernel::layout-p value)
+ (return-from find-layout value))))
+ function)))
+ (kernel:layout-info (find-layout function))))
+
+(defun dd-location (dd)
+ "Return the location of a `defstruct'."
+ ;; Find the location in a constructor.
+ (function-location (struct-constructor dd)))
+
+(defun struct-constructor (dd)
+ "Return a constructor function from a defstruct definition.
+Signal an error if no constructor can be found."
+ (let ((constructor (or (kernel:dd-default-constructor dd)
+ (car (kernel::dd-constructors dd)))))
+ (when (or (null constructor)
+ (and (consp constructor) (null (car constructor))))
+ (error "Cannot find structure's constructor: ~S"
+ (kernel::dd-name dd)))
+ (coerce (if (consp constructor) (first constructor) constructor)
+ 'function)))
+
+;;;;;; Generic functions and methods
+
+(defun generic-function-definitions (name function)
+ "Return the definitions of a generic function and its methods."
+ (cons (list `(defgeneric ,name) (gf-location function))
+ (gf-method-definitions function)))
+
+(defun gf-location (gf)
+ "Return the location of the generic function GF."
+ (definition-source-location gf (pcl::generic-function-name gf)))
+
+(defun gf-method-definitions (gf)
+ "Return the locations of all methods of the generic function GF."
+ (mapcar #'method-definition (pcl::generic-function-methods gf)))
+
+(defun method-definition (method)
+ (list (method-dspec method)
+ (method-location method)))
+
+(defun method-dspec (method)
+ "Return a human-readable \"definition specifier\" for METHOD."
+ (let* ((gf (pcl:method-generic-function method))
+ (name (pcl:generic-function-name gf))
+ (specializers (pcl:method-specializers method))
+ (qualifiers (pcl:method-qualifiers method)))
+ `(method ,name , at qualifiers ,(pcl::unparse-specializers specializers))))
+
+;; XXX maybe special case setters/getters
+(defun method-location (method)
+ (function-location (or (pcl::method-fast-function method)
+ (pcl:method-function method))))
+
+(defun genericp (fn)
+ (typep fn 'generic-function))
+
+;;;;;; Types and classes
+
+(defun type-definitions (name)
+ "Return `deftype' locations for type NAME."
+ (maybe-make-definition (ext:info :type :expander name) 'deftype name))
+
+(defun maybe-make-definition (function kind name)
+ "If FUNCTION is non-nil then return its definition location."
+ (if function
+ (list (list `(,kind ,name) (function-location function)))))
+
+(defun class-definitions (name)
+ "Return the definition locations for the class called NAME."
+ (if (symbolp name)
+ (let ((class (kernel::find-class name nil)))
+ (etypecase class
+ (null '())
+ (kernel::structure-class
+ (list (list `(defstruct ,name) (dd-location (find-dd name)))))
+ #+(or)
+ (conditions::condition-class
+ (list (list `(define-condition ,name)
+ (condition-class-location class))))
+ (kernel::standard-class
+ (list (list `(defclass ,name)
+ (class-location (find-class name)))))
+ ((or kernel::built-in-class
+ conditions::condition-class
+ kernel:funcallable-structure-class)
+ (list (list `(kernel::define-type-class ,name)
+ `(:error
+ ,(format nil "No source info for ~A" name)))))))))
+
+(defun class-location (class)
+ "Return the `defclass' location for CLASS."
+ (definition-source-location class (pcl:class-name class)))
+
+(defun find-dd (name)
+ "Find the defstruct-definition by the name of its structure-class."
+ (let ((layout (ext:info :type :compiler-layout name)))
+ (if layout
+ (kernel:layout-info layout))))
+
+(defun condition-class-location (class)
+ (let ((slots (conditions::condition-class-slots class))
+ (name (conditions::condition-class-name class)))
+ (cond ((null slots)
+ `(:error ,(format nil "No location info for condition: ~A" name)))
+ (t
+ ;; Find the class via one of its slot-reader methods.
+ (let* ((slot (first slots))
+ (gf (fdefinition
+ (first (conditions::condition-slot-readers slot)))))
+ (method-location
+ (first
+ (pcl:compute-applicable-methods-using-classes
+ gf (list (find-class name))))))))))
+
+(defun make-name-in-file-location (file string)
+ (multiple-value-bind (filename c)
+ (ignore-errors
+ (unix-truename (merge-pathnames (make-pathname :type "lisp")
+ file)))
+ (cond (filename (make-location `(:file ,filename)
+ `(:function-name ,(string string))))
+ (t (list :error (princ-to-string c))))))
+
+(defun source-location-form-numbers (location)
+ (c::decode-form-numbers (c::form-numbers-form-numbers location)))
+
+(defun source-location-tlf-number (location)
+ (nth-value 0 (source-location-form-numbers location)))
+
+(defun source-location-form-number (location)
+ (nth-value 1 (source-location-form-numbers location)))
+
+(defun resolve-file-source-location (location)
+ (let ((filename (c::file-source-location-pathname location))
+ (tlf-number (source-location-tlf-number location))
+ (form-number (source-location-form-number location)))
+ (with-open-file (s filename)
+ (let ((pos (form-number-stream-position tlf-number form-number s)))
+ (make-location `(:file ,(unix-truename filename))
+ `(:position ,(1+ pos)))))))
+
+(defun resolve-stream-source-location (location)
+ (let ((info (c::stream-source-location-user-info location))
+ (tlf-number (source-location-tlf-number location))
+ (form-number (source-location-form-number location)))
+ ;; XXX duplication in frame-source-location
+ (assert (info-from-emacs-buffer-p info))
+ (destructuring-bind (&key emacs-buffer emacs-buffer-string
+ emacs-buffer-offset) info
+ (with-input-from-string (s emacs-buffer-string)
+ (let ((pos (form-number-stream-position tlf-number form-number s)))
+ (make-location `(:buffer ,emacs-buffer)
+ `(:position ,(+ emacs-buffer-offset pos))))))))
+
+;; XXX predicates for 18e backward compatibilty. Remove them when
+;; we're 19a only.
+(defun file-source-location-p (object)
+ (when (fboundp 'c::file-source-location-p)
+ (c::file-source-location-p object)))
+
+(defun stream-source-location-p (object)
+ (when (fboundp 'c::stream-source-location-p)
+ (c::stream-source-location-p object)))
+
+(defun source-location-p (object)
+ (or (file-source-location-p object)
+ (stream-source-location-p object)))
+
+(defun resolve-source-location (location)
+ (etypecase location
+ ((satisfies file-source-location-p)
+ (resolve-file-source-location location))
+ ((satisfies stream-source-location-p)
+ (resolve-stream-source-location location))))
+
+(defun definition-source-location (object name)
+ (let ((source (pcl::definition-source object)))
+ (etypecase source
+ (null
+ `(:error ,(format nil "No source info for: ~A" object)))
+ ((satisfies source-location-p)
+ (resolve-source-location source))
+ (pathname
+ (make-name-in-file-location source name))
+ (cons
+ (destructuring-bind ((dg name) pathname) source
+ (declare (ignore dg))
+ (etypecase pathname
+ (pathname (make-name-in-file-location pathname (string name)))
+ (null `(:error ,(format nil "Cannot resolve: ~S" source)))))))))
+
+(defun setf-definitions (name)
+ (let ((function (or (ext:info :setf :inverse name)
+ (ext:info :setf :expander name)
+ (and (symbolp name)
+ (fboundp `(setf ,name))
+ (fdefinition `(setf ,name))))))
+ (if function
+ (list (list `(setf ,name)
+ (function-location (coerce function 'function)))))))
+
+
+(defun variable-location (symbol)
+ (multiple-value-bind (location foundp)
+ ;; XXX for 18e compatibilty. rewrite this when we drop 18e
+ ;; support.
+ (ignore-errors (eval `(ext:info :source-location :defvar ',symbol)))
+ (if (and foundp location)
+ (resolve-source-location location)
+ `(:error ,(format nil "No source info for variable ~S" symbol)))))
+
+(defun variable-definitions (name)
+ (if (symbolp name)
+ (multiple-value-bind (kind recorded-p) (ext:info :variable :kind name)
+ (if recorded-p
+ (list (list `(variable ,kind ,name)
+ (variable-location name)))))))
+
+(defun compiler-macro-definitions (symbol)
+ (maybe-make-definition (compiler-macro-function symbol)
+ 'define-compiler-macro
+ symbol))
+
+(defun source-transform-definitions (name)
+ (maybe-make-definition (ext:info :function :source-transform name)
+ 'c:def-source-transform
+ name))
+
+(defun function-info-definitions (name)
+ (let ((info (ext:info :function :info name)))
+ (if info
+ (append (loop for transform in (c::function-info-transforms info)
+ collect (list `(c:deftransform ,name
+ ,(c::type-specifier
+ (c::transform-type transform)))
+ (function-location (c::transform-function
+ transform))))
+ (maybe-make-definition (c::function-info-derive-type info)
+ 'c::derive-type name)
+ (maybe-make-definition (c::function-info-optimizer info)
+ 'c::optimizer name)
+ (maybe-make-definition (c::function-info-ltn-annotate info)
+ 'c::ltn-annotate name)
+ (maybe-make-definition (c::function-info-ir2-convert info)
+ 'c::ir2-convert name)
+ (loop for template in (c::function-info-templates info)
+ collect (list `(c::vop ,(c::template-name template))
+ (function-location
+ (c::vop-info-generator-function
+ template))))))))
+
+(defun ir1-translator-definitions (name)
+ (maybe-make-definition (ext:info :function :ir1-convert name)
+ 'c:def-ir1-translator name))
+
+
+;;;; Documentation.
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (flet ((doc (kind)
+ (or (documentation symbol kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (multiple-value-bind (kind recorded-p)
+ (ext:info variable kind symbol)
+ (declare (ignore kind))
+ (if (or (boundp symbol) recorded-p)
+ (doc 'variable))))
+ (when (fboundp symbol)
+ (maybe-push
+ (cond ((macro-function symbol) :macro)
+ ((special-operator-p symbol) :special-operator)
+ ((genericp (fdefinition symbol)) :generic-function)
+ (t :function))
+ (doc 'function)))
+ (maybe-push
+ :setf (if (or (ext:info setf inverse symbol)
+ (ext:info setf expander symbol))
+ (doc 'setf)))
+ (maybe-push
+ :type (if (ext:info type kind symbol)
+ (doc 'type)))
+ (maybe-push
+ :class (if (find-class symbol nil)
+ (doc 'class)))
+ (maybe-push
+ :alien-type (if (not (eq (ext:info alien-type kind symbol) :unknown))
+ (doc 'alien-type)))
+ (maybe-push
+ :alien-struct (if (ext:info alien-type struct symbol)
+ (doc nil)))
+ (maybe-push
+ :alien-union (if (ext:info alien-type union symbol)
+ (doc nil)))
+ (maybe-push
+ :alien-enum (if (ext:info alien-type enum symbol)
+ (doc nil)))
+ result)))
+
+(defimplementation describe-definition (symbol namespace)
+ (describe (ecase namespace
+ (:variable
+ symbol)
+ ((:function :generic-function)
+ (symbol-function symbol))
+ (:setf
+ (or (ext:info setf inverse symbol)
+ (ext:info setf expander symbol)))
+ (:type
+ (kernel:values-specifier-type symbol))
+ (:class
+ (find-class symbol))
+ (:alien-struct
+ (ext:info :alien-type :struct symbol))
+ (:alien-union
+ (ext:info :alien-type :union symbol))
+ (:alien-enum
+ (ext:info :alien-type :enum symbol))
+ (:alien-type
+ (ecase (ext:info :alien-type :kind symbol)
+ (:primitive
+ (let ((alien::*values-type-okay* t))
+ (funcall (ext:info :alien-type :translator symbol)
+ (list symbol))))
+ ((:defined)
+ (ext:info :alien-type :definition symbol))
+ (:unknown :unkown))))))
+
+;;;;; Argument lists
+
+(defimplementation arglist (fun)
+ (etypecase fun
+ (function (function-arglist fun))
+ (symbol (function-arglist (or (macro-function fun)
+ (symbol-function fun))))))
+
+(defun function-arglist (fun)
+ (let ((arglist
+ (cond ((eval:interpreted-function-p fun)
+ (eval:interpreted-function-arglist fun))
+ ((pcl::generic-function-p fun)
+ (pcl:generic-function-lambda-list fun))
+ ((c::byte-function-or-closure-p fun)
+ (byte-code-function-arglist fun))
+ ((kernel:%function-arglist (kernel:%function-self fun))
+ (handler-case (read-arglist fun)
+ (error () :not-available)))
+ ;; this should work both for compiled-debug-function
+ ;; and for interpreted-debug-function
+ (t
+ (handler-case (debug-function-arglist
+ (di::function-debug-function fun))
+ (di:unhandled-condition () :not-available))))))
+ (check-type arglist (or list (member :not-available)))
+ arglist))
+
+(defimplementation function-name (function)
+ (cond ((eval:interpreted-function-p function)
+ (eval:interpreted-function-name function))
+ ((pcl::generic-function-p function)
+ (pcl::generic-function-name function))
+ ((c::byte-function-or-closure-p function)
+ (c::byte-function-name function))
+ (t (kernel:%function-name (kernel:%function-self function)))))
+
+;;; A simple case: the arglist is available as a string that we can
+;;; `read'.
+
+(defun read-arglist (fn)
+ "Parse the arglist-string of the function object FN."
+ (let ((string (kernel:%function-arglist
+ (kernel:%function-self fn)))
+ (package (find-package
+ (c::compiled-debug-info-package
+ (kernel:%code-debug-info
+ (vm::find-code-object fn))))))
+ (with-standard-io-syntax
+ (let ((*package* (or package *package*)))
+ (read-from-string string)))))
+
+;;; A harder case: an approximate arglist is derived from available
+;;; debugging information.
+
+(defun debug-function-arglist (debug-function)
+ "Derive the argument list of DEBUG-FUNCTION from debug info."
+ (let ((args (di::debug-function-lambda-list debug-function))
+ (required '())
+ (optional '())
+ (rest '())
+ (key '()))
+ ;; collect the names of debug-vars
+ (dolist (arg args)
+ (etypecase arg
+ (di::debug-variable
+ (push (di::debug-variable-symbol arg) required))
+ ((member :deleted)
+ (push ':deleted required))
+ (cons
+ (ecase (car arg)
+ (:keyword
+ (push (second arg) key))
+ (:optional
+ (push (debug-variable-symbol-or-deleted (second arg)) optional))
+ (:rest
+ (push (debug-variable-symbol-or-deleted (second arg)) rest))))))
+ ;; intersperse lambda keywords as needed
+ (append (nreverse required)
+ (if optional (cons '&optional (nreverse optional)))
+ (if rest (cons '&rest (nreverse rest)))
+ (if key (cons '&key (nreverse key))))))
+
+(defun debug-variable-symbol-or-deleted (var)
+ (etypecase var
+ (di:debug-variable
+ (di::debug-variable-symbol var))
+ ((member :deleted)
+ '#:deleted)))
+
+(defun symbol-debug-function-arglist (fname)
+ "Return FNAME's debug-function-arglist and %function-arglist.
+A utility for debugging DEBUG-FUNCTION-ARGLIST."
+ (let ((fn (fdefinition fname)))
+ (values (debug-function-arglist (di::function-debug-function fn))
+ (kernel:%function-arglist (kernel:%function-self fn)))))
+
+;;; Deriving arglists for byte-compiled functions:
+;;;
+(defun byte-code-function-arglist (fn)
+ ;; There doesn't seem to be much arglist information around for
+ ;; byte-code functions. Use the arg-count and return something like
+ ;; (arg0 arg1 ...)
+ (etypecase fn
+ (c::simple-byte-function
+ (loop for i from 0 below (c::simple-byte-function-num-args fn)
+ collect (make-arg-symbol i)))
+ (c::hairy-byte-function
+ (hairy-byte-function-arglist fn))
+ (c::byte-closure
+ (byte-code-function-arglist (c::byte-closure-function fn)))))
+
+(defun make-arg-symbol (i)
+ (make-symbol (format nil "~A~D" (string 'arg) i)))
+
+;;; A "hairy" byte-function is one that takes a variable number of
+;;; arguments. `hairy-byte-function' is a type from the bytecode
+;;; interpreter.
+;;;
+(defun hairy-byte-function-arglist (fn)
+ (let ((counter -1))
+ (flet ((next-arg () (make-arg-symbol (incf counter))))
+ (with-struct (c::hairy-byte-function- min-args max-args rest-arg-p
+ keywords-p keywords) fn
+ (let ((arglist '())
+ (optional (- max-args min-args)))
+ ;; XXX isn't there a better way to write this?
+ ;; (Looks fine to me. -luke)
+ (dotimes (i min-args)
+ (push (next-arg) arglist))
+ (when (plusp optional)
+ (push '&optional arglist)
+ (dotimes (i optional)
+ (push (next-arg) arglist)))
+ (when rest-arg-p
+ (push '&rest arglist)
+ (push (next-arg) arglist))
+ (when keywords-p
+ (push '&key arglist)
+ (loop for (key _ __) in keywords
+ do (push key arglist))
+ (when (eq keywords-p :allow-others)
+ (push '&allow-other-keys arglist)))
+ (nreverse arglist))))))
+
+
+;;;; Miscellaneous.
+
+(defimplementation macroexpand-all (form)
+ (walker:macroexpand-all form))
+
+(defimplementation compiler-macroexpand-1 (form &optional env)
+ (ext:compiler-macroexpand-1 form env))
+
+(defimplementation compiler-macroexpand (form &optional env)
+ (ext:compiler-macroexpand form env))
+
+(defimplementation set-default-directory (directory)
+ (setf (ext:default-directory) (namestring directory))
+ ;; Setting *default-pathname-defaults* to an absolute directory
+ ;; makes the behavior of MERGE-PATHNAMES a bit more intuitive.
+ (setf *default-pathname-defaults* (pathname (ext:default-directory)))
+ (default-directory))
+
+(defimplementation default-directory ()
+ (namestring (ext:default-directory)))
+
+(defimplementation call-without-interrupts (fn)
+ (sys:without-interrupts (funcall fn)))
+
+(defimplementation getpid ()
+ (unix:unix-getpid))
+
+(defimplementation lisp-implementation-type-name ()
+ "cmucl")
+
+(defimplementation quit-lisp ()
+ (ext::quit))
+
+;;; source-path-{stream,file,string,etc}-position moved into
+;;; swank-source-path-parser
+
+
+;;;; Debugging
+
+(defvar *sldb-stack-top*)
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (unix:unix-sigsetmask 0)
+ (let* ((*sldb-stack-top* (or debug:*stack-top-hint* (di:top-frame)))
+ (debug:*stack-top-hint* nil)
+ (kernel:*current-level* 0))
+ (handler-bind ((di::unhandled-condition
+ (lambda (condition)
+ (error (make-condition
+ 'sldb-condition
+ :original-condition condition)))))
+ (unwind-protect
+ (progn
+ #+(or)(sys:scrub-control-stack)
+ (funcall debugger-loop-fn))
+ #+(or)(sys:scrub-control-stack)
+ ))))
+
+(defun frame-down (frame)
+ (handler-case (di:frame-down frame)
+ (di:no-debug-info () nil)))
+
+(defun nth-frame (index)
+ (do ((frame *sldb-stack-top* (frame-down frame))
+ (i index (1- i)))
+ ((zerop i) frame)))
+
+(defimplementation compute-backtrace (start end)
+ (let ((end (or end most-positive-fixnum)))
+ (loop for f = (nth-frame start) then (frame-down f)
+ for i from start below end
+ while f
+ collect f)))
+
+(defimplementation print-frame (frame stream)
+ (let ((*standard-output* stream))
+ (handler-case
+ (debug::print-frame-call frame :verbosity 1 :number nil)
+ (error (e)
+ (ignore-errors (princ e stream))))))
+
+(defimplementation frame-source-location-for-emacs (index)
+ (code-location-source-location (di:frame-code-location (nth-frame index))))
+
+(defimplementation eval-in-frame (form index)
+ (di:eval-in-frame (nth-frame index) form))
+
+(defun frame-debug-vars (frame)
+ "Return a vector of debug-variables in frame."
+ (di::debug-function-debug-variables (di:frame-debug-function frame)))
+
+(defun debug-var-value (var frame location)
+ (let ((validity (di:debug-variable-validity var location)))
+ (ecase validity
+ (:valid (di:debug-variable-value var frame))
+ ((:invalid :unknown) (make-symbol (string validity))))))
+
+(defimplementation frame-locals (index)
+ (let* ((frame (nth-frame index))
+ (loc (di:frame-code-location frame))
+ (vars (frame-debug-vars frame)))
+ (loop for v across vars collect
+ (list :name (di:debug-variable-symbol v)
+ :id (di:debug-variable-id v)
+ :value (debug-var-value v frame loc)))))
+
+(defimplementation frame-var-value (frame var)
+ (let* ((frame (nth-frame frame))
+ (dvar (aref (frame-debug-vars frame) var)))
+ (debug-var-value dvar frame (di:frame-code-location frame))))
+
+(defimplementation frame-catch-tags (index)
+ (mapcar #'car (di:frame-catches (nth-frame index))))
+
+(defimplementation return-from-frame (index form)
+ (let ((sym (find-symbol (string 'find-debug-tag-for-frame)
+ :debug-internals)))
+ (if sym
+ (let* ((frame (nth-frame index))
+ (probe (funcall sym frame)))
+ (cond (probe (throw (car probe) (eval-in-frame form index)))
+ (t (format nil "Cannot return from frame: ~S" frame))))
+ "return-from-frame is not implemented in this version of CMUCL.")))
+
+(defimplementation activate-stepping (frame)
+ (set-step-breakpoints (nth-frame frame)))
+
+(defimplementation sldb-break-on-return (frame)
+ (break-on-return (nth-frame frame)))
+
+;;; We set the breakpoint in the caller which might be a bit confusing.
+;;;
+(defun break-on-return (frame)
+ (let* ((caller (di:frame-down frame))
+ (cl (di:frame-code-location caller)))
+ (flet ((hook (frame bp)
+ (when (frame-pointer= frame caller)
+ (di:delete-breakpoint bp)
+ (signal-breakpoint bp frame))))
+ (let* ((info (ecase (di:code-location-kind cl)
+ ((:single-value-return :unknown-return) nil)
+ (:known-return (debug-function-returns
+ (di:frame-debug-function frame)))))
+ (bp (di:make-breakpoint #'hook cl :kind :code-location
+ :info info)))
+ (di:activate-breakpoint bp)
+ `(:ok ,(format nil "Set breakpoint in ~A" caller))))))
+
+(defun frame-pointer= (frame1 frame2)
+ "Return true if the frame pointers of FRAME1 and FRAME2 are the same."
+ (sys:sap= (di::frame-pointer frame1) (di::frame-pointer frame2)))
+
+;;; The PC in escaped frames at a single-return-value point is
+;;; actually vm:single-value-return-byte-offset bytes after the
+;;; position given in the debug info. Here we try to recognize such
+;;; cases.
+;;;
+(defun next-code-locations (frame code-location)
+ "Like `debug::next-code-locations' but be careful in escaped frames."
+ (let ((next (debug::next-code-locations code-location)))
+ (flet ((adjust-pc ()
+ (let ((cl (di::copy-compiled-code-location code-location)))
+ (incf (di::compiled-code-location-pc cl)
+ vm:single-value-return-byte-offset)
+ cl)))
+ (cond ((and (di::compiled-frame-escaped frame)
+ (eq (di:code-location-kind code-location)
+ :single-value-return)
+ (= (length next) 1)
+ (di:code-location= (car next) (adjust-pc)))
+ (debug::next-code-locations (car next)))
+ (t
+ next)))))
+
+(defun set-step-breakpoints (frame)
+ (let ((cl (di:frame-code-location frame)))
+ (when (di:debug-block-elsewhere-p (di:code-location-debug-block cl))
+ (error "Cannot step in elsewhere code"))
+ (let* ((debug::*bad-code-location-types*
+ (remove :call-site debug::*bad-code-location-types*))
+ (next (next-code-locations frame cl)))
+ (cond (next
+ (let ((steppoints '()))
+ (flet ((hook (bp-frame bp)
+ (signal-breakpoint bp bp-frame)
+ (mapc #'di:delete-breakpoint steppoints)))
+ (dolist (code-location next)
+ (let ((bp (di:make-breakpoint #'hook code-location
+ :kind :code-location)))
+ (di:activate-breakpoint bp)
+ (push bp steppoints))))))
+ (t
+ (break-on-return frame))))))
+
+
+;; XXX the return values at return breakpoints should be passed to the
+;; user hooks. debug-int.lisp should be changed to do this cleanly.
+
+;;; The sigcontext and the PC for a breakpoint invocation are not
+;;; passed to user hook functions, but we need them to extract return
+;;; values. So we advice di::handle-breakpoint and bind the values to
+;;; special variables.
+;;;
+(defvar *breakpoint-sigcontext*)
+(defvar *breakpoint-pc*)
+
+;; XXX don't break old versions without fwrappers. Remove this one day.
+#+#.(cl:if (cl:find-package :fwrappers) '(and) '(or))
+(progn
+ (fwrappers:define-fwrapper bind-breakpoint-sigcontext (offset c sigcontext)
+ (let ((*breakpoint-sigcontext* sigcontext)
+ (*breakpoint-pc* offset))
+ (fwrappers:call-next-function)))
+ (fwrappers:set-fwrappers 'di::handle-breakpoint '())
+ (fwrappers:fwrap 'di::handle-breakpoint #'bind-breakpoint-sigcontext))
+
+(defun sigcontext-object (sc index)
+ "Extract the lisp object in sigcontext SC at offset INDEX."
+ (kernel:make-lisp-obj (vm:sigcontext-register sc index)))
+
+(defun known-return-point-values (sigcontext sc-offsets)
+ (let ((fp (system:int-sap (vm:sigcontext-register sigcontext
+ vm::cfp-offset))))
+ (system:without-gcing
+ (loop for sc-offset across sc-offsets
+ collect (di::sub-access-debug-var-slot fp sc-offset sigcontext)))))
+
+;;; CMUCL returns the first few values in registers and the rest on
+;;; the stack. In the multiple value case, the number of values is
+;;; stored in a dedicated register. The values of the registers can be
+;;; accessed in the sigcontext for the breakpoint. There are 3 kinds
+;;; of return conventions: :single-value-return, :unknown-return, and
+;;; :known-return.
+;;;
+;;; The :single-value-return convention returns the value in a
+;;; register without setting the nargs registers.
+;;;
+;;; The :unknown-return variant is used for multiple values. A
+;;; :unknown-return point consists actually of 2 breakpoints: one for
+;;; the single value case and one for the general case. The single
+;;; value breakpoint comes vm:single-value-return-byte-offset after
+;;; the multiple value breakpoint.
+;;;
+;;; The :known-return convention is used by local functions.
+;;; :known-return is currently not supported because we don't know
+;;; where the values are passed.
+;;;
+(defun breakpoint-values (breakpoint)
+ "Return the list of return values for a return point."
+ (flet ((1st (sc) (sigcontext-object sc (car vm::register-arg-offsets))))
+ (let ((sc (locally (declare (optimize (ext:inhibit-warnings 3)))
+ (alien:sap-alien *breakpoint-sigcontext* (* unix:sigcontext))))
+ (cl (di:breakpoint-what breakpoint)))
+ (ecase (di:code-location-kind cl)
+ (:single-value-return
+ (list (1st sc)))
+ (:known-return
+ (let ((info (di:breakpoint-info breakpoint)))
+ (if (vectorp info)
+ (known-return-point-values sc info)
+ (progn
+ ;;(break)
+ (list "<<known-return convention not supported>>" info)))))
+ (:unknown-return
+ (let ((mv-return-pc (di::compiled-code-location-pc cl)))
+ (if (= mv-return-pc *breakpoint-pc*)
+ (mv-function-end-breakpoint-values sc)
+ (list (1st sc)))))))))
+
+;; XXX: di::get-function-end-breakpoint-values takes 2 arguments in
+;; newer versions of CMUCL (after ~March 2005).
+(defun mv-function-end-breakpoint-values (sigcontext)
+ (let ((sym (find-symbol "FUNCTION-END-BREAKPOINT-VALUES/STANDARD" :di)))
+ (cond (sym (funcall sym sigcontext))
+ (t (di::get-function-end-breakpoint-values sigcontext)))))
+
+(defun debug-function-returns (debug-fun)
+ "Return the return style of DEBUG-FUN."
+ (let* ((cdfun (di::compiled-debug-function-compiler-debug-fun debug-fun)))
+ (c::compiled-debug-function-returns cdfun)))
+
+(define-condition breakpoint (simple-condition)
+ ((message :initarg :message :reader breakpoint.message)
+ (values :initarg :values :reader breakpoint.values))
+ (:report (lambda (c stream) (princ (breakpoint.message c) stream))))
+
+(defimplementation condition-extras (condition)
+ (typecase condition
+ (breakpoint
+ ;; pop up the source buffer
+ `((:show-frame-source 0)))
+ (t '())))
+
+(defun signal-breakpoint (breakpoint frame)
+ "Signal a breakpoint condition for BREAKPOINT in FRAME.
+Try to create a informative message."
+ (flet ((brk (values fstring &rest args)
+ (let ((msg (apply #'format nil fstring args))
+ (debug:*stack-top-hint* frame))
+ (break 'breakpoint :message msg :values values))))
+ (with-struct (di::breakpoint- kind what) breakpoint
+ (case kind
+ (:code-location
+ (case (di:code-location-kind what)
+ ((:single-value-return :known-return :unknown-return)
+ (let ((values (breakpoint-values breakpoint)))
+ (brk values "Return value: ~{~S ~}" values)))
+ (t
+ #+(or)
+ (when (eq (di:code-location-kind what) :call-site)
+ (call-site-function breakpoint frame))
+ (brk nil "Breakpoint: ~S ~S"
+ (di:code-location-kind what)
+ (di::compiled-code-location-pc what)))))
+ (:function-start
+ (brk nil "Function start breakpoint"))
+ (t (brk nil "Breakpoint: ~A in ~A" breakpoint frame))))))
+
+(defimplementation sldb-break-at-start (fname)
+ (let ((debug-fun (di:function-debug-function (coerce fname 'function))))
+ (cond ((not debug-fun)
+ `(:error ,(format nil "~S has no debug-function" fname)))
+ (t
+ (flet ((hook (frame bp &optional args cookie)
+ (declare (ignore args cookie))
+ (signal-breakpoint bp frame)))
+ (let ((bp (di:make-breakpoint #'hook debug-fun
+ :kind :function-start)))
+ (di:activate-breakpoint bp)
+ `(:ok ,(format nil "Set breakpoint in ~S" fname))))))))
+
+(defun frame-cfp (frame)
+ "Return the Control-Stack-Frame-Pointer for FRAME."
+ (etypecase frame
+ (di::compiled-frame (di::frame-pointer frame))
+ ((or di::interpreted-frame null) -1)))
+
+(defun frame-ip (frame)
+ "Return the (absolute) instruction pointer and the relative pc of FRAME."
+ (if (not frame)
+ -1
+ (let ((debug-fun (di::frame-debug-function frame)))
+ (etypecase debug-fun
+ (di::compiled-debug-function
+ (let* ((code-loc (di:frame-code-location frame))
+ (component (di::compiled-debug-function-component debug-fun))
+ (pc (di::compiled-code-location-pc code-loc))
+ (ip (sys:without-gcing
+ (sys:sap-int
+ (sys:sap+ (kernel:code-instructions component) pc)))))
+ (values ip pc)))
+ ((or di::bogus-debug-function di::interpreted-debug-function)
+ -1)))))
+
+(defun frame-registers (frame)
+ "Return the lisp registers CSP, CFP, IP, OCFP, LRA for FRAME-NUMBER."
+ (let* ((cfp (frame-cfp frame))
+ (csp (frame-cfp (di::frame-up frame)))
+ (ip (frame-ip frame))
+ (ocfp (frame-cfp (di::frame-down frame)))
+ (lra (frame-ip (di::frame-down frame))))
+ (values csp cfp ip ocfp lra)))
+
+(defun print-frame-registers (frame-number)
+ (let ((frame (di::frame-real-frame (nth-frame frame-number))))
+ (flet ((fixnum (p) (etypecase p
+ (integer p)
+ (sys:system-area-pointer (sys:sap-int p)))))
+ (apply #'format t "~
+CSP = ~X
+CFP = ~X
+IP = ~X
+OCFP = ~X
+LRA = ~X~%" (mapcar #'fixnum
+ (multiple-value-list (frame-registers frame)))))))
+
+
+(defimplementation disassemble-frame (frame-number)
+ "Return a string with the disassembly of frames code."
+ (print-frame-registers frame-number)
+ (terpri)
+ (let* ((frame (di::frame-real-frame (nth-frame frame-number)))
+ (debug-fun (di::frame-debug-function frame)))
+ (etypecase debug-fun
+ (di::compiled-debug-function
+ (let* ((component (di::compiled-debug-function-component debug-fun))
+ (fun (di:debug-function-function debug-fun)))
+ (if fun
+ (disassemble fun)
+ (disassem:disassemble-code-component component))))
+ (di::bogus-debug-function
+ (format t "~%[Disassembling bogus frames not implemented]")))))
+
+
+;;;; Inspecting
+
+(defclass cmucl-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'cmucl-inspector))
+
+(defconstant +lowtag-symbols+
+ '(vm:even-fixnum-type
+ vm:function-pointer-type
+ vm:other-immediate-0-type
+ vm:list-pointer-type
+ vm:odd-fixnum-type
+ vm:instance-pointer-type
+ vm:other-immediate-1-type
+ vm:other-pointer-type)
+ "Names of the constants that specify type tags.
+The `symbol-value' of each element is a type tag.")
+
+(defconstant +header-type-symbols+
+ (labels ((suffixp (suffix string)
+ (and (>= (length string) (length suffix))
+ (string= string suffix :start1 (- (length string)
+ (length suffix)))))
+ (header-type-symbol-p (x)
+ (and (suffixp "-TYPE" (symbol-name x))
+ (not (member x +lowtag-symbols+))
+ (boundp x)
+ (typep (symbol-value x) 'fixnum))))
+ (remove-if-not #'header-type-symbol-p
+ (append (apropos-list "-TYPE" "VM")
+ (apropos-list "-TYPE" "BIGNUM"))))
+ "A list of names of the type codes in boxed objects.")
+
+(defimplementation describe-primitive-type (object)
+ (with-output-to-string (*standard-output*)
+ (let* ((lowtag (kernel:get-lowtag object))
+ (lowtag-symbol (find lowtag +lowtag-symbols+ :key #'symbol-value)))
+ (format t "lowtag: ~A" lowtag-symbol)
+ (when (member lowtag (list vm:other-pointer-type
+ vm:function-pointer-type
+ vm:other-immediate-0-type
+ vm:other-immediate-1-type
+ ))
+ (let* ((type (kernel:get-type object))
+ (type-symbol (find type +header-type-symbols+
+ :key #'symbol-value)))
+ (format t ", type: ~A" type-symbol))))))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (cond ((di::indirect-value-cell-p o)
+ (values (format nil "~A is a value cell." o)
+ `("Value: " (:value ,(c:value-cell-ref o)))))
+ ((alien::alien-value-p o)
+ (inspect-alien-value o))
+ (t
+ (cmucl-inspect o))))
+
+(defun cmucl-inspect (o)
+ (destructuring-bind (text labeledp . parts) (inspect::describe-parts o)
+ (values (format nil "~A~%" text)
+ (if labeledp
+ (loop for (label . value) in parts
+ append (label-value-line label value))
+ (loop for value in parts for i from 0
+ append (label-value-line i value))))))
+
+(defmethod inspect-for-emacs ((o function) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (let ((header (kernel:get-type o)))
+ (cond ((= header vm:function-header-type)
+ (values (format nil "~A is a function." o)
+ (append (label-value-line*
+ ("Self" (kernel:%function-self o))
+ ("Next" (kernel:%function-next o))
+ ("Name" (kernel:%function-name o))
+ ("Arglist" (kernel:%function-arglist o))
+ ("Type" (kernel:%function-type o))
+ ("Code" (kernel:function-code-header o)))
+ (list
+ (with-output-to-string (s)
+ (disassem:disassemble-function o :stream s))))))
+ ((= header vm:closure-header-type)
+ (values (format nil "~A is a closure" o)
+ (append
+ (label-value-line "Function" (kernel:%closure-function o))
+ `("Environment:" (:newline))
+ (loop for i from 0 below (1- (kernel:get-closure-length o))
+ append (label-value-line
+ i (kernel:%closure-index-ref o i))))))
+ ((eval::interpreted-function-p o)
+ (cmucl-inspect o))
+ (t
+ (call-next-method)))))
+
+(defmethod inspect-for-emacs ((o kernel:funcallable-instance)
+ (i backend-inspector))
+ (declare (ignore i))
+ (values
+ (format nil "~A is a funcallable-instance." o)
+ (append (label-value-line*
+ (:function (kernel:%funcallable-instance-function o))
+ (:lexenv (kernel:%funcallable-instance-lexenv o))
+ (:layout (kernel:%funcallable-instance-layout o)))
+ (nth-value 1 (cmucl-inspect o)))))
+
+(defmethod inspect-for-emacs ((o kernel:code-component) (_ backend-inspector))
+ (declare (ignore _))
+ (values (format nil "~A is a code data-block." o)
+ (append
+ (label-value-line*
+ ("code-size" (kernel:%code-code-size o))
+ ("entry-points" (kernel:%code-entry-points o))
+ ("debug-info" (kernel:%code-debug-info o))
+ ("trace-table-offset" (kernel:code-header-ref
+ o vm:code-trace-table-offset-slot)))
+ `("Constants:" (:newline))
+ (loop for i from vm:code-constants-offset
+ below (kernel:get-header-data o)
+ append (label-value-line i (kernel:code-header-ref o i)))
+ `("Code:" (:newline)
+ , (with-output-to-string (s)
+ (cond ((kernel:%code-debug-info o)
+ (disassem:disassemble-code-component o :stream s))
+ (t
+ (disassem:disassemble-memory
+ (disassem::align
+ (+ (logandc2 (kernel:get-lisp-obj-address o)
+ vm:lowtag-mask)
+ (* vm:code-constants-offset vm:word-bytes))
+ (ash 1 vm:lowtag-bits))
+ (ash (kernel:%code-code-size o) vm:word-shift)
+ :stream s))))))))
+
+(defmethod inspect-for-emacs ((o kernel:fdefn) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values (format nil "~A is a fdenf object." o)
+ (label-value-line*
+ ("name" (kernel:fdefn-name o))
+ ("function" (kernel:fdefn-function o))
+ ("raw-addr" (sys:sap-ref-32
+ (sys:int-sap (kernel:get-lisp-obj-address o))
+ (* vm:fdefn-raw-addr-slot vm:word-bytes))))))
+
+(defmethod inspect-for-emacs ((o array) (inspector backend-inspector))
+ inspector
+ (if (typep o 'simple-array)
+ (call-next-method)
+ (values (format nil "~A is an array." o)
+ (label-value-line*
+ (:header (describe-primitive-type o))
+ (:rank (array-rank o))
+ (:fill-pointer (kernel:%array-fill-pointer o))
+ (:fill-pointer-p (kernel:%array-fill-pointer-p o))
+ (:elements (kernel:%array-available-elements o))
+ (:data (kernel:%array-data-vector o))
+ (:displacement (kernel:%array-displacement o))
+ (:displaced-p (kernel:%array-displaced-p o))
+ (:dimensions (array-dimensions o))))))
+
+(defmethod inspect-for-emacs ((o simple-vector) (inspector backend-inspector))
+ inspector
+ (values (format nil "~A is a simple-vector." o)
+ (append
+ (label-value-line*
+ (:header (describe-primitive-type o))
+ (:length (c::vector-length o)))
+ (loop for i below (length o)
+ append (label-value-line i (aref o i))))))
+
+(defun inspect-alien-record (alien)
+ (values
+ (format nil "~A is an alien value." alien)
+ (with-struct (alien::alien-value- sap type) alien
+ (with-struct (alien::alien-record-type- kind name fields) type
+ (append
+ (label-value-line*
+ (:sap sap)
+ (:kind kind)
+ (:name name))
+ (loop for field in fields
+ append (let ((slot (alien::alien-record-field-name field)))
+ (label-value-line slot (alien:slot alien slot)))))))))
+
+(defun inspect-alien-pointer (alien)
+ (values
+ (format nil "~A is an alien value." alien)
+ (with-struct (alien::alien-value- sap type) alien
+ (label-value-line*
+ (:sap sap)
+ (:type type)
+ (:to (alien::deref alien))))))
+
+(defun inspect-alien-value (alien)
+ (typecase (alien::alien-value-type alien)
+ (alien::alien-record-type (inspect-alien-record alien))
+ (alien::alien-pointer-type (inspect-alien-pointer alien))
+ (t (cmucl-inspect alien))))
+
+;;;; Profiling
+(defimplementation profile (fname)
+ (eval `(profile:profile ,fname)))
+
+(defimplementation unprofile (fname)
+ (eval `(profile:unprofile ,fname)))
+
+(defimplementation unprofile-all ()
+ (eval `(profile:unprofile))
+ "All functions unprofiled.")
+
+(defimplementation profile-report ()
+ (eval `(profile:report-time)))
+
+(defimplementation profile-reset ()
+ (eval `(profile:reset-time))
+ "Reset profiling counters.")
+
+(defimplementation profiled-functions ()
+ profile:*timed-functions*)
+
+(defimplementation profile-package (package callers methods)
+ (profile:profile-all :package package
+ :callers-p callers
+ #-cmu18e :methods #-cmu18e methods))
+
+
+;;;; Multiprocessing
+
+#+mp
+(progn
+ (defimplementation initialize-multiprocessing (continuation)
+ (mp::init-multi-processing)
+ (mp:make-process continuation :name "swank")
+ ;; Threads magic: this never returns! But top-level becomes
+ ;; available again.
+ (unless mp::*idle-process*
+ (mp::startup-idle-and-top-level-loops)))
+
+ (defimplementation spawn (fn &key name)
+ (mp:make-process fn :name (or name "Anonymous")))
+
+ (defvar *thread-id-counter* 0)
+
+ (defimplementation thread-id (thread)
+ (or (getf (mp:process-property-list thread) 'id)
+ (setf (getf (mp:process-property-list thread) 'id)
+ (incf *thread-id-counter*))))
+
+ (defimplementation find-thread (id)
+ (find id (all-threads)
+ :key (lambda (p) (getf (mp:process-property-list p) 'id))))
+
+ (defimplementation thread-name (thread)
+ (mp:process-name thread))
+
+ (defimplementation thread-status (thread)
+ (mp:process-whostate thread))
+
+ (defimplementation current-thread ()
+ mp:*current-process*)
+
+ (defimplementation all-threads ()
+ (copy-list mp:*all-processes*))
+
+ (defimplementation interrupt-thread (thread fn)
+ (mp:process-interrupt thread fn))
+
+ (defimplementation kill-thread (thread)
+ (mp:destroy-process thread))
+
+ (defvar *mailbox-lock* (mp:make-lock "mailbox lock"))
+
+ (defstruct (mailbox (:conc-name mailbox.))
+ (mutex (mp:make-lock "process mailbox"))
+ (queue '() :type list))
+
+ (defun mailbox (thread)
+ "Return THREAD's mailbox."
+ (mp:with-lock-held (*mailbox-lock*)
+ (or (getf (mp:process-property-list thread) 'mailbox)
+ (setf (getf (mp:process-property-list thread) 'mailbox)
+ (make-mailbox)))))
+
+ (defimplementation send (thread message)
+ (let* ((mbox (mailbox thread))
+ (mutex (mailbox.mutex mbox)))
+ (mp:with-lock-held (mutex)
+ (setf (mailbox.queue mbox)
+ (nconc (mailbox.queue mbox) (list message))))))
+
+ (defimplementation receive ()
+ (let* ((mbox (mailbox mp:*current-process*))
+ (mutex (mailbox.mutex mbox)))
+ (mp:process-wait "receive" #'mailbox.queue mbox)
+ (mp:with-lock-held (mutex)
+ (pop (mailbox.queue mbox)))))
+
+ ) ;; #+mp
+
+
+
+;;;; GC hooks
+;;;
+;;; Display GC messages in the echo area to avoid cluttering the
+;;; normal output.
+;;;
+
+;; this should probably not be here, but where else?
+(defun background-message (message)
+ (funcall (find-symbol (string :background-message) :swank)
+ message))
+
+(defun print-bytes (nbytes &optional stream)
+ "Print the number NBYTES to STREAM in KB, MB, or GB units."
+ (let ((names '((0 bytes) (10 kb) (20 mb) (30 gb) (40 tb) (50 eb))))
+ (multiple-value-bind (power name)
+ (loop for ((p1 n1) (p2 n2)) on names
+ while n2 do
+ (when (<= (expt 2 p1) nbytes (1- (expt 2 p2)))
+ (return (values p1 n1))))
+ (cond (name
+ (format stream "~,1F ~A" (/ nbytes (expt 2 power)) name))
+ (t
+ (format stream "~:D bytes" nbytes))))))
+
+(defconstant gc-generations 6)
+
+#+gencgc
+(defun generation-stats ()
+ "Return a string describing the size distribution among the generations."
+ (let* ((alloc (loop for i below gc-generations
+ collect (lisp::gencgc-stats i)))
+ (sum (coerce (reduce #'+ alloc) 'float)))
+ (format nil "~{~3F~^/~}"
+ (mapcar (lambda (size) (/ size sum))
+ alloc))))
+
+(defvar *gc-start-time* 0)
+
+(defun pre-gc-hook (bytes-in-use)
+ (setq *gc-start-time* (get-internal-real-time))
+ (let ((msg (format nil "[Commencing GC with ~A in use.]"
+ (print-bytes bytes-in-use))))
+ (background-message msg)))
+
+(defun post-gc-hook (bytes-retained bytes-freed trigger)
+ (declare (ignore trigger))
+ (let* ((seconds (/ (- (get-internal-real-time) *gc-start-time*)
+ internal-time-units-per-second))
+ (msg (format nil "[GC done. ~A freed ~A retained ~A ~4F sec]"
+ (print-bytes bytes-freed)
+ (print-bytes bytes-retained)
+ #+gencgc(generation-stats)
+ #-gencgc""
+ seconds)))
+ (background-message msg)))
+
+(defun install-gc-hooks ()
+ (setq ext:*gc-notify-before* #'pre-gc-hook)
+ (setq ext:*gc-notify-after* #'post-gc-hook))
+
+(defun remove-gc-hooks ()
+ (setq ext:*gc-notify-before* #'lisp::default-gc-notify-before)
+ (setq ext:*gc-notify-after* #'lisp::default-gc-notify-after))
+
+(defvar *install-gc-hooks* t
+ "If non-nil install GC hooks")
+
+(defimplementation emacs-connected ()
+ (when *install-gc-hooks*
+ (install-gc-hooks)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;Trace implementations
+;;In CMUCL, we have:
+;; (trace <name>)
+;; (trace (method <name> <qualifier>? (<specializer>+)))
+;; (trace :methods t '<name>) ;;to trace all methods of the gf <name>
+;; <name> can be a normal name or a (setf name)
+
+(defun tracedp (spec)
+ (member spec (eval '(trace)) :test #'equal))
+
+(defun toggle-trace-aux (spec &rest options)
+ (cond ((tracedp spec)
+ (eval `(untrace ,spec))
+ (format nil "~S is now untraced." spec))
+ (t
+ (eval `(trace ,spec , at options))
+ (format nil "~S is now traced." spec))))
+
+(defimplementation toggle-trace (spec)
+ (ecase (car spec)
+ ((setf)
+ (toggle-trace-aux spec))
+ ((:defgeneric)
+ (let ((name (second spec)))
+ (toggle-trace-aux name :methods name)))
+ ((:defmethod)
+ (cond ((fboundp `(method ,@(cdr spec)))
+ (toggle-trace-aux `(method ,(cdr spec))))
+ ;; Man, is this ugly
+ ((fboundp `(pcl::fast-method ,@(cdr spec)))
+ (toggle-trace-aux `(pcl::fast-method ,@(cdr spec))))
+ (t
+ (error 'undefined-function :name (cdr spec)))))
+ ((:call)
+ (destructuring-bind (caller callee) (cdr spec)
+ (toggle-trace-aux (process-fspec callee)
+ :wherein (list (process-fspec caller)))))
+ ;; doesn't work properly
+ ;; ((:labels :flet) (toggle-trace-aux (process-fspec spec)))
+ ))
+
+(defun process-fspec (fspec)
+ (cond ((consp fspec)
+ (ecase (first fspec)
+ ((:defun :defgeneric) (second fspec))
+ ((:defmethod)
+ `(method ,(second fspec) ,@(third fspec) ,(fourth fspec)))
+ ((:labels) `(labels ,(third fspec) ,(process-fspec (second fspec))))
+ ((:flet) `(flet ,(third fspec) ,(process-fspec (second fspec))))))
+ (t
+ fspec)))
+
+;;; Weak datastructures
+
+(defimplementation make-weak-key-hash-table (&rest args)
+ (apply #'make-hash-table :weak-p t args))
+
+;; Local Variables:
+;; pbook-heading-regexp: "^;;;\\(;+\\)"
+;; pbook-commentary-regexp: "^;;;\\($\\|[^;]\\)"
+;; End:
Added: branches/bos/thirdparty/emacs/slime/swank-corman.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-corman.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,580 @@
+;;;
+;;; swank-corman.lisp --- Corman Lisp specific code for SLIME.
+;;;
+;;; Copyright (C) 2004, 2005 Espen Wiborg (espenhw at grumblesmurf.org)
+;;;
+;;; License
+;;; =======
+;;; This software is provided 'as-is', without any express or implied
+;;; warranty. In no event will the author be held liable for any damages
+;;; arising from the use of this software.
+;;;
+;;; Permission is granted to anyone to use this software for any purpose,
+;;; including commercial applications, and to alter it and redistribute
+;;; it freely, subject to the following restrictions:
+;;;
+;;; 1. The origin of this software must not be misrepresented; you must
+;;; not claim that you wrote the original software. If you use this
+;;; software in a product, an acknowledgment in the product documentation
+;;; would be appreciated but is not required.
+;;;
+;;; 2. Altered source versions must be plainly marked as such, and must
+;;; not be misrepresented as being the original software.
+;;;
+;;; 3. This notice may not be removed or altered from any source
+;;; distribution.
+;;;
+;;; Notes
+;;; =====
+;;; You will need CCL 2.51, and you will *definitely* need to patch
+;;; CCL with the patches at
+;;; http://www.grumblesmurf.org/lisp/corman-patches, otherwise SLIME
+;;; will blow up in your face. You should also follow the
+;;; instructions on http://www.grumblesmurf.org/lisp/corman-slime.
+;;;
+;;; The only communication style currently supported is NIL.
+;;;
+;;; Starting CCL inside emacs (with M-x slime) seems to work for me
+;;; with Corman Lisp 2.51, but I have seen random failures with 2.5
+;;; (sometimes it works, other times it hangs on start or hangs when
+;;; initializing WinSock) - starting CCL externally and using M-x
+;;; slime-connect always works fine.
+;;;
+;;; Sometimes CCL gets confused and starts giving you random memory
+;;; access violation errors on startup; if this happens, try redumping
+;;; your image.
+;;;
+;;; What works
+;;; ==========
+;;; * Basic editing and evaluation
+;;; * Arglist display
+;;; * Compilation
+;;; * Loading files
+;;; * apropos/describe
+;;; * Debugger
+;;; * Inspector
+;;;
+;;; TODO
+;;; ====
+;;; * More debugger functionality (missing bits: restart-frame,
+;;; return-from-frame, disassemble-frame, activate-stepping,
+;;; toggle-trace)
+;;; * XREF
+;;; * Profiling
+;;; * More sophisticated communication styles than NIL
+;;;
+
+(in-package :swank-backend)
+
+;;; Pull in various needed bits
+(require :composite-streams)
+(require :sockets)
+(require :winbase)
+(require :lp)
+
+(use-package :gs)
+
+;; MOP stuff
+
+(defclass swank-mop:standard-slot-definition ()
+ ()
+ (:documentation "Dummy class created so that swank.lisp will compile and load."))
+
+(defun named-by-gensym-p (c)
+ (null (symbol-package (class-name c))))
+
+(deftype swank-mop:eql-specializer ()
+ '(satisfies named-by-gensym-p))
+
+(defun swank-mop:eql-specializer-object (specializer)
+ (with-hash-table-iterator (next-entry cl::*clos-singleton-specializers*)
+ (loop (multiple-value-bind (more key value)
+ (next-entry)
+ (unless more (return nil))
+ (when (eq specializer value)
+ (return key))))))
+
+(defun swank-mop:class-finalized-p (class)
+ (declare (ignore class))
+ t)
+
+(defun swank-mop:class-prototype (class)
+ (make-instance class))
+
+(defun swank-mop:specializer-direct-methods (obj)
+ (declare (ignore obj))
+ nil)
+
+(defun swank-mop:generic-function-argument-precedence-order (gf)
+ (generic-function-lambda-list gf))
+
+(defun swank-mop:generic-function-method-combination (gf)
+ (declare (ignore gf))
+ :standard)
+
+(defun swank-mop:generic-function-declarations (gf)
+ (declare (ignore gf))
+ nil)
+
+(defun swank-mop:slot-definition-documentation (slot)
+ (declare (ignore slot))
+ (getf slot :documentation nil))
+
+(defun swank-mop:slot-definition-type (slot)
+ (declare (ignore slot))
+ t)
+
+(import-swank-mop-symbols :cl '(;; classes
+ :standard-slot-definition
+ :eql-specializer
+ :eql-specializer-object
+ ;; standard class readers
+ :class-default-initargs
+ :class-direct-default-initargs
+ :class-finalized-p
+ :class-prototype
+ :specializer-direct-methods
+ ;; gf readers
+ :generic-function-argument-precedence-order
+ :generic-function-declarations
+ :generic-function-method-combination
+ ;; method readers
+ ;; slot readers
+ :slot-definition-documentation
+ :slot-definition-type))
+
+;;;; swank implementations
+
+;;; Debugger
+
+(defvar *stack-trace* nil)
+(defvar *frame-trace* nil)
+
+(defstruct frame
+ name function address debug-info variables)
+
+(defimplementation call-with-debugging-environment (fn)
+ (let* ((real-stack-trace (cl::stack-trace))
+ (*stack-trace* (cdr (member 'cl:invoke-debugger real-stack-trace
+ :key #'car)))
+ (*frame-trace*
+ (let* ((db::*debug-level* (1+ db::*debug-level*))
+ (db::*debug-frame-pointer* (db::stash-ebp
+ (ct:create-foreign-ptr)))
+ (db::*debug-max-level* (length real-stack-trace))
+ (db::*debug-min-level* 1))
+ (cdr (member #'cl:invoke-debugger
+ (cons
+ (make-frame :function nil)
+ (loop for i from db::*debug-min-level*
+ upto db::*debug-max-level*
+ until (eq (db::get-frame-function i) cl::*top-level*)
+ collect
+ (make-frame :function (db::get-frame-function i)
+ :address (db::get-frame-address i))))
+ :key #'frame-function)))))
+ (funcall fn)))
+
+(defimplementation compute-backtrace (start end)
+ (subseq *stack-trace* start (min end (length *stack-trace*))))
+
+(defimplementation print-frame (frame stream)
+ (format stream "~S" frame))
+
+(defun get-frame-debug-info (frame)
+ (or (frame-debug-info frame)
+ (setf (frame-debug-info frame)
+ (db::prepare-frame-debug-info (frame-function frame)
+ (frame-address frame)))))
+
+(defimplementation frame-locals (frame-number)
+ (let* ((frame (elt *frame-trace* frame-number))
+ (info (get-frame-debug-info frame)))
+ (let ((var-list
+ (loop for i from 4 below (length info) by 2
+ collect `(list :name ',(svref info i) :id 0
+ :value (db::debug-filter ,(svref info i))))))
+ (let ((vars (eval-in-frame `(list , at var-list) frame-number)))
+ (setf (frame-variables frame) vars)))))
+
+(defimplementation eval-in-frame (form frame-number)
+ (let ((frame (elt *frame-trace* frame-number)))
+ (let ((cl::*compiler-environment* (get-frame-debug-info frame)))
+ (eval form))))
+
+(defimplementation frame-catch-tags (index)
+ (declare (ignore index))
+ nil)
+
+(defimplementation frame-var-value (frame-number var)
+ (let ((vars (frame-variables (elt *frame-trace* frame-number))))
+ (when vars
+ (second (elt vars var)))))
+
+(defimplementation frame-source-location-for-emacs (frame-number)
+ (fspec-location (frame-function (elt *frame-trace* frame-number))))
+
+(defun break (&optional (format-control "Break") &rest format-arguments)
+ (with-simple-restart (continue "Return from BREAK.")
+ (let ();(*debugger-hook* nil))
+ (let ((condition
+ (make-condition 'simple-condition
+ :format-control format-control
+ :format-arguments format-arguments)))
+ ;;(format *debug-io* ";;; User break: ~A~%" condition)
+ (invoke-debugger condition))))
+ nil)
+
+;;; Socket communication
+
+(defimplementation create-socket (host port)
+ (sockets:start-sockets)
+ (sockets:make-server-socket :host host :port port))
+
+(defimplementation local-port (socket)
+ (sockets:socket-port socket))
+
+(defimplementation close-socket (socket)
+ (close socket))
+
+(defimplementation accept-connection (socket
+ &key external-format buffering timeout)
+ (declare (ignore buffering timeout external-format))
+ (sockets:make-socket-stream (sockets:accept-socket socket)))
+
+;;; Misc
+
+(defimplementation preferred-communication-style ()
+ nil)
+
+(defimplementation getpid ()
+ ccl:*current-process-id*)
+
+(defimplementation lisp-implementation-type-name ()
+ "cormanlisp")
+
+(defimplementation quit-lisp ()
+ (sockets:stop-sockets)
+ (win32:exitprocess 0))
+
+(defimplementation set-default-directory (directory)
+ (setf (ccl:current-directory) directory)
+ (directory-namestring (setf *default-pathname-defaults*
+ (truename (merge-pathnames directory)))))
+
+(defimplementation default-directory ()
+ (directory-namestring (ccl:current-directory)))
+
+(defimplementation macroexpand-all (form)
+ (ccl:macroexpand-all form))
+
+;;; Documentation
+
+(defun fspec-location (fspec)
+ (when (symbolp fspec)
+ (setq fspec (symbol-function fspec)))
+ (let ((file (ccl::function-source-file fspec)))
+ (if file
+ (handler-case
+ (let ((truename (truename
+ (merge-pathnames file
+ ccl:*cormanlisp-directory*))))
+ (make-location (list :file (namestring truename))
+ (if (ccl::function-source-line fspec)
+ (list :line
+ (1+ (ccl::function-source-line fspec)))
+ (list :function-name (princ-to-string
+ (function-name fspec))))))
+ (error (c) (list :error (princ-to-string c))))
+ (list :error (format nil "No source information available for ~S"
+ fspec)))))
+
+(defimplementation find-definitions (name)
+ (list (list name (fspec-location name))))
+
+(defimplementation arglist (name)
+ (handler-case
+ (cond ((and (symbolp name)
+ (macro-function name))
+ (ccl::macro-lambda-list (symbol-function name)))
+ (t
+ (when (symbolp name)
+ (setq name (symbol-function name)))
+ (if (eq (class-of name) cl::the-class-standard-gf)
+ (generic-function-lambda-list name)
+ (ccl:function-lambda-list name))))
+ (error () :not-available)))
+
+(defimplementation function-name (fn)
+ (handler-case (getf (cl::function-info-list fn) 'cl::function-name)
+ (error () nil)))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (flet ((doc (kind &optional (sym symbol))
+ (or (documentation sym kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (when (boundp symbol)
+ (doc 'variable)))
+ (maybe-push
+ :function (if (fboundp symbol)
+ (doc 'function)))
+ (maybe-push
+ :class (if (find-class symbol nil)
+ (doc 'class)))
+ result)))
+
+(defimplementation describe-definition (symbol namespace)
+ (ecase namespace
+ (:variable
+ (describe symbol))
+ ((:function :generic-function)
+ (describe (symbol-function symbol)))
+ (:class
+ (describe (find-class symbol)))))
+
+;;; Compiler
+
+(defvar *buffer-name* nil)
+(defvar *buffer-position*)
+(defvar *buffer-string*)
+(defvar *compile-filename* nil)
+
+;; FIXME
+(defimplementation call-with-compilation-hooks (FN)
+ (handler-bind ((error (lambda (c)
+ (signal (make-condition
+ 'compiler-condition
+ :original-condition c
+ :severity :warning
+ :message (format nil "~A" c)
+ :location
+ (cond (*buffer-name*
+ (make-location
+ (list :buffer *buffer-name*)
+ (list :position *buffer-position*)))
+ (*compile-filename*
+ (make-location
+ (list :file *compile-filename*)
+ (list :position 1)))
+ (t
+ (list :error "No location"))))))))
+ (funcall fn)))
+
+(defimplementation swank-compile-file (*compile-filename* load-p
+ external-format)
+ (declare (ignore external-format))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* nil))
+ (compile-file *compile-filename*)
+ (when load-p
+ (load (compile-file-pathname *compile-filename*))))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-position* position)
+ (*buffer-string* string))
+ (funcall (compile nil (read-from-string
+ (format nil "(~S () ~A)" 'lambda string)))))))
+
+;;;; Inspecting
+
+;; Hack to make swank.lisp load, at least
+(defclass file-stream ())
+
+(defclass corman-inspector (backend-inspector)
+ ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'corman-inspector))
+
+(defun comma-separated (list &optional (callback (lambda (v)
+ `(:value ,v))))
+ (butlast (loop for e in list
+ collect (funcall callback e)
+ collect ", ")))
+
+(defmethod inspect-for-emacs ((class standard-class)
+ (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values "A class."
+ `("Name: " (:value ,(class-name class))
+ (:newline)
+ "Super classes: "
+ ,@(comma-separated (swank-mop:class-direct-superclasses class))
+ (:newline)
+ "Direct Slots: "
+ ,@(comma-separated
+ (swank-mop:class-direct-slots class)
+ (lambda (slot)
+ `(:value ,slot ,(princ-to-string (swank-mop:slot-definition-name slot)))))
+ (:newline)
+ "Effective Slots: "
+ ,@(if (swank-mop:class-finalized-p class)
+ (comma-separated
+ (swank-mop:class-slots class)
+ (lambda (slot)
+ `(:value ,slot ,(princ-to-string
+ (swank-mop:slot-definition-name slot)))))
+ '("#<N/A (class not finalized)>"))
+ (:newline)
+ ,@(when (documentation class t)
+ `("Documentation:" (:newline) ,(documentation class t) (:newline)))
+ "Sub classes: "
+ ,@(comma-separated (swank-mop:class-direct-subclasses class)
+ (lambda (sub)
+ `(:value ,sub ,(princ-to-string (class-name sub)))))
+ (:newline)
+ "Precedence List: "
+ ,@(if (swank-mop:class-finalized-p class)
+ (comma-separated (swank-mop:class-precedence-list class)
+ (lambda (class)
+ `(:value ,class ,(princ-to-string (class-name class)))))
+ '("#<N/A (class not finalized)>"))
+ (:newline))))
+
+(defmethod inspect-for-emacs ((slot cons) (inspector backend-inspector))
+ ;; Inspects slot definitions
+ (declare (ignore inspector))
+ (if (eq (car slot) :name)
+ (values "A slot."
+ `("Name: " (:value ,(swank-mop:slot-definition-name slot))
+ (:newline)
+ ,@(when (swank-mop:slot-definition-documentation slot)
+ `("Documentation:" (:newline)
+ (:value ,(swank-mop:slot-definition-documentation slot))
+ (:newline)))
+ "Init args: " (:value ,(swank-mop:slot-definition-initargs slot)) (:newline)
+ "Init form: " ,(if (swank-mop:slot-definition-initfunction slot)
+ `(:value ,(swank-mop:slot-definition-initform slot))
+ "#<unspecified>") (:newline)
+ "Init function: " (:value ,(swank-mop:slot-definition-initfunction slot))
+ (:newline)))
+ (call-next-method)))
+
+(defmethod inspect-for-emacs ((pathname pathnames::pathname-internal)
+ inspector)
+ (declare (ignore inspector))
+ (values (if (wild-pathname-p pathname)
+ "A wild pathname."
+ "A pathname.")
+ (append (label-value-line*
+ ("Namestring" (namestring pathname))
+ ("Host" (pathname-host pathname))
+ ("Device" (pathname-device pathname))
+ ("Directory" (pathname-directory pathname))
+ ("Name" (pathname-name pathname))
+ ("Type" (pathname-type pathname))
+ ("Version" (pathname-version pathname)))
+ (unless (or (wild-pathname-p pathname)
+ (not (probe-file pathname)))
+ (label-value-line "Truename" (truename pathname))))))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (cond ((cl::structurep o) (inspect-structure o))
+ (t (call-next-method))))
+
+(defun inspect-structure (o)
+ (values
+ (format nil "~A is a structure" o)
+ (let* ((template (cl::uref o 1))
+ (num-slots (cl::struct-template-num-slots template)))
+ (cond ((symbolp template)
+ (loop for i below num-slots
+ append (label-value-line i (cl::uref o (+ 2 i)))))
+ (t
+ (loop for i below num-slots
+ append (label-value-line (elt template (+ 6 (* i 5)))
+ (cl::uref o (+ 2 i)))))))))
+
+
+;;; Threads
+
+(require 'threads)
+
+(defstruct (mailbox (:conc-name mailbox.))
+ thread
+ (lock (make-instance 'threads:critical-section))
+ (queue '() :type list))
+
+(defvar *mailbox-lock* (make-instance 'threads:critical-section))
+(defvar *mailboxes* (list))
+
+(defmacro with-lock (lock &body body)
+ `(threads:with-synchronization (threads:cs ,lock)
+ , at body))
+
+(defimplementation spawn (fun &key name)
+ (declare (ignore name))
+ (th:create-thread
+ (lambda ()
+ (handler-bind ((serious-condition #'invoke-debugger))
+ (unwind-protect (funcall fun)
+ (with-lock *mailbox-lock*
+ (setq *mailboxes* (remove cormanlisp:*current-thread-id*
+ *mailboxes* :key #'mailbox.thread))))))))
+
+(defimplementation thread-id (thread)
+ thread)
+
+(defimplementation find-thread (thread)
+ (if (thread-alive-p thread)
+ thread))
+
+(defimplementation thread-alive-p (thread)
+ (if (threads:thread-handle thread) t nil))
+
+(defimplementation current-thread ()
+ cormanlisp:*current-thread-id*)
+
+;; XXX implement it
+(defimplementation all-threads ()
+ '())
+
+;; XXX something here is broken
+(defimplementation kill-thread (thread)
+ (threads:terminate-thread thread 'killed))
+
+(defun mailbox (thread)
+ (with-lock *mailbox-lock*
+ (or (find thread *mailboxes* :key #'mailbox.thread)
+ (let ((mb (make-mailbox :thread thread)))
+ (push mb *mailboxes*)
+ mb))))
+
+(defimplementation send (thread message)
+ (let ((mbox (mailbox thread)))
+ (with-lock (mailbox.lock mbox)
+ (setf (mailbox.queue mbox)
+ (nconc (mailbox.queue mbox) (list message))))))
+
+(defimplementation receive ()
+ (let ((mbox (mailbox cormanlisp:*current-thread-id*)))
+ (loop
+ (with-lock (mailbox.lock mbox)
+ (when (mailbox.queue mbox)
+ (return (pop (mailbox.queue mbox)))))
+ (sleep 0.1))))
+
+
+;;; This is probably not good, but it WFM
+(in-package :common-lisp)
+
+(defvar *old-documentation* #'documentation)
+(defun documentation (thing &optional (type 'function))
+ (if (symbolp thing)
+ (funcall *old-documentation* thing type)
+ (values)))
+
+(defmethod print-object ((restart restart) stream)
+ (if (or *print-escape*
+ *print-readably*)
+ (print-unreadable-object (restart stream :type t :identity t)
+ (princ (restart-name restart) stream))
+ (when (functionp (restart-report-function restart))
+ (funcall (restart-report-function restart) stream))))
Added: branches/bos/thirdparty/emacs/slime/swank-ecl.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-ecl.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,416 @@
+;;;; -*- indent-tabs-mode: nil -*-
+;;;
+;;; swank-ecl.lisp --- SLIME backend for ECL.
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+;;; Administrivia
+
+(in-package :swank-backend)
+
+(import-from :ext *gray-stream-symbols* :swank-backend)
+
+(swank-backend::import-swank-mop-symbols :clos
+ '(:eql-specializer
+ :eql-specializer-object
+ :generic-function-declarations
+ :specializer-direct-methods
+ :compute-applicable-methods-using-classes))
+
+
+;;;; TCP Server
+
+(require 'sockets)
+
+(defun resolve-hostname (name)
+ (car (sb-bsd-sockets:host-ent-addresses
+ (sb-bsd-sockets:get-host-by-name name))))
+
+(defimplementation create-socket (host port)
+ (let ((socket (make-instance 'sb-bsd-sockets:inet-socket
+ :type :stream
+ :protocol :tcp)))
+ (setf (sb-bsd-sockets:sockopt-reuse-address socket) t)
+ (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port)
+ (sb-bsd-sockets:socket-listen socket 5)
+ socket))
+
+(defimplementation local-port (socket)
+ (nth-value 1 (sb-bsd-sockets:socket-name socket)))
+
+(defimplementation close-socket (socket)
+ (sb-bsd-sockets:socket-close socket))
+
+(defimplementation accept-connection (socket
+ &key external-format
+ buffering timeout)
+ (declare (ignore buffering timeout external-format))
+ (make-socket-io-stream (accept socket)))
+
+(defun make-socket-io-stream (socket)
+ (sb-bsd-sockets:socket-make-stream socket
+ :output t
+ :input t
+ :element-type 'base-char))
+
+(defun accept (socket)
+ "Like socket-accept, but retry on EAGAIN."
+ (loop (handler-case
+ (return (sb-bsd-sockets:socket-accept socket))
+ (sb-bsd-sockets:interrupted-error ()))))
+
+(defimplementation preferred-communication-style ()
+ (values nil))
+
+
+;;;; Unix signals
+
+(defimplementation getpid ()
+ (si:getpid))
+
+#+nil
+(defimplementation set-default-directory (directory)
+ (ext::chdir (namestring directory))
+ ;; Setting *default-pathname-defaults* to an absolute directory
+ ;; makes the behavior of MERGE-PATHNAMES a bit more intuitive.
+ (setf *default-pathname-defaults* (ext::getcwd))
+ (default-directory))
+
+#+nil
+(defimplementation default-directory ()
+ (namestring (ext:getcwd)))
+
+(defimplementation quit-lisp ()
+ (ext:quit))
+
+
+;;;; Compilation
+
+(defvar *buffer-name* nil)
+(defvar *buffer-start-position*)
+(defvar *buffer-string*)
+(defvar *compile-filename*)
+
+(defun signal-compiler-condition (&rest args)
+ (signal (apply #'make-condition 'compiler-condition args)))
+
+(defun handle-compiler-warning (condition)
+ (signal-compiler-condition
+ :original-condition condition
+ :message (format nil "~A" condition)
+ :severity :warning
+ :location
+ (if *buffer-name*
+ (make-location (list :buffer *buffer-name*)
+ (list :position *buffer-start-position*))
+ ;; ;; compiler::*current-form*
+ ;; (if compiler::*current-function*
+ ;; (make-location (list :file *compile-filename*)
+ ;; (list :function-name
+ ;; (symbol-name
+ ;; (slot-value compiler::*current-function*
+ ;; 'compiler::name))))
+ (list :error "No location found.")
+ ;; )
+ )))
+
+(defimplementation call-with-compilation-hooks (function)
+ (handler-bind ((warning #'handle-compiler-warning))
+ (funcall function)))
+
+(defimplementation swank-compile-file (*compile-filename* load-p
+ external-format)
+ (declare (ignore external-format))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* nil))
+ (multiple-value-bind (fn warn fail)
+ (compile-file *compile-filename*)
+ (when load-p (unless fail (load fn)))))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-start-position* position)
+ (*buffer-string* string))
+ (with-input-from-string (s string)
+ (compile-from-stream s :load t)))))
+
+(defun compile-from-stream (stream &rest args)
+ (let ((file (si::mkstemp "TMP:ECLXXXXXX")))
+ (with-open-file (s file :direction :output :if-exists :overwrite)
+ (do ((line (read-line stream nil) (read-line stream nil)))
+ ((not line))
+ (write-line line s)))
+ (unwind-protect
+ (apply #'compile-file file args)
+ (delete-file file))))
+
+
+;;;; Documentation
+
+(defimplementation arglist (name)
+ (or (functionp name) (setf name (symbol-function name)))
+ (if (functionp name)
+ (typecase name
+ (generic-function
+ (clos::generic-function-lambda-list name))
+ (compiled-function
+ ; most of the compiled functions have an Args: line in their docs
+ (with-input-from-string (s (or
+ (si::get-documentation
+ (si:compiled-function-name name) 'function)
+ ""))
+ (do ((line (read-line s nil) (read-line s nil)))
+ ((not line) :not-available)
+ (ignore-errors
+ (if (string= (subseq line 0 6) "Args: ")
+ (return-from nil
+ (read-from-string (subseq line 6))))))))
+ ;
+ (function
+ (let ((fle (function-lambda-expression name)))
+ (case (car fle)
+ (si:lambda-block (caddr fle))
+ (t :not-available)))))
+ :not-available))
+
+(defimplementation function-name (f)
+ (si:compiled-function-name f))
+
+(defimplementation macroexpand-all (form)
+ ;;; FIXME! This is not the same as a recursive macroexpansion!
+ (macroexpand form))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (dolist (type '(:VARIABLE :FUNCTION :CLASS))
+ (let ((doc (describe-definition symbol type)))
+ (when doc
+ (setf result (list* type doc result)))))
+ result))
+
+(defimplementation describe-definition (name type)
+ (case type
+ (:variable (documentation name 'variable))
+ (:function (documentation name 'function))
+ (:class (documentation name 'class))
+ (t nil)))
+
+;;; Debugging
+
+(import
+ '(si::*ihs-top*
+ si::*ihs-current*
+ si::*ihs-base*
+ si::*frs-base*
+ si::*frs-top*
+ si::*tpl-commands*
+ si::*tpl-level*
+ si::frs-top
+ si::ihs-top
+ si::sch-frs-base
+ si::set-break-env
+ si::set-current-ihs
+ si::tpl-commands))
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (declare (type function debugger-loop-fn))
+ (let* ((*tpl-commands* si::tpl-commands)
+ (*ihs-top* (ihs-top 'call-with-debugging-environment))
+ (*ihs-current* *ihs-top*)
+ (*frs-base* (or (sch-frs-base *frs-top* *ihs-base*) (1+ (frs-top))))
+ (*frs-top* (frs-top))
+ (*read-suppress* nil)
+ (*tpl-level* (1+ *tpl-level*)))
+ (set-break-env)
+ (set-current-ihs)
+ (funcall debugger-loop-fn)))
+
+;; (defimplementation call-with-debugger-hook (hook fun)
+;; (let ((*debugger-hook* hook))
+;; (funcall fun)))
+
+(defun nth-frame (n)
+ (cond ((>= n *ihs-top* ) nil)
+ (t (- *ihs-top* n))))
+
+(defimplementation compute-backtrace (start end)
+ (loop for i from start below end
+ for f = (nth-frame i)
+ while f
+ collect f))
+
+(defimplementation print-frame (frame stream)
+ (format stream "~A" (si::ihs-fname frame)))
+
+;;;; Inspector
+
+(defclass ecl-inspector (inspector)
+ ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'ecl-inspector))
+
+;;;; Definitions
+
+(defimplementation find-definitions (name) nil)
+
+;;;; Threads
+
+#+threads
+(progn
+ (defvar *thread-id-counter* 0)
+
+ (defvar *thread-id-counter-lock*
+ (mp:make-lock :name "thread id counter lock"))
+
+ (defun next-thread-id ()
+ (mp:with-lock (*thread-id-counter-lock*)
+ (incf *thread-id-counter*)))
+
+ (defparameter *thread-id-map* (make-hash-table))
+
+ (defvar *thread-id-map-lock*
+ (mp:make-lock :name "thread id map lock"))
+
+ ; ecl doesn't have weak pointers
+ (defimplementation spawn (fn &key name)
+ (let ((thread (mp:make-process :name name))
+ (id (next-thread-id)))
+ (mp:process-preset
+ thread
+ #'(lambda ()
+ (unwind-protect
+ (mp:with-lock (*thread-id-map-lock*)
+ (setf (gethash id *thread-id-map*) thread))
+ (funcall fn)
+ (mp:with-lock (*thread-id-map-lock*)
+ (remhash id *thread-id-map*)))))
+ (mp:process-enable thread)))
+
+ (defimplementation thread-id (thread)
+ (block thread-id
+ (mp:with-lock (*thread-id-map-lock*)
+ (loop for id being the hash-key in *thread-id-map*
+ using (hash-value thread-pointer)
+ do (if (eq thread thread-pointer)
+ (return-from thread-id id))))))
+
+ (defimplementation find-thread (id)
+ (mp:with-lock (*thread-id-map-lock*)
+ (gethash id *thread-id-map*)))
+
+ (defimplementation thread-name (thread)
+ (mp:process-name thread))
+
+ (defimplementation thread-status (thread)
+ (if (mp:process-active-p thread)
+ "RUNNING"
+ "STOPPED"))
+
+ (defimplementation make-lock (&key name)
+ (mp:make-lock :name name))
+
+ (defimplementation call-with-lock-held (lock function)
+ (declare (type function function))
+ (mp:with-lock (lock) (funcall function)))
+
+ (defimplementation make-recursive-lock (&key name)
+ (mp:make-lock :name name))
+
+ (defimplementation call-with-recursive-lock-held (lock function)
+ (declare (type function function))
+ (mp:with-lock (lock) (funcall function)))
+
+ (defimplementation current-thread ()
+ mp:*current-process*)
+
+ (defimplementation all-threads ()
+ (mp:all-processes))
+
+ (defimplementation interrupt-thread (thread fn)
+ (mp:interrupt-process thread fn))
+
+ (defimplementation kill-thread (thread)
+ (mp:process-kill thread))
+
+ (defimplementation thread-alive-p (thread)
+ (mp:process-active-p thread))
+
+ (defvar *mailbox-lock* (mp:make-lock :name "mailbox lock"))
+
+ (defstruct (mailbox (:conc-name mailbox.))
+ (mutex (mp:make-lock :name "process mailbox"))
+ (queue '() :type list))
+
+ (defun mailbox (thread)
+ "Return THREAD's mailbox."
+ (mp:with-lock (*mailbox-lock*)
+ (or (find thread *mailboxes* :key #'mailbox.thread)
+ (let ((mb (make-mailbox :thread thread)))
+ (push mb *mailboxes*)
+ mb))))
+
+ (defimplementation send (thread message)
+ (let* ((mbox (mailbox thread))
+ (mutex (mailbox.mutex mbox)))
+ (mp:interrupt-process
+ thread
+ (lambda ()
+ (mp:with-lock (mutex)
+ (setf (mailbox.queue mbox)
+ (nconc (mailbox.queue mbox) (list message))))))))
+
+ (defimplementation receive ()
+ (block got-mail
+ (let* ((mbox (mailbox mp:*current-process*))
+ (mutex (mailbox.mutex mbox)))
+ (loop
+ (mp:with-lock (mutex)
+ (if (mailbox.queue mbox)
+ (return-from got-mail (pop (mailbox.queue mbox)))))
+ ;interrupt-process will halt this if it takes longer than 1sec
+ (sleep 1)))))
+
+ ;; Auto-flush streams
+ (defvar *auto-flush-interval* 0.15
+ "How often to flush interactive streams. This valu is passed
+ directly to cl:sleep.")
+
+ (defvar *auto-flush-lock* (make-recursive-lock :name "auto flush"))
+
+ (defvar *auto-flush-thread* nil)
+
+ (defvar *auto-flush-streams* '())
+
+ (defimplementation make-stream-interactive (stream)
+ (call-with-recursive-lock-held
+ *auto-flush-lock*
+ (lambda ()
+ (pushnew stream *auto-flush-streams*)
+ (unless *auto-flush-thread*
+ (setq *auto-flush-thread*
+ (spawn #'flush-streams
+ :name "auto-flush-thread"))))))
+
+ (defmethod stream-finish-output ((stream stream))
+ (finish-output stream))
+
+ (defun flush-streams ()
+ (loop
+ (call-with-recursive-lock-held
+ *auto-flush-lock*
+ (lambda ()
+ (setq *auto-flush-streams*
+ (remove-if (lambda (x)
+ (not (and (open-stream-p x)
+ (output-stream-p x))))
+ *auto-flush-streams*))
+ (mapc #'stream-finish-output *auto-flush-streams*)))
+ (sleep *auto-flush-interval*)))
+
+ )
+
Added: branches/bos/thirdparty/emacs/slime/swank-gray.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-gray.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,168 @@
+;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
+;;;
+;;; swank-gray.lisp --- Gray stream based IO redirection.
+;;;
+;;; Created 2003
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+(in-package :swank-backend)
+
+(defclass slime-output-stream (fundamental-character-output-stream)
+ ((output-fn :initarg :output-fn)
+ (buffer :initform (make-string 8000))
+ (fill-pointer :initform 0)
+ (column :initform 0)
+ (last-flush-time :initform (get-internal-real-time))
+ (lock :initform (make-recursive-lock :name "buffer write lock"))))
+
+(defmethod stream-write-char ((stream slime-output-stream) char)
+ (call-with-recursive-lock-held
+ (slot-value stream 'lock)
+ (lambda ()
+ (with-slots (buffer fill-pointer column) stream
+ (setf (schar buffer fill-pointer) char)
+ (incf fill-pointer)
+ (incf column)
+ (when (char= #\newline char)
+ (setf column 0)
+ (force-output stream))
+ (when (= fill-pointer (length buffer))
+ (finish-output stream)))))
+ char)
+
+(defmethod stream-line-column ((stream slime-output-stream))
+ (call-with-recursive-lock-held
+ (slot-value stream 'lock)
+ (lambda ()
+ (slot-value stream 'column))))
+
+(defmethod stream-line-length ((stream slime-output-stream))
+ 75)
+
+(defmethod stream-finish-output ((stream slime-output-stream))
+ (call-with-recursive-lock-held
+ (slot-value stream 'lock)
+ (lambda ()
+ (with-slots (buffer fill-pointer output-fn last-flush-time) stream
+ (let ((end fill-pointer))
+ (unless (zerop end)
+ (funcall output-fn (subseq buffer 0 end))
+ (setf fill-pointer 0)))
+ (setf last-flush-time (get-internal-real-time)))))
+ nil)
+
+(defmethod stream-force-output ((stream slime-output-stream))
+ (call-with-recursive-lock-held
+ (slot-value stream 'lock)
+ (lambda ()
+ (with-slots (last-flush-time fill-pointer) stream
+ (let ((now (get-internal-real-time)))
+ (when (> (/ (- now last-flush-time)
+ (coerce internal-time-units-per-second 'double-float))
+ 0.2)
+ (finish-output stream))))))
+ nil)
+
+(defmethod stream-fresh-line ((stream slime-output-stream))
+ (call-with-recursive-lock-held
+ (slot-value stream 'lock)
+ (lambda ()
+ (with-slots (column) stream
+ (cond ((zerop column) nil)
+ (t (terpri stream) t))))))
+
+(defclass slime-input-stream (fundamental-character-input-stream)
+ ((output-stream :initarg :output-stream)
+ (input-fn :initarg :input-fn)
+ (buffer :initform "") (index :initform 0)
+ (lock :initform (make-lock :name "buffer read lock"))))
+
+(defmethod stream-read-char ((s slime-input-stream))
+ (call-with-lock-held
+ (slot-value s 'lock)
+ (lambda ()
+ (with-slots (buffer index output-stream input-fn) s
+ (when (= index (length buffer))
+ (when output-stream
+ (finish-output output-stream))
+ (let ((string (funcall input-fn)))
+ (cond ((zerop (length string))
+ (return-from stream-read-char :eof))
+ (t
+ (setf buffer string)
+ (setf index 0)))))
+ (assert (plusp (length buffer)))
+ (prog1 (aref buffer index) (incf index))))))
+
+(defmethod stream-listen ((s slime-input-stream))
+ (call-with-lock-held
+ (slot-value s 'lock)
+ (lambda ()
+ (with-slots (buffer index) s
+ (< index (length buffer))))))
+
+(defmethod stream-unread-char ((s slime-input-stream) char)
+ (call-with-lock-held
+ (slot-value s 'lock)
+ (lambda ()
+ (with-slots (buffer index) s
+ (decf index)
+ (cond ((eql (aref buffer index) char)
+ (setf (aref buffer index) char))
+ (t
+ (warn "stream-unread-char: ignoring ~S (expected ~S)"
+ char (aref buffer index)))))))
+ nil)
+
+(defmethod stream-clear-input ((s slime-input-stream))
+ (call-with-lock-held
+ (slot-value s 'lock)
+ (lambda ()
+ (with-slots (buffer index) s
+ (setf buffer ""
+ index 0))))
+ nil)
+
+(defmethod stream-line-column ((s slime-input-stream))
+ nil)
+
+(defmethod stream-line-length ((s slime-input-stream))
+ 75)
+
+
+;;; CLISP extensions
+
+;; We have to define an additional method for the sake of the C
+;; function listen_char (see src/stream.d), on which SYS::READ-FORM
+;; depends.
+
+;; We could make do with either of the two methods below.
+
+(defmethod stream-read-char-no-hang ((s slime-input-stream))
+ (call-with-lock-held
+ (slot-value s 'lock)
+ (lambda ()
+ (with-slots (buffer index) s
+ (when (< index (length buffer))
+ (prog1 (aref buffer index) (incf index)))))))
+
+;; This CLISP extension is what listen_char actually calls. The
+;; default method would call STREAM-READ-CHAR-NO-HANG, so it is a bit
+;; more efficient to define it directly.
+
+(defmethod stream-read-char-will-hang-p ((s slime-input-stream))
+ (with-slots (buffer index) s
+ (= index (length buffer))))
+
+
+;;;
+(defimplementation make-fn-streams (input-fn output-fn)
+ (let* ((output (make-instance 'slime-output-stream
+ :output-fn output-fn))
+ (input (make-instance 'slime-input-stream
+ :input-fn input-fn
+ :output-stream output)))
+ (values input output)))
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/swank-lispworks.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-lispworks.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,791 @@
+;;; -*- indent-tabs-mode: nil -*-
+;;;
+;;; swank-lispworks.lisp --- LispWorks specific code for SLIME.
+;;;
+;;; Created 2003, Helmut Eller
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+(in-package :swank-backend)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (require "comm")
+ (import-from :stream *gray-stream-symbols* :swank-backend))
+
+(import-swank-mop-symbols :clos '(:slot-definition-documentation
+ :eql-specializer
+ :eql-specializer-object
+ :compute-applicable-methods-using-classes))
+
+(defun swank-mop:slot-definition-documentation (slot)
+ (documentation slot t))
+
+(defun swank-mop:compute-applicable-methods-using-classes (gf classes)
+ (clos::compute-applicable-methods-from-classes gf classes))
+
+;; lispworks doesn't have the eql-specializer class, it represents
+;; them as a list of `(EQL ,OBJECT)
+(deftype swank-mop:eql-specializer () 'cons)
+
+(defun swank-mop:eql-specializer-object (eql-spec)
+ (second eql-spec))
+
+(when (fboundp 'dspec::define-dspec-alias)
+ (dspec::define-dspec-alias defimplementation (name args &rest body)
+ `(defmethod ,name ,args , at body)))
+
+;;; TCP server
+
+(defimplementation preferred-communication-style ()
+ :spawn)
+
+(defun socket-fd (socket)
+ (etypecase socket
+ (fixnum socket)
+ (comm:socket-stream (comm:socket-stream-socket socket))))
+
+(defimplementation create-socket (host port)
+ (multiple-value-bind (socket where errno)
+ #-(or lispworks4.1 (and macosx lispworks4.3))
+ (comm::create-tcp-socket-for-service port :address host)
+ #+(or lispworks4.1 (and macosx lispworks4.3))
+ (comm::create-tcp-socket-for-service port)
+ (cond (socket socket)
+ (t (error 'network-error
+ :format-control "~A failed: ~A (~D)"
+ :format-arguments (list where
+ (list #+unix (lw:get-unix-error errno))
+ errno))))))
+
+(defimplementation local-port (socket)
+ (nth-value 1 (comm:get-socket-address (socket-fd socket))))
+
+(defimplementation close-socket (socket)
+ (comm::close-socket (socket-fd socket)))
+
+(defimplementation accept-connection (socket
+ &key external-format buffering timeout)
+ (declare (ignore buffering timeout external-format))
+ (let* ((fd (comm::get-fd-from-socket socket)))
+ (assert (/= fd -1))
+ (make-instance 'comm:socket-stream :socket fd :direction :io
+ :element-type 'base-char)))
+
+(defun set-sigint-handler ()
+ ;; Set SIGINT handler on Swank request handler thread.
+ #-win32
+ (sys::set-signal-handler +sigint+
+ (make-sigint-handler mp:*current-process*)))
+
+;;; Coding Systems
+
+(defvar *external-format-to-coding-system*
+ '(((:latin-1 :eol-style :lf)
+ "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix")
+ ((:latin-1)
+ "latin-1" "iso-latin-1" "iso-8859-1")
+ ((:utf-8) "utf-8")
+ ((:utf-8 :eol-style :lf) "utf-8-unix")
+ ((:euc-jp) "euc-jp")
+ ((:euc-jp :eol-style :lf) "euc-jp-unix")
+ ((:ascii) "us-ascii")
+ ((:ascii :eol-style :lf) "us-ascii-unix")))
+
+(defimplementation find-external-format (coding-system)
+ (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
+ *external-format-to-coding-system*)))
+
+;;; Unix signals
+
+(defun sigint-handler ()
+ (with-simple-restart (continue "Continue from SIGINT handler.")
+ (invoke-debugger "SIGINT")))
+
+(defun make-sigint-handler (process)
+ (lambda (&rest args)
+ (declare (ignore args))
+ (mp:process-interrupt process #'sigint-handler)))
+
+(defimplementation call-without-interrupts (fn)
+ (lw:without-interrupts (funcall fn)))
+
+(defimplementation getpid ()
+ #+win32 (win32:get-current-process-id)
+ #-win32 (system::getpid))
+
+(defimplementation lisp-implementation-type-name ()
+ "lispworks")
+
+(defimplementation set-default-directory (directory)
+ (namestring (hcl:change-directory directory)))
+
+;;;; Documentation
+
+(defimplementation arglist (symbol-or-function)
+ (let ((arglist (lw:function-lambda-list symbol-or-function)))
+ (etypecase arglist
+ ((member :dont-know)
+ :not-available)
+ (list
+ arglist))))
+
+(defimplementation function-name (function)
+ (nth-value 2 (function-lambda-expression function)))
+
+(defimplementation macroexpand-all (form)
+ (walker:walk-form form))
+
+(defun generic-function-p (object)
+ (typep object 'generic-function))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ "Return a plist describing SYMBOL.
+Return NIL if the symbol is unbound."
+ (let ((result '()))
+ (labels ((first-line (string)
+ (let ((pos (position #\newline string)))
+ (if (null pos) string (subseq string 0 pos))))
+ (doc (kind &optional (sym symbol))
+ (let ((string (documentation sym kind)))
+ (if string
+ (first-line string)
+ :not-documented)))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (when (boundp symbol)
+ (doc 'variable)))
+ (maybe-push
+ :generic-function (if (and (fboundp symbol)
+ (generic-function-p (fdefinition symbol)))
+ (doc 'function)))
+ (maybe-push
+ :function (if (and (fboundp symbol)
+ (not (generic-function-p (fdefinition symbol))))
+ (doc 'function)))
+ (maybe-push
+ :setf (let ((setf-name (sys:underlying-setf-name `(setf ,symbol))))
+ (if (fboundp setf-name)
+ (doc 'setf))))
+ (maybe-push
+ :class (if (find-class symbol nil)
+ (doc 'class)))
+ result)))
+
+(defimplementation describe-definition (symbol type)
+ (ecase type
+ (:variable (describe-symbol symbol))
+ (:class (describe (find-class symbol)))
+ ((:function :generic-function) (describe-function symbol))
+ (:setf (describe-function (sys:underlying-setf-name `(setf ,symbol))))))
+
+(defun describe-function (symbol)
+ (cond ((fboundp symbol)
+ (format t "~%(~A~{ ~A~})~%~%~:[(not documented)~;~:*~A~]~%"
+ (string-downcase symbol)
+ (mapcar #'string-upcase
+ (lispworks:function-lambda-list symbol))
+ (documentation symbol 'function))
+ (describe (fdefinition symbol)))
+ (t (format t "~S is not fbound" symbol))))
+
+(defun describe-symbol (sym)
+ (format t "~A is a symbol in package ~A." sym (symbol-package sym))
+ (when (boundp sym)
+ (format t "~%~%Value: ~A" (symbol-value sym)))
+ (let ((doc (documentation sym 'variable)))
+ (when doc
+ (format t "~%~%Variable documentation:~%~A" doc)))
+ (when (fboundp sym)
+ (describe-function sym)))
+
+;;; Debugging
+
+(defclass slime-env (env:environment)
+ ((debugger-hook :initarg :debugger-hoook)))
+
+(defun slime-env (hook io-bindings)
+ (make-instance 'slime-env :name "SLIME Environment"
+ :io-bindings io-bindings
+ :debugger-hoook hook))
+
+(defmethod env-internals:environment-display-notifier
+ ((env slime-env) &key restarts condition)
+ (declare (ignore restarts))
+ (funcall (slot-value env 'debugger-hook) condition *debugger-hook*))
+
+(defmethod env-internals:environment-display-debugger ((env slime-env))
+ *debug-io*)
+
+(defimplementation call-with-debugger-hook (hook fun)
+ (let ((*debugger-hook* hook))
+ (env:with-environment ((slime-env hook '()))
+ (funcall fun))))
+
+(defvar *sldb-top-frame*)
+
+(defun interesting-frame-p (frame)
+ (cond ((or (dbg::call-frame-p frame)
+ (dbg::derived-call-frame-p frame)
+ (dbg::foreign-frame-p frame)
+ (dbg::interpreted-call-frame-p frame))
+ t)
+ ((dbg::catch-frame-p frame) dbg:*print-catch-frames*)
+ ((dbg::binding-frame-p frame) dbg:*print-binding-frames*)
+ ((dbg::handler-frame-p frame) dbg:*print-handler-frames*)
+ ((dbg::restart-frame-p frame) dbg:*print-restart-frames*)
+ ((dbg::open-frame-p frame) dbg:*print-open-frames*)
+ (t nil)))
+
+(defun nth-next-frame (frame n)
+ "Unwind FRAME N times."
+ (do ((frame frame (dbg::frame-next frame))
+ (i n (if (interesting-frame-p frame) (1- i) i)))
+ ((or (not frame)
+ (and (interesting-frame-p frame) (zerop i)))
+ frame)))
+
+(defun nth-frame (index)
+ (nth-next-frame *sldb-top-frame* index))
+
+(defun find-top-frame ()
+ "Return the most suitable top-frame for the debugger."
+ (or (do ((frame (dbg::debugger-stack-current-frame dbg::*debugger-stack*)
+ (nth-next-frame frame 1)))
+ ((or (null frame) ; no frame found!
+ (and (dbg::call-frame-p frame)
+ (eq (dbg::call-frame-function-name frame)
+ 'invoke-debugger)))
+ (nth-next-frame frame 1)))
+ ;; if we can't find a invoke-debugger frame, take any old frame at the top
+ (dbg::debugger-stack-current-frame dbg::*debugger-stack*)))
+
+(defimplementation call-with-debugging-environment (fn)
+ (dbg::with-debugger-stack ()
+ (let ((*sldb-top-frame* (find-top-frame)))
+ (funcall fn))))
+
+(defimplementation compute-backtrace (start end)
+ (let ((end (or end most-positive-fixnum))
+ (backtrace '()))
+ (do ((frame (nth-frame start) (dbg::frame-next frame))
+ (i start))
+ ((or (not frame) (= i end)) (nreverse backtrace))
+ (when (interesting-frame-p frame)
+ (incf i)
+ (push frame backtrace)))))
+
+(defun frame-actual-args (frame)
+ (let ((*break-on-signals* nil))
+ (mapcar (lambda (arg)
+ (case arg
+ ((&rest &optional &key) arg)
+ (t
+ (handler-case (dbg::dbg-eval arg frame)
+ (error (e) (format nil "<~A>" arg))))))
+ (dbg::call-frame-arglist frame))))
+
+(defimplementation print-frame (frame stream)
+ (cond ((dbg::call-frame-p frame)
+ (format stream "~S ~S"
+ (dbg::call-frame-function-name frame)
+ (frame-actual-args frame)))
+ (t (princ frame stream))))
+
+(defun frame-vars (frame)
+ (first (dbg::frame-locals-format-list frame #'list 75 0)))
+
+(defimplementation frame-locals (n)
+ (let ((frame (nth-frame n)))
+ (if (dbg::call-frame-p frame)
+ (mapcar (lambda (var)
+ (destructuring-bind (name value symbol location) var
+ (declare (ignore name location))
+ (list :name symbol :id 0
+ :value value)))
+ (frame-vars frame)))))
+
+(defimplementation frame-var-value (frame var)
+ (let ((frame (nth-frame frame)))
+ (destructuring-bind (_n value _s _l) (nth var (frame-vars frame))
+ (declare (ignore _n _s _l))
+ value)))
+
+(defimplementation frame-catch-tags (index)
+ (declare (ignore index))
+ nil)
+
+(defimplementation frame-source-location-for-emacs (frame)
+ (let ((frame (nth-frame frame))
+ (callee (if (plusp frame) (nth-frame (1- frame)))))
+ (if (dbg::call-frame-p frame)
+ (let ((dspec (dbg::call-frame-function-name frame))
+ (cname (and (dbg::call-frame-p callee)
+ (dbg::call-frame-function-name callee))))
+ (if dspec
+ (frame-location dspec cname))))))
+
+(defimplementation eval-in-frame (form frame-number)
+ (let ((frame (nth-frame frame-number)))
+ (dbg::dbg-eval form frame)))
+
+(defimplementation return-from-frame (frame-number form)
+ (let* ((frame (nth-frame frame-number))
+ (return-frame (dbg::find-frame-for-return frame)))
+ (dbg::dbg-return-from-call-frame frame form return-frame
+ dbg::*debugger-stack*)))
+
+(defimplementation restart-frame (frame-number)
+ (let ((frame (nth-frame frame-number)))
+ (dbg::restart-frame frame :same-args t)))
+
+;;; Definition finding
+
+(defun frame-location (dspec callee-name)
+ (let ((infos (dspec:find-dspec-locations dspec)))
+ (cond (infos
+ (destructuring-bind ((rdspec location) &rest _) infos
+ (declare (ignore _))
+ (let ((name (and callee-name (symbolp callee-name)
+ (string callee-name))))
+ (make-dspec-location rdspec location
+ `(:call-site ,name)))))
+ (t
+ (list :error (format nil "Source location not available for: ~S"
+ dspec))))))
+
+(defimplementation find-definitions (name)
+ (let ((locations (dspec:find-name-locations dspec:*dspec-classes* name)))
+ (loop for (dspec location) in locations
+ collect (list dspec (make-dspec-location dspec location)))))
+
+
+;;; Compilation
+
+(defmacro with-swank-compilation-unit ((location &rest options) &body body)
+ (lw:rebinding (location)
+ `(let ((compiler::*error-database* '()))
+ (with-compilation-unit ,options
+ , at body
+ (signal-error-data-base compiler::*error-database* ,location)
+ (signal-undefined-functions compiler::*unknown-functions* ,location)))))
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (with-swank-compilation-unit (filename)
+ (compile-file filename :load load-p :external-format external-format)))
+
+(defvar *within-call-with-compilation-hooks* nil
+ "Whether COMPILE-FILE was called from within CALL-WITH-COMPILATION-HOOKS.")
+
+(defvar *undefined-functions-hash* nil
+ "Hash table to map info about undefined functions to pathnames.")
+
+(lw:defadvice (compile-file compile-file-and-collect-notes :around)
+ (pathname &rest rest)
+ (multiple-value-prog1 (apply #'lw:call-next-advice pathname rest)
+ (when *within-call-with-compilation-hooks*
+ (maphash (lambda (unfun dspecs)
+ (dolist (dspec dspecs)
+ (let ((unfun-info (list unfun dspec)))
+ (unless (gethash unfun-info *undefined-functions-hash*)
+ (setf (gethash unfun-info *undefined-functions-hash*)
+ pathname)))))
+ compiler::*unknown-functions*))))
+
+(defimplementation call-with-compilation-hooks (function)
+ (let ((compiler::*error-database* '())
+ (*undefined-functions-hash* (make-hash-table :test 'equal))
+ (*within-call-with-compilation-hooks* t))
+ (with-compilation-unit ()
+ (prog1 (funcall function)
+ (signal-error-data-base compiler::*error-database*)
+ (signal-undefined-functions compiler::*unknown-functions*)))))
+
+(defun map-error-database (database fn)
+ (loop for (filename . defs) in database do
+ (loop for (dspec . conditions) in defs do
+ (dolist (c conditions)
+ (funcall fn filename dspec c)))))
+
+(defun lispworks-severity (condition)
+ (cond ((not condition) :warning)
+ (t (etypecase condition
+ (error :error)
+ (style-warning :warning)
+ (warning :warning)))))
+
+(defun signal-compiler-condition (message location condition)
+ (check-type message string)
+ (signal
+ (make-instance 'compiler-condition :message message
+ :severity (lispworks-severity condition)
+ :location location
+ :original-condition condition)))
+
+(defun compile-from-temp-file (string filename)
+ (unwind-protect
+ (progn
+ (with-open-file (s filename :direction :output :if-exists :supersede)
+ (write-string string s)
+ (finish-output s))
+ (let ((binary-filename (compile-file filename :load t)))
+ (when binary-filename
+ (delete-file binary-filename))))
+ (delete-file filename)))
+
+(defun dspec-buffer-position (dspec offset)
+ (etypecase dspec
+ (cons (let ((name (dspec:dspec-primary-name dspec)))
+ (typecase name
+ ((or symbol string)
+ (list :function-name (string name)))
+ (t (list :position offset)))))
+ (null (list :position offset))
+ (symbol (list :function-name (string dspec)))))
+
+(defmacro with-fairly-standard-io-syntax (&body body)
+ "Like WITH-STANDARD-IO-SYNTAX but preserve *PACKAGE* and *READTABLE*."
+ (let ((package (gensym))
+ (readtable (gensym)))
+ `(let ((,package *package*)
+ (,readtable *readtable*))
+ (with-standard-io-syntax
+ (let ((*package* ,package)
+ (*readtable* ,readtable))
+ , at body)))))
+
+#-(or lispworks4.1 lispworks4.2) ; no dspec:parse-form-dspec prior to 4.3
+(defun dspec-stream-position (stream dspec)
+ (with-fairly-standard-io-syntax
+ (loop (let* ((pos (file-position stream))
+ (form (read stream nil '#1=#:eof)))
+ (when (eq form '#1#)
+ (return nil))
+ (labels ((check-dspec (form)
+ (when (consp form)
+ (let ((operator (car form)))
+ (case operator
+ ((progn)
+ (mapcar #'check-dspec
+ (cdr form)))
+ ((eval-when locally macrolet symbol-macrolet)
+ (mapcar #'check-dspec
+ (cddr form)))
+ ((in-package)
+ (let ((package (find-package (second form))))
+ (when package
+ (setq *package* package))))
+ (otherwise
+ (let ((form-dspec (dspec:parse-form-dspec form)))
+ (when (dspec:dspec-equal dspec form-dspec)
+ (return pos)))))))))
+ (check-dspec form))))))
+
+(defun dspec-file-position (file dspec)
+ (let* ((*compile-file-pathname* (pathname file))
+ (*compile-file-truename* (truename *compile-file-pathname*))
+ (*load-pathname* *compile-file-pathname*)
+ (*load-truename* *compile-file-truename*))
+ (with-open-file (stream file)
+ (let ((pos
+ #-(or lispworks4.1 lispworks4.2)
+ (dspec-stream-position stream dspec)))
+ (if pos
+ (list :position (1+ pos) t)
+ (dspec-buffer-position dspec 1))))))
+
+(defun emacs-buffer-location-p (location)
+ (and (consp location)
+ (eq (car location) :emacs-buffer)))
+
+(defun make-dspec-location (dspec location &optional hints)
+ (etypecase location
+ ((or pathname string)
+ (multiple-value-bind (file err)
+ (ignore-errors (namestring (truename location)))
+ (if err
+ (list :error (princ-to-string err))
+ (make-location `(:file ,file)
+ (dspec-file-position file dspec)
+ hints))))
+ (symbol
+ `(:error ,(format nil "Cannot resolve location: ~S" location)))
+ ((satisfies emacs-buffer-location-p)
+ (destructuring-bind (_ buffer offset string) location
+ (declare (ignore _ string))
+ (make-location `(:buffer ,buffer)
+ (dspec-buffer-position dspec offset)
+ hints)))))
+
+(defun make-dspec-progenitor-location (dspec location)
+ (let ((canon-dspec (dspec:canonicalize-dspec dspec)))
+ (make-dspec-location
+ (if canon-dspec
+ (if (dspec:local-dspec-p canon-dspec)
+ (dspec:dspec-progenitor canon-dspec)
+ canon-dspec)
+ nil)
+ location)))
+
+(defun signal-error-data-base (database &optional location)
+ (map-error-database
+ database
+ (lambda (filename dspec condition)
+ (signal-compiler-condition
+ (format nil "~A" condition)
+ (make-dspec-progenitor-location dspec (or location filename))
+ condition))))
+
+(defun unmangle-unfun (symbol)
+ "Converts symbols like 'SETF::|\"CL-USER\" \"GET\"| to
+function names like \(SETF GET)."
+ (cond ((sys::setf-symbol-p symbol)
+ (sys::setf-pair-from-underlying-name symbol))
+ (t symbol)))
+
+(defun signal-undefined-functions (htab &optional filename)
+ (maphash (lambda (unfun dspecs)
+ (dolist (dspec dspecs)
+ (signal-compiler-condition
+ (format nil "Undefined function ~A" (unmangle-unfun unfun))
+ (make-dspec-progenitor-location dspec
+ (or filename
+ (gethash (list unfun dspec)
+ *undefined-functions-hash*)))
+ nil)))
+ htab))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (assert buffer)
+ (assert position)
+ (let* ((location (list :emacs-buffer buffer position string))
+ (tmpname (hcl:make-temp-file nil "lisp")))
+ (with-swank-compilation-unit (location)
+ (compile-from-temp-file
+ (with-output-to-string (s)
+ (let ((*print-radix* t))
+ (print `(eval-when (:compile-toplevel)
+ (setq dspec::*location* (list , at location)))
+ s))
+ (write-string string s))
+ tmpname))))
+
+;;; xref
+
+(defmacro defxref (name function)
+ `(defimplementation ,name (name)
+ (xref-results (,function name))))
+
+(defxref who-calls hcl:who-calls)
+(defxref who-macroexpands hcl:who-calls) ; macros are in the calls table too
+(defxref calls-who hcl:calls-who)
+(defxref list-callers list-callers-internal)
+;; (defxref list-callees list-callees-internal)
+
+(defun list-callers-internal (name)
+ (let ((callers (make-array 100
+ :fill-pointer 0
+ :adjustable t)))
+ (hcl:sweep-all-objects
+ #'(lambda (object)
+ (when (and #+Harlequin-PC-Lisp (low:compiled-code-p object)
+ #-Harlequin-PC-Lisp (sys::callablep object)
+ (system::find-constant$funcallable name object))
+ (vector-push-extend object callers))))
+ ;; Delay dspec:object-dspec until after sweep-all-objects
+ ;; to reduce allocation problems.
+ (loop for object across callers
+ collect (if (symbolp object)
+ (list 'function object)
+ (or (dspec:object-dspec object) object)))))
+
+;; only for lispworks 4.2 and above
+#-lispworks4.1
+(progn
+ (defxref who-references hcl:who-references)
+ (defxref who-binds hcl:who-binds)
+ (defxref who-sets hcl:who-sets))
+
+(defimplementation who-specializes (classname)
+ (let ((methods (clos:class-direct-methods (find-class classname))))
+ (xref-results (mapcar #'dspec:object-dspec methods))))
+
+(defun xref-results (dspecs)
+ (flet ((frob-locs (dspec locs)
+ (cond (locs
+ (loop for (name loc) in locs
+ collect (list name (make-dspec-location name loc))))
+ (t `((,dspec (:error "Source location not available")))))))
+ (loop for dspec in dspecs
+ append (frob-locs dspec (dspec:dspec-definition-locations dspec)))))
+
+;;; Inspector
+(defclass lispworks-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'lispworks-inspector))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (lispworks-inspect o))
+
+(defmethod inspect-for-emacs ((o function)
+ (inspector backend-inspector))
+ (declare (ignore inspector))
+ (lispworks-inspect o))
+
+;; FIXME: slot-boundp-using-class in LW works with names so we can't
+;; use our method in swank.lisp.
+(defmethod inspect-for-emacs ((o standard-object)
+ (inspector backend-inspector))
+ (declare (ignore inspector))
+ (lispworks-inspect o))
+
+(defun lispworks-inspect (o)
+ (multiple-value-bind (names values _getter _setter type)
+ (lw:get-inspector-values o nil)
+ (declare (ignore _getter _setter))
+ (values "A value."
+ (append
+ (label-value-line "Type" type)
+ (loop for name in names
+ for value in values
+ append (label-value-line name value))))))
+
+;;; Miscellaneous
+
+(defimplementation quit-lisp ()
+ (lispworks:quit))
+
+;;; Tracing
+
+(defun parse-fspec (fspec)
+ "Return a dspec for FSPEC."
+ (ecase (car fspec)
+ ((:defmethod) `(method ,(cdr fspec)))))
+
+(defun tracedp (dspec)
+ (member dspec (eval '(trace)) :test #'equal))
+
+(defun toggle-trace-aux (dspec)
+ (cond ((tracedp dspec)
+ (eval `(untrace ,dspec))
+ (format nil "~S is now untraced." dspec))
+ (t
+ (eval `(trace (,dspec)))
+ (format nil "~S is now traced." dspec))))
+
+(defimplementation toggle-trace (fspec)
+ (toggle-trace-aux (parse-fspec fspec)))
+
+;;; Multithreading
+
+(defimplementation initialize-multiprocessing (continuation)
+ (cond ((not mp::*multiprocessing*)
+ (push (list "Initialize SLIME" '() continuation)
+ mp:*initial-processes*)
+ (mp:initialize-multiprocessing))
+ (t (funcall continuation))))
+
+(defimplementation spawn (fn &key name)
+ (let ((mp:*process-initial-bindings*
+ (remove (find-package :cl)
+ mp:*process-initial-bindings*
+ :key (lambda (x) (symbol-package (car x))))))
+ (mp:process-run-function name () fn)))
+
+(defvar *id-lock* (mp:make-lock))
+(defvar *thread-id-counter* 0)
+
+(defimplementation thread-id (thread)
+ (mp:with-lock (*id-lock*)
+ (or (getf (mp:process-plist thread) 'id)
+ (setf (getf (mp:process-plist thread) 'id)
+ (incf *thread-id-counter*)))))
+
+(defimplementation find-thread (id)
+ (find id (mp:list-all-processes)
+ :key (lambda (p) (getf (mp:process-plist p) 'id))))
+
+(defimplementation thread-name (thread)
+ (mp:process-name thread))
+
+(defimplementation thread-status (thread)
+ (format nil "~A ~D"
+ (mp:process-whostate thread)
+ (mp:process-priority thread)))
+
+(defimplementation make-lock (&key name)
+ (mp:make-lock :name name))
+
+(defimplementation call-with-lock-held (lock function)
+ (mp:with-lock (lock) (funcall function)))
+
+(defimplementation current-thread ()
+ mp:*current-process*)
+
+(defimplementation all-threads ()
+ (mp:list-all-processes))
+
+(defimplementation interrupt-thread (thread fn)
+ (mp:process-interrupt thread fn))
+
+(defimplementation kill-thread (thread)
+ (mp:process-kill thread))
+
+(defimplementation thread-alive-p (thread)
+ (mp:process-alive-p thread))
+
+(defvar *mailbox-lock* (mp:make-lock))
+
+(defun mailbox (thread)
+ (mp:with-lock (*mailbox-lock*)
+ (or (getf (mp:process-plist thread) 'mailbox)
+ (setf (getf (mp:process-plist thread) 'mailbox)
+ (mp:make-mailbox)))))
+
+(defimplementation receive ()
+ (mp:mailbox-read (mailbox mp:*current-process*)))
+
+(defimplementation send (thread object)
+ (mp:mailbox-send (mailbox thread) object))
+
+;;; Some intergration with the lispworks environment
+
+(defun swank-sym (name) (find-symbol (string name) :swank))
+
+(defimplementation emacs-connected ()
+ (when (eq (eval (swank-sym :*communication-style*))
+ nil)
+ (set-sigint-handler))
+ ;; pop up the slime debugger by default
+ (let ((lw:*handle-warn-on-redefinition* :warn))
+ (defmethod env-internals:environment-display-notifier
+ (env &key restarts condition)
+ (declare (ignore restarts))
+ (funcall (swank-sym :swank-debugger-hook) condition *debugger-hook*))
+ (defmethod env-internals:environment-display-debugger (env)
+ *debug-io*)))
+
+(defimplementation make-stream-interactive (stream)
+ (unless (find-method #'stream:stream-soft-force-output nil `((eql ,stream))
+ nil)
+ (let ((lw:*handle-warn-on-redefinition* :warn))
+ (defmethod stream:stream-soft-force-output ((o (eql stream)))
+ (force-output o)))))
+
+(defmethod env-internals:confirm-p ((e slime-env) &optional msg &rest args)
+ (apply (swank-sym :y-or-n-p-in-emacs) msg args))
+
+
+;;;; Weak hashtables
+
+(defimplementation make-weak-key-hash-table (&rest args)
+ (apply #'make-hash-table :weak-kind :key args))
+
+(defimplementation make-weak-value-hash-table (&rest args)
+ (apply #'make-hash-table :weak-kind :value args))
Added: branches/bos/thirdparty/emacs/slime/swank-loader.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-loader.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,237 @@
+;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
+;;;
+;;; swank-loader.lisp --- Compile and load the Slime backend.
+;;;
+;;; Created 2003, James Bielman <jamesjb at jamesjb.com>
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+;; If you want customize the source- or fasl-directory you can set
+;; swank-loader:*source-directory* resp. swank-loader:*fasl-directory*
+;; before loading this files. (you also need to create the
+;; swank-loader package.)
+;; E.g.:
+;;
+;; (make-package :swank-loader)
+;; (defparameter swank-loader::*fasl-directory* "/tmp/fasl/")
+;; (load ".../swank-loader.lisp")
+
+(cl:defpackage :swank-loader
+ (:use :cl)
+ (:export :load-swank
+ :*source-directory*
+ :*fasl-directory*))
+
+(cl:in-package :swank-loader)
+
+(defvar *source-directory*
+ (make-pathname :name nil :type nil
+ :defaults (or *load-pathname* *default-pathname-defaults*))
+ "The directory where to look for the source.")
+
+(defparameter *sysdep-files*
+ (append
+ '()
+ #+cmu '("swank-source-path-parser" "swank-source-file-cache" "swank-cmucl")
+ #+scl '("swank-source-path-parser" "swank-source-file-cache" "swank-scl")
+ #+sbcl '("swank-source-path-parser" "swank-source-file-cache"
+ "swank-sbcl" "swank-gray")
+ #+openmcl '("metering" "swank-openmcl" "swank-gray")
+ #+lispworks '("swank-lispworks" "swank-gray")
+ #+allegro '("swank-allegro" "swank-gray")
+ #+clisp '("xref" "metering" "swank-clisp" "swank-gray")
+ #+armedbear '("swank-abcl")
+ #+cormanlisp '("swank-corman" "swank-gray")
+ #+ecl '("swank-ecl" "swank-gray")
+ ))
+
+(defparameter *implementation-features*
+ '(:allegro :lispworks :sbcl :openmcl :cmu :clisp :ccl :corman :cormanlisp
+ :armedbear :gcl :ecl :scl))
+
+(defparameter *os-features*
+ '(:macosx :linux :windows :mswindows :win32 :solaris :darwin :sunos :hpux
+ :unix))
+
+(defparameter *architecture-features*
+ '(:powerpc :ppc :x86 :x86-64 :amd64 :i686 :i586 :i486 :pc386 :iapx386
+ :sparc64 :sparc :hppa64 :hppa))
+
+(defun lisp-version-string ()
+ #+cmu (substitute-if #\_ (lambda (x) (find x " /"))
+ (lisp-implementation-version))
+ #+scl (lisp-implementation-version)
+ #+sbcl (lisp-implementation-version)
+ #+ecl (lisp-implementation-version)
+ #+openmcl (format nil "~d.~d"
+ ccl::*openmcl-major-version*
+ ccl::*openmcl-minor-version*)
+ #+lispworks (lisp-implementation-version)
+ #+allegro (format nil
+ "~A~A~A"
+ excl::*common-lisp-version-number*
+ (if (eq 'h 'H) "A" "M") ; ANSI vs MoDeRn
+ (if (member :64bit *features*) "-64bit" ""))
+ #+clisp (let ((s (lisp-implementation-version)))
+ (subseq s 0 (position #\space s)))
+ #+armedbear (lisp-implementation-version)
+ #+cormanlisp (lisp-implementation-version))
+
+(defun unique-directory-name ()
+ "Return a name that can be used as a directory name that is
+unique to a Lisp implementation, Lisp implementation version,
+operating system, and hardware architecture."
+ (flet ((first-of (features)
+ (loop for f in features
+ when (find f *features*) return it))
+ (maybe-warn (value fstring &rest args)
+ (cond (value)
+ (t (apply #'warn fstring args)
+ "unknown"))))
+ (let ((lisp (maybe-warn (first-of *implementation-features*)
+ "No implementation feature found in ~a."
+ *implementation-features*))
+ (os (maybe-warn (first-of *os-features*)
+ "No os feature found in ~a." *os-features*))
+ (arch (maybe-warn (first-of *architecture-features*)
+ "No architecture feature found in ~a."
+ *architecture-features*))
+ (version (maybe-warn (lisp-version-string)
+ "Don't know how to get Lisp ~
+ implementation version.")))
+ (format nil "~(~@{~a~^-~}~)" lisp version os arch))))
+
+(defun file-newer-p (new-file old-file)
+ "Returns true if NEW-FILE is newer than OLD-FILE."
+ (> (file-write-date new-file) (file-write-date old-file)))
+
+(defun slime-version-string ()
+ "Return a string identifying the SLIME version.
+Return nil if nothing appropriate is available."
+ (with-open-file (s (merge-pathnames "ChangeLog" *source-directory*)
+ :if-does-not-exist nil)
+ (and s (symbol-name (read s)))))
+
+(defun default-fasl-directory ()
+ (merge-pathnames
+ (make-pathname
+ :directory `(:relative ".slime" "fasl"
+ ,@(if (slime-version-string) (list (slime-version-string)))
+ ,(unique-directory-name)))
+ (user-homedir-pathname)))
+
+(defun binary-pathname (source-pathname binary-directory)
+ "Return the pathname where SOURCE-PATHNAME's binary should be compiled."
+ (let ((cfp (compile-file-pathname source-pathname)))
+ (merge-pathnames (make-pathname :name (pathname-name cfp)
+ :type (pathname-type cfp))
+ binary-directory)))
+
+(defun handle-loadtime-error (condition binary-pathname)
+ (pprint-logical-block (*error-output* () :per-line-prefix ";; ")
+ (format *error-output*
+ "~%Error while loading: ~A~%Condition: ~A~%Aborting.~%"
+ binary-pathname condition))
+ (when (equal (directory-namestring binary-pathname)
+ (directory-namestring (default-fasl-directory)))
+ (ignore-errors (delete-file binary-pathname)))
+ (abort))
+
+(defun compile-files-if-needed-serially (files fasl-directory load)
+ "Compile each file in FILES if the source is newer than
+its corresponding binary, or the file preceding it was
+recompiled."
+ (let ((needs-recompile nil))
+ (dolist (source-pathname files)
+ (let ((binary-pathname (binary-pathname source-pathname
+ fasl-directory)))
+ (handler-case
+ (progn
+ (when (or needs-recompile
+ (not (probe-file binary-pathname))
+ (file-newer-p source-pathname binary-pathname))
+ ;; need a to recompile source-pathname, so we'll
+ ;; need to recompile everything after this too.
+ (setq needs-recompile t)
+ (ensure-directories-exist binary-pathname)
+ (compile-file source-pathname :output-file binary-pathname
+ :print nil
+ :verbose t))
+ (when load
+ (load binary-pathname :verbose t)))
+ ;; Fail as early as possible
+ (serious-condition (c)
+ (handle-loadtime-error c binary-pathname)))))))
+
+#+(or cormanlisp ecl)
+(defun compile-files-if-needed-serially (files fasl-directory load)
+ "Corman Lisp and ECL have trouble with compiled files."
+ (declare (ignore fasl-directory))
+ (when load
+ (dolist (file files)
+ (load file :verbose t)
+ (force-output))))
+
+(defun load-user-init-file ()
+ "Load the user init file, return NIL if it does not exist."
+ (load (merge-pathnames (user-homedir-pathname)
+ (make-pathname :name ".swank" :type "lisp"))
+ :if-does-not-exist nil))
+
+(defun load-site-init-file (directory)
+ (load (make-pathname :name "site-init" :type "lisp"
+ :defaults directory)
+ :if-does-not-exist nil))
+
+(defun source-files (names src-dir)
+ (mapcar (lambda (name)
+ (make-pathname :name (string-downcase name) :type "lisp"
+ :defaults src-dir))
+ names))
+
+(defun swank-source-files (src-dir)
+ (source-files `("swank-backend" ,@*sysdep-files* "swank")
+ src-dir))
+
+(defvar *fasl-directory* (default-fasl-directory)
+ "The directory where fasl files should be placed.")
+
+(defvar *contribs* '(swank-c-p-c swank-arglists swank-fuzzy
+ swank-fancy-inspector
+ swank-presentations swank-presentation-streams
+ #+(or asdf sbcl) swank-asdf
+ )
+ "List of names for contrib modules.")
+
+(defun append-dir (absolute name)
+ (merge-pathnames
+ (make-pathname :directory `(:relative ,name) :defaults absolute)
+ absolute))
+
+(defun contrib-src-dir (src-dir)
+ (append-dir src-dir "contrib"))
+
+(defun contrib-source-files (src-dir)
+ (source-files *contribs* (contrib-src-dir src-dir)))
+
+(defun load-swank (&key
+ (source-directory *source-directory*)
+ (fasl-directory *fasl-directory*)
+ (contrib-fasl-directory
+ (append-dir fasl-directory "contrib")))
+ (compile-files-if-needed-serially (swank-source-files source-directory)
+ fasl-directory t)
+ (compile-files-if-needed-serially (contrib-source-files source-directory)
+ contrib-fasl-directory nil))
+
+(load-swank)
+
+(setq swank::*swank-wire-protocol-version* (slime-version-string))
+(setq swank::*load-path*
+ (append swank::*load-path* (list (contrib-src-dir *source-directory*))))
+(swank-backend::warn-unimplemented-interfaces)
+(load-site-init-file *source-directory*)
+(load-user-init-file)
+(swank:run-after-init-hook)
Added: branches/bos/thirdparty/emacs/slime/swank-openmcl.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-openmcl.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,985 @@
+;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
+;;;
+;;; openmcl-swank.lisp --- SLIME backend for OpenMCL.
+;;;
+;;; Copyright (C) 2003, James Bielman <jamesjb at jamesjb.com>
+;;;
+;;; This program is licensed under the terms of the Lisp Lesser GNU
+;;; Public License, known as the LLGPL, and distributed with OpenMCL
+;;; as the file "LICENSE". The LLGPL consists of a preamble and the
+;;; LGPL, which is distributed with OpenMCL as the file "LGPL". Where
+;;; these conflict, the preamble takes precedence.
+;;;
+;;; The LLGPL is also available online at
+;;; http://opensource.franz.com/preamble.html
+
+;;;
+;;; This is the beginning of a Slime backend for OpenMCL. It has been
+;;; tested only with OpenMCL version 0.14-030901 on Darwin --- I would
+;;; be interested in hearing the results with other versions.
+;;;
+;;; Additionally, reporting the positions of warnings accurately requires
+;;; a small patch to the OpenMCL file compiler, which may be found at:
+;;;
+;;; http://www.jamesjb.com/slime/openmcl-warning-position.diff
+;;;
+;;; Things that work:
+;;;
+;;; * Evaluation of forms with C-M-x.
+;;; * Compilation of defuns with C-c C-c.
+;;; * File compilation with C-c C-k.
+;;; * Most of the debugger functionality, except EVAL-IN-FRAME,
+;;; FRAME-SOURCE-LOCATION, and FRAME-CATCH-TAGS.
+;;; * Macroexpanding with C-c RET.
+;;; * Disassembling the symbol at point with C-c M-d.
+;;; * Describing symbol at point with C-c C-d.
+;;; * Compiler warnings are trapped and sent to Emacs using the buffer
+;;; position of the offending top level form.
+;;; * Symbol completion and apropos.
+;;;
+;;; Things that sort of work:
+;;;
+;;; * WHO-CALLS is implemented but is only able to return the file a
+;;; caller is defined in---source location information is not
+;;; available.
+;;;
+;;; Things that aren't done yet:
+;;;
+;;; * Cross-referencing.
+;;; * Due to unimplementation functionality the test suite does not
+;;; run correctly (it hangs upon entering the debugger).
+;;;
+
+(in-package :swank-backend)
+
+(import-from :ccl *gray-stream-symbols* :swank-backend)
+
+(require 'xref)
+
+;;; swank-mop
+
+(import-to-swank-mop
+ '( ;; classes
+ cl:standard-generic-function
+ ccl::standard-slot-definition
+ cl:method
+ cl:standard-class
+ ccl::eql-specializer
+ openmcl-mop:finalize-inheritance
+ ;; standard-class readers
+ openmcl-mop:class-default-initargs
+ openmcl-mop:class-direct-default-initargs
+ openmcl-mop:class-direct-slots
+ openmcl-mop:class-direct-subclasses
+ openmcl-mop:class-direct-superclasses
+ openmcl-mop:class-finalized-p
+ cl:class-name
+ openmcl-mop:class-precedence-list
+ openmcl-mop:class-prototype
+ openmcl-mop:class-slots
+ openmcl-mop:specializer-direct-methods
+ ;; eql-specializer accessors
+ openmcl-mop:eql-specializer-object
+ ;; generic function readers
+ openmcl-mop:generic-function-argument-precedence-order
+ openmcl-mop:generic-function-declarations
+ openmcl-mop:generic-function-lambda-list
+ openmcl-mop:generic-function-methods
+ openmcl-mop:generic-function-method-class
+ openmcl-mop:generic-function-method-combination
+ openmcl-mop:generic-function-name
+ ;; method readers
+ openmcl-mop:method-generic-function
+ openmcl-mop:method-function
+ openmcl-mop:method-lambda-list
+ openmcl-mop:method-specializers
+ openmcl-mop:method-qualifiers
+ ;; slot readers
+ openmcl-mop:slot-definition-allocation
+ ccl::slot-definition-documentation
+ openmcl-mop:slot-value-using-class
+ openmcl-mop:slot-definition-initargs
+ openmcl-mop:slot-definition-initform
+ openmcl-mop:slot-definition-initfunction
+ openmcl-mop:slot-definition-name
+ openmcl-mop:slot-definition-type
+ openmcl-mop:slot-definition-readers
+ openmcl-mop:slot-definition-writers
+ openmcl-mop:slot-boundp-using-class
+ openmcl-mop:slot-makunbound-using-class))
+
+(defun specializer-name (spec)
+ (etypecase spec
+ (cons spec)
+ (class (class-name spec))
+ (ccl::eql-specializer `(eql ,(ccl::eql-specializer-object spec)))))
+
+(defun swank-mop:compute-applicable-methods-using-classes (gf args)
+ (let* ((methods (ccl::%gf-methods gf))
+ (args-length (length args))
+ (bits (ccl::inner-lfun-bits gf))
+ arg-count res)
+ (when methods
+ (setq arg-count (length (ccl::%method-specializers (car methods))))
+ (unless (<= arg-count args-length)
+ (error "Too few args to ~s" gf))
+ (unless (or (logbitp ccl::$lfbits-rest-bit bits)
+ (logbitp ccl::$lfbits-restv-bit bits)
+ (logbitp ccl::$lfbits-keys-bit bits)
+ (<= args-length
+ (+ (ldb ccl::$lfbits-numreq bits) (ldb ccl::$lfbits-numopt bits))))
+ (error "Too many args to ~s" gf))
+ (let ((cpls (make-list arg-count)))
+ (declare (dynamic-extent cpls))
+ (do* ((args-tail args (cdr args-tail))
+ (cpls-tail cpls (cdr cpls-tail)))
+ ((null cpls-tail))
+ (setf (car cpls-tail)
+ (ccl::%class-precedence-list (car args-tail))))
+ (flet ((%method-applicable-p (method args cpls)
+ (do* ((specs (ccl::%method-specializers method) (ccl::%cdr specs))
+ (args args (ccl::%cdr args))
+ (cpls cpls (ccl::%cdr cpls)))
+ ((null specs) t)
+ (let ((spec (ccl::%car specs)))
+ (if (typep spec 'ccl::eql-specializer)
+ (unless (subtypep (ccl::%car args) (class-of (ccl::eql-specializer-object spec)))
+ (return nil))
+ (unless (ccl:memq spec (ccl::%car cpls))
+ (return nil)))))))
+ (dolist (m methods)
+ (if (%method-applicable-p m args cpls)
+ (push m res))))
+ (ccl::sort-methods res cpls (ccl::%gf-precedence-list gf))))))
+
+;;; TCP Server
+
+(defimplementation preferred-communication-style ()
+ :spawn)
+
+(defimplementation create-socket (host port)
+ (ccl:make-socket :connect :passive :local-port port
+ :local-host host :reuse-address t))
+
+(defimplementation local-port (socket)
+ (ccl:local-port socket))
+
+(defimplementation close-socket (socket)
+ (close socket))
+
+(defimplementation accept-connection (socket &key external-format
+ buffering timeout)
+ (declare (ignore buffering timeout
+ #-openmcl-unicode-strings external-format))
+ #+openmcl-unicode-strings
+ (when external-format
+ (let ((keys (ccl::socket-keys socket)))
+ (setf (getf keys :external-format) external-format
+ (slot-value socket 'ccl::keys) keys)))
+ (ccl:accept-connection socket :wait t))
+
+#+openmcl-unicode-strings
+(defvar *external-format-to-coding-system*
+ '((:iso-8859-1
+ "latin-1" "latin-1-unix" "iso-latin-1-unix"
+ "iso-8859-1" "iso-8859-1-unix")
+ (:utf-8 "utf-8" "utf-8-unix")))
+
+#+openmcl-unicode-strings
+(defimplementation find-external-format (coding-system)
+ (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
+ *external-format-to-coding-system*)))
+
+(defimplementation emacs-connected ()
+ (setq ccl::*interactive-abort-process* ccl::*current-process*))
+
+(defimplementation make-stream-interactive (stream)
+ (typecase stream
+ (ccl:fundamental-output-stream
+ (push stream ccl::*auto-flush-streams*))))
+
+;;; Unix signals
+
+(defimplementation call-without-interrupts (fn)
+ (ccl:without-interrupts (funcall fn)))
+
+(defimplementation getpid ()
+ (ccl::getpid))
+
+(defimplementation lisp-implementation-type-name ()
+ "openmcl")
+
+(defvar *break-in-sldb* t)
+
+(let ((ccl::*warn-if-redefine-kernel* nil))
+ (ccl::advise
+ cl::break
+ (if (and *break-in-sldb*
+ (find ccl::*current-process* (symbol-value (intern "*CONNECTIONS*" 'swank))
+ :key (intern "CONNECTION.REPL-THREAD" 'swank)))
+ (apply 'break-in-sldb ccl::arglist)
+ (:do-it)) :when :around :name sldb-break))
+
+(defun break-in-sldb (&optional string &rest args)
+ (let ((c (make-condition 'simple-condition
+ :format-control (or string "Break")
+ :format-arguments args)))
+ (let ((previous-f nil)
+ (previous-f2 nil))
+ (block find-frame
+ (map-backtrace
+ #'(lambda(frame-number p context lfun pc)
+ (declare (ignore frame-number context pc))
+ (when (eq previous-f2 'break-in-sldb)
+ (record-stack-top p)
+ (return-from find-frame))
+ (setq previous-f2 previous-f)
+ (setq previous-f (ccl::lfun-name lfun)))))
+ (restart-case (invoke-debugger c)
+ (continue () :report (lambda (stream) (write-string "Resume interrupted evaluation" stream)) t))
+ )))
+
+; In previous version the code that recorded the function that had an
+; error or which was interrupted was not thread safe. This code repairs that by
+; associating the frame pointer with a process via the *process-to-stack-top* hash.
+
+(defvar *process-to-stack-top* (make-hash-table :test 'eql))
+
+(defun record-stack-top (frame)
+ (setf (gethash (ccl::process-serial-number ccl::*current-process*) *process-to-stack-top* )
+ frame))
+
+(defun grab-stack-top ()
+ (let ((psn (ccl::process-serial-number ccl::*current-process*)))
+ (ccl::without-interrupts
+ (prog1
+ (gethash psn *process-to-stack-top*)
+ (setf (gethash psn *process-to-stack-top*) nil)))))
+
+(defmethod ccl::application-error :before (application condition error-pointer)
+ (declare (ignore application condition))
+ (record-stack-top error-pointer)
+ nil)
+
+;;; Evaluation
+
+(defimplementation arglist (fname)
+ (arglist% fname))
+
+(defmethod arglist% ((f symbol))
+ (ccl:arglist f))
+
+(defmethod arglist% ((f function))
+ (ccl:arglist (ccl:function-name f)))
+
+(defimplementation function-name (function)
+ (ccl:function-name function))
+
+;;; Compilation
+
+(defvar *buffer-offset* nil)
+(defvar *buffer-name* nil)
+
+(defun condition-source-position (condition)
+ "Return the position in the source file of a compiler condition."
+ (+ 1
+ (or *buffer-offset* 0)
+ ;; alanr sometimes returned stream position nil.
+ (or (ccl::compiler-warning-stream-position condition) 0)))
+
+
+(defun handle-compiler-warning (condition)
+ "Construct a compiler note for Emacs from a compiler warning
+condition."
+ (signal (make-condition
+ 'compiler-condition
+ :original-condition condition
+ :message (format nil "~A" condition)
+ :severity :warning
+ :location
+ (let ((position (condition-source-position condition)))
+ (if *buffer-name*
+ (make-location
+ (list :buffer *buffer-name*)
+ (list :position position t))
+ (if (ccl::compiler-warning-file-name condition)
+ (make-location
+ (list :file (namestring (truename (ccl::compiler-warning-file-name condition))))
+ (list :position position t))))))))
+
+(defun temp-file-name ()
+ "Return a temporary file name to compile strings into."
+ (ccl:%get-cstring (#_tmpnam (ccl:%null-ptr))))
+
+(defimplementation call-with-compilation-hooks (function)
+ (handler-bind ((ccl::compiler-warning 'handle-compiler-warning))
+ (funcall function)))
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (declare (ignore external-format))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* nil)
+ (*buffer-offset* nil))
+ (compile-file filename :load load-p))))
+
+(defimplementation frame-var-value (frame var)
+ (block frame-var-value
+ (map-backtrace
+ #'(lambda(frame-number p context lfun pc)
+ (when (= frame frame-number)
+ (return-from frame-var-value
+ (multiple-value-bind (total vsp parent-vsp)
+ (ccl::count-values-in-frame p context)
+ (loop for count below total
+ with varcount = -1
+ for (value nil name) = (multiple-value-list (ccl::nth-value-in-frame p count context lfun pc vsp parent-vsp))
+ when name do (incf varcount)
+ until (= varcount var)
+ finally (return value))
+ )))))))
+
+(defun xref-locations (relation name &optional (inverse nil))
+ (flet ((function-source-location (entry)
+ (multiple-value-bind (info name)
+ (ccl::edit-definition-p
+ (ccl::%db-key-from-xref-entry entry)
+ (if (eql (ccl::xref-entry-type entry)
+ 'macro)
+ 'function
+ (ccl::xref-entry-type entry)))
+ (cond ((not info)
+ (list :error
+ (format nil "No source info available for ~A"
+ (ccl::xref-entry-name entry))))
+ ((typep (caar info) 'ccl::method)
+ `(:location
+ (:file ,(remove-filename-quoting
+ (namestring (translate-logical-pathname
+ (cdr (car info))))))
+ (:method
+ ,(princ-to-string (ccl::method-name (caar info)))
+ ,(mapcar 'princ-to-string
+ (mapcar #'specializer-name
+ (ccl::method-specializers
+ (caar info))))
+ ,@(mapcar 'princ-to-string
+ (ccl::method-qualifiers (caar info))))
+ nil))
+ (t
+ (canonicalize-location (cdr (first info)) name))))))
+ (declare (dynamic-extent #'function-source-location))
+ (loop for xref in (if inverse
+ (ccl::get-relation relation name
+ :wild :exhaustive t)
+ (ccl::get-relation relation
+ :wild name :exhaustive t))
+ for function = (ccl::xref-entry-name xref)
+ collect `((function ,function)
+ ,(function-source-location xref)))))
+
+(defimplementation who-binds (name)
+ (xref-locations :binds name))
+
+(defimplementation who-macroexpands (name)
+ (xref-locations :macro-calls name t))
+
+(defimplementation who-references (name)
+ (remove-duplicates
+ (append (xref-locations :references name)
+ (xref-locations :sets name)
+ (xref-locations :binds name))
+ :test 'equal))
+
+(defimplementation who-sets (name)
+ (xref-locations :sets name))
+
+(defimplementation who-calls (name)
+ (remove-duplicates
+ (append
+ (xref-locations :direct-calls name)
+ (xref-locations :indirect-calls name)
+ (xref-locations :macro-calls name t))
+ :test 'equal))
+
+(defimplementation list-callees (name)
+ (remove-duplicates
+ (append
+ (xref-locations :direct-calls name t)
+ (xref-locations :macro-calls name nil))
+ :test 'equal))
+
+(defimplementation who-specializes (class)
+ (if (symbolp class) (setq class (find-class class)))
+ (remove-duplicates
+ (append (mapcar (lambda(m)
+ (let ((location (function-source-location (ccl::method-function m))))
+ (if (eq (car location) :error)
+ (setq location nil ))
+ `((method ,(ccl::method-name m)
+ ,(mapcar #'specializer-name (ccl::method-specializers m))
+ ,@(ccl::method-qualifiers m))
+ ,location)))
+ (ccl::%class.direct-methods class))
+ (mapcan 'who-specializes (ccl::%class-direct-subclasses class)))
+ :test 'equal))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-offset* position)
+ (filename (temp-file-name)))
+ (unwind-protect
+ (with-open-file (s filename :direction :output :if-exists :error)
+ (write-string string s))
+ (let ((binary-filename (compile-file filename :load t)))
+ (delete-file binary-filename)))
+ (delete-file filename))))
+
+;;; Profiling (alanr: lifted from swank-clisp)
+
+(defimplementation profile (fname)
+ (eval `(mon:monitor ,fname))) ;monitor is a macro
+
+(defimplementation profiled-functions ()
+ mon:*monitored-functions*)
+
+(defimplementation unprofile (fname)
+ (eval `(mon:unmonitor ,fname))) ;unmonitor is a macro
+
+(defimplementation unprofile-all ()
+ (mon:unmonitor))
+
+(defimplementation profile-report ()
+ (mon:report-monitoring))
+
+(defimplementation profile-reset ()
+ (mon:reset-all-monitoring))
+
+(defimplementation profile-package (package callers-p methods)
+ (declare (ignore callers-p methods))
+ (mon:monitor-all package))
+
+;;; Debugging
+
+(defun openmcl-set-debug-switches ()
+ (setq ccl::*fasl-save-definitions* nil)
+ (setq ccl::*fasl-save-doc-strings* t)
+ (setq ccl::*fasl-save-local-symbols* t)
+ (setq ccl::*ppc2-compiler-register-save-label* t)
+ (setq ccl::*save-arglist-info* t)
+ (setq ccl::*save-definitions* nil)
+ (setq ccl::*save-doc-strings* t)
+ (setq ccl::*save-local-symbols* t)
+ (ccl::start-xref))
+
+(defvar *sldb-stack-top* nil)
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (let* ((*debugger-hook* nil)
+ (*sldb-stack-top* (grab-stack-top))
+ (ccl::*signal-printing-errors* nil)) ; don't let error while printing error take us down
+ (funcall debugger-loop-fn)))
+
+(defun backtrace-context ()
+ (if (and (= ccl::*openmcl-major-version* 0)
+ (<= ccl::*openmcl-minor-version* 14)
+ (< ccl::*openmcl-revision* 2))
+ (ccl::%current-tcr)
+ nil))
+
+(defun map-backtrace (function &optional
+ (start-frame-number 0)
+ (end-frame-number most-positive-fixnum))
+ "Call FUNCTION passing information about each stack frame
+ from frames START-FRAME-NUMBER to END-FRAME-NUMBER."
+ (let ((context (backtrace-context))
+ (frame-number 0)
+ (top-stack-frame (or *sldb-stack-top*
+ (ccl::%get-frame-ptr))))
+ (do* ((p top-stack-frame (ccl::parent-frame p context))
+ (q (ccl::last-frame-ptr context)))
+ ((or (null p) (eq p q) (ccl::%stack< q p context))
+ (values))
+ (multiple-value-bind (lfun pc) (ccl::cfp-lfun p)
+ (when lfun
+ (if (and (>= frame-number start-frame-number)
+ (< frame-number end-frame-number))
+ (funcall function frame-number p context lfun pc))
+ (incf frame-number))))))
+
+;; May 13, 2004 alanr: use prin1 instead of princ so I see " around strings. Write ' in front of symbol names and lists.
+;; Sept 6, 2004 alanr: use builtin ccl::frame-supplied-args
+
+(defun frame-arguments (p context lfun pc)
+ "Returns a string representing the arguments of a frame."
+ (multiple-value-bind (args types names count nclosed)
+ (ccl::frame-supplied-args p lfun pc nil context)
+ (declare (ignore count nclosed))
+ (let ((result nil))
+ (loop named loop
+ for var = (cond
+ ((null args)
+ (return-from loop))
+ ((atom args)
+ (prog1
+ args
+ (setf args nil)))
+ (t (pop args)))
+ for type in types
+ for name in names
+ do
+ (when (or (symbolp var) (listp var)) (setq var (list 'quote var)))
+ (cond ((equal type "keyword")
+ (push (format nil "~S ~A"
+ (intern (symbol-name name) "KEYWORD")
+ (prin1-to-string var))
+ result))
+ (t (push (prin1-to-string var) result))))
+ (format nil "~{ ~A~}" (nreverse result)))))
+
+
+;; XXX should return something less stringy
+;; alanr May 13, 2004: put #<> around anonymous functions in the backtrace.
+
+(defimplementation compute-backtrace (start-frame-number end-frame-number)
+ (let (result)
+ (map-backtrace (lambda (frame-number p context lfun pc)
+ (declare (ignore frame-number))
+ (push (with-output-to-string (s)
+ (format s "(~A~A)"
+ (if (ccl::function-name lfun)
+ (ccl::%lfun-name-string lfun)
+ lfun)
+ (frame-arguments p context lfun pc)))
+ result))
+ start-frame-number end-frame-number)
+ (nreverse result)))
+
+(defimplementation print-frame (frame stream)
+ (princ frame stream))
+
+(defimplementation frame-locals (index)
+ (block frame-locals
+ (map-backtrace
+ (lambda (frame-number p context lfun pc)
+ (when (= frame-number index)
+ (multiple-value-bind (count vsp parent-vsp)
+ (ccl::count-values-in-frame p context)
+ (let (result)
+ (dotimes (i count)
+ (multiple-value-bind (var type name)
+ (ccl::nth-value-in-frame p i context lfun pc vsp parent-vsp)
+ (declare (ignore type))
+ (when name
+ (push (list
+ :name name
+ :id 0
+ :value var)
+ result))))
+ (return-from frame-locals (nreverse result)))))))))
+
+(defimplementation frame-catch-tags (index &aux my-frame)
+ (block frame-catch-tags
+ (map-backtrace
+ (lambda (frame-number p context lfun pc)
+ (declare (ignore pc lfun))
+ (if (= frame-number index)
+ (setq my-frame p)
+ (when my-frame
+ (return-from frame-catch-tags
+ (loop for catch = (ccl::%catch-top (ccl::%current-tcr)) then (ccl::next-catch catch)
+ while catch
+ for csp = (ccl::uvref catch 3) ; ppc32::catch-frame.csp-cell) defined in arch.lisp
+ for tag = (ccl::uvref catch 0) ; ppc32::catch-frame.catch-tag-cell)
+ until (ccl::%stack< p csp context)
+ when (ccl::%stack< my-frame csp context)
+ collect (cond
+ ((symbolp tag)
+ tag)
+ ((and (listp tag)
+ (typep (car tag) 'restart))
+ `(:restart ,(restart-name (car tag)))))))))))))
+
+(defimplementation disassemble-frame (the-frame-number)
+ (let ((function-to-disassemble nil))
+ (block find-frame
+ (map-backtrace
+ (lambda(frame-number p context lfun pc)
+ (declare (ignore p context pc))
+ (when (= frame-number the-frame-number)
+ (setq function-to-disassemble lfun)
+ (return-from find-frame)))))
+ (ccl::print-ppc-instructions
+ *standard-output*
+ (ccl::function-to-dll-header function-to-disassemble) nil)))
+
+;;;
+
+(defun canonicalize-location (file symbol)
+ (etypecase file
+ ((or string pathname)
+ (multiple-value-bind (truename c) (ignore-errors (namestring (truename file)))
+ (cond (c (list :error (princ-to-string c)))
+ (t (make-location (list :file (remove-filename-quoting truename))
+ (list :function-name (princ-to-string symbol)))))))))
+
+(defun remove-filename-quoting (string)
+ (if (search "\\" string)
+ (read-from-string (format nil "\"~a\"" string))
+ string))
+
+(defun maybe-method-location (type)
+ (when (typep type 'ccl::method)
+ `((method ,(ccl::method-name type)
+ ,(mapcar #'specializer-name (ccl::method-specializers type))
+ ,@(ccl::method-qualifiers type))
+ ,(function-source-location (ccl::method-function type)))))
+
+(defimplementation find-definitions (symbol)
+ (let* ((info (ccl::get-source-files-with-types&classes symbol)))
+ (loop for (type . file) in info
+ when (not (equal "l1-boot-3" (pathname-name file))) ; alanr: This is a bug - there's nothing in there
+ collect (or (maybe-method-location type)
+ (list (list type symbol)
+ (canonicalize-location file symbol))))))
+
+
+(defun function-source-location (function)
+ (multiple-value-bind (info name) (ccl::edit-definition-p function)
+ (cond ((not info) (list :error (format nil "No source info available for ~A" function)))
+ ((typep (caar info) 'ccl::method)
+ `(:location
+ (:file ,(remove-filename-quoting (namestring (translate-logical-pathname (cdr (car info))) )))
+ (:method ,(princ-to-string (ccl::method-name (caar info)))
+ ,(mapcar 'princ-to-string
+ (mapcar #'specializer-name
+ (ccl::method-specializers (caar info))))
+ ,@(mapcar 'princ-to-string (ccl::method-qualifiers (caar info))))
+ nil))
+ (t (canonicalize-location (cdr (first info)) name)))))
+
+(defimplementation frame-source-location-for-emacs (index)
+ "Return to Emacs the location of the source code for the
+function in a debugger frame. In OpenMCL, we are not able to
+find the precise position of the frame, but we do attempt to give
+at least the filename containing it."
+ (block frame-source-location-for-emacs
+ (map-backtrace
+ (lambda (frame-number p context lfun pc)
+ (declare (ignore p context pc))
+ (when (and (= frame-number index) lfun)
+ (return-from frame-source-location-for-emacs
+ (function-source-location lfun)))))))
+
+(defimplementation eval-in-frame (form index)
+ (block eval-in-frame
+ (map-backtrace
+ (lambda (frame-number p context lfun pc)
+ (when (= frame-number index)
+ (multiple-value-bind (count vsp parent-vsp)
+ (ccl::count-values-in-frame p context)
+ (let ((bindings nil))
+ (dotimes (i count)
+ (multiple-value-bind (var type name)
+ (ccl::nth-value-in-frame p i context lfun pc vsp parent-vsp)
+ (declare (ignore type))
+ (when name
+ (push (list name `',var) bindings))
+ ))
+ (return-from eval-in-frame
+ (eval `(let ,bindings
+ (declare (ignorable ,@(mapcar 'car bindings)))
+ ,form)))
+ )))))))
+
+(defimplementation return-from-frame (index form)
+ (let ((values (multiple-value-list (eval-in-frame form index))))
+ (map-backtrace
+ (lambda (frame-number p context lfun pc)
+ (declare (ignore context lfun pc))
+ (when (= frame-number index)
+ (ccl::apply-in-frame p #'values values))))))
+
+(defimplementation restart-frame (index)
+ (map-backtrace
+ (lambda (frame-number p context lfun pc)
+ (when (= frame-number index)
+ (ccl::apply-in-frame p lfun
+ (ccl::frame-supplied-args p lfun pc nil context))))))
+
+;;; Utilities
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (flet ((doc (kind &optional (sym symbol))
+ (or (documentation sym kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (when (boundp symbol)
+ (doc 'variable)))
+ (maybe-push
+ :function (if (fboundp symbol)
+ (doc 'function)))
+ (maybe-push
+ :setf (let ((setf-function-name (ccl::setf-function-spec-name
+ `(setf ,symbol))))
+ (when (fboundp setf-function-name)
+ (doc 'function setf-function-name))))
+ result)))
+
+(defimplementation describe-definition (symbol namespace)
+ (ecase namespace
+ (:variable
+ (describe symbol))
+ ((:function :generic-function)
+ (describe (symbol-function symbol)))
+ (:setf
+ (describe (ccl::setf-function-spec-name `(setf ,symbol))))
+ (:class
+ (describe (find-class symbol)))))
+
+(defimplementation toggle-trace (spec)
+ "We currently ignore just about everything."
+ (ecase (car spec)
+ (setf
+ (ccl::%trace spec))
+ (:defmethod
+ (ccl::%trace (second spec)))
+ (:defgeneric
+ (ccl::%trace (second spec)))
+ (:call
+ (toggle-trace (third spec)))
+ ;; mb: FIXME: shouldn't we warn that we're not doing anything for
+ ;; these two?
+ (:labels nil)
+ (:flet nil))
+ t)
+
+;;; XREF
+
+(defimplementation list-callers (symbol)
+ (loop for caller in (ccl::callers symbol)
+ append (multiple-value-bind (info name type specializers modifiers)
+ (ccl::edit-definition-p caller)
+ (loop for (nil . file) in info
+ collect (list (if (eq t type)
+ name
+ `(,type ,name ,specializers
+ , at modifiers))
+ (canonicalize-location file name))))))
+;;; Macroexpansion
+
+(defvar *value2tag* (make-hash-table))
+
+(do-symbols (s (find-package 'arch))
+ (if (and (> (length (symbol-name s)) 7)
+ (string= (symbol-name s) "SUBTAG-" :end1 7)
+ (boundp s)
+ (numberp (symbol-value s))
+ (< (symbol-value s) 255))
+ (setf (gethash (symbol-value s) *value2tag*) s)))
+
+;;;; Inspection
+
+(defclass openmcl-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'openmcl-inspector))
+
+(defimplementation describe-primitive-type (thing)
+ (let ((typecode (ccl::typecode thing)))
+ (if (gethash typecode *value2tag*)
+ (string (gethash typecode *value2tag*))
+ (string (nth typecode '(tag-fixnum tag-list tag-misc tag-imm))))))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (let* ((i (inspector::make-inspector o))
+ (count (inspector::compute-line-count i))
+ (lines
+ (loop
+ for l below count
+ for (value label) = (multiple-value-list
+ (inspector::line-n i l))
+ collect `(:value ,label ,(string-capitalize (format nil "~a" label)))
+ collect " = "
+ collect `(:value ,value)
+ collect '(:newline))))
+ (values (with-output-to-string (s)
+ (let ((*print-lines* 1)
+ (*print-right-margin* 80))
+ (pprint o s)))
+ lines)))
+
+(defmethod inspect-for-emacs :around ((o t) (inspector backend-inspector))
+ (if (or (uvector-inspector-p o)
+ (not (ccl:uvectorp o)))
+ (call-next-method)
+ (multiple-value-bind (title content)
+ (call-next-method)
+ (values
+ title
+ (append content
+ `((:newline)
+ (:value ,(make-instance 'uvector-inspector :object o)
+ "Underlying UVECTOR")))))))
+
+(defclass uvector-inspector ()
+ ((object :initarg :object)))
+
+(defgeneric uvector-inspector-p (object)
+ (:method ((object t)) nil)
+ (:method ((object uvector-inspector)) t))
+
+(defmethod inspect-for-emacs ((uv uvector-inspector)
+ (inspector backend-inspector))
+ (with-slots (object)
+ uv
+ (values (format nil "The UVECTOR for ~S." object)
+ (loop
+ for index below (ccl::uvsize object)
+ collect (format nil "~D: " index)
+ collect `(:value ,(ccl::uvref object index))
+ collect `(:newline)))))
+
+(defun closure-closed-over-values (closure)
+ (let ((howmany (nth-value 8 (ccl::function-args (ccl::closure-function closure)))))
+ (loop for n below howmany
+ collect
+ (let* ((value (ccl::nth-immediate closure (+ 1 (- howmany n))))
+ (map (car (ccl::function-symbol-map (ccl::closure-function closure))))
+ (label (or (and map (svref map n)) n))
+ (cellp (ccl::closed-over-value-p value)))
+ (list label (if cellp (ccl::closed-over-value value) value))))))
+
+(defmethod inspect-for-emacs ((c ccl::compiled-lexical-closure) (inspector t))
+ (declare (ignore inspector))
+ (values
+ (format nil "A closure: ~a" c)
+ `(,@(if (arglist c)
+ (list "Its argument list is: "
+ (funcall (intern "INSPECTOR-PRINC" 'swank) (arglist c)))
+ ;; FIXME inspector-princ should load earlier
+ (list "A function of no arguments"))
+ (:newline)
+ ,@(when (documentation c t)
+ `("Documentation:" (:newline) ,(documentation c t) (:newline)))
+ ,(format nil "Closed over ~a values" (length (closure-closed-over-values c)))
+ (:newline)
+ ,@(loop for (name value) in (closure-closed-over-values c)
+ for count from 1
+ append
+ (label-value-line* ((format nil "~2,' d) ~a" count (string name)) value))))))
+
+
+
+
+;;; Multiprocessing
+
+(defvar *known-processes* '() ; FIXME: leakage. -luke
+ "Alist (ID . PROCESS MAILBOX) list of processes that we have handed
+out IDs for.")
+
+(defvar *known-processes-lock* (ccl:make-lock "*known-processes-lock*"))
+
+(defstruct (mailbox (:conc-name mailbox.))
+ (mutex (ccl:make-lock "thread mailbox"))
+ (semaphore (ccl:make-semaphore))
+ (queue '() :type list))
+
+(defimplementation spawn (fn &key name)
+ (ccl:process-run-function (or name "Anonymous (Swank)") fn))
+
+(defimplementation thread-id (thread)
+ (ccl::process-serial-number thread))
+
+(defimplementation find-thread (id)
+ (find id (ccl:all-processes) :key #'ccl::process-serial-number))
+
+(defimplementation thread-name (thread)
+ (ccl::process-name thread))
+
+(defimplementation thread-status (thread)
+ (format nil "~A" (ccl:process-whostate thread)))
+
+(defimplementation make-lock (&key name)
+ (ccl:make-lock name))
+
+(defimplementation call-with-lock-held (lock function)
+ (ccl:with-lock-grabbed (lock)
+ (funcall function)))
+
+(defimplementation current-thread ()
+ ccl:*current-process*)
+
+(defimplementation all-threads ()
+ (ccl:all-processes))
+
+(defimplementation kill-thread (thread)
+ (ccl:process-kill thread))
+
+;; September 5, 2004 alanr. record the frame interrupted
+(defimplementation interrupt-thread (thread fn)
+ (ccl:process-interrupt
+ thread
+ (lambda(&rest args)
+ (let ((previous-f nil))
+ (block find-frame
+ (map-backtrace
+ #'(lambda(frame-number p context lfun pc)
+ (declare (ignore frame-number context pc))
+ (when (eq previous-f 'ccl::%pascal-functions%)
+ (record-stack-top p)
+ (return-from find-frame))
+ (setq previous-f (ccl::lfun-name lfun)))))
+ (apply fn args)))))
+
+
+(defun mailbox (thread)
+ (ccl:with-lock-grabbed (*known-processes-lock*)
+ (let ((probe (rassoc thread *known-processes* :key #'car)))
+ (cond (probe (second (cdr probe)))
+ (t (let ((mailbox (make-mailbox)))
+ (setq *known-processes*
+ (acons (ccl::process-serial-number thread)
+ (list thread mailbox)
+ (remove-if
+ (lambda(entry)
+ (string= (ccl::process-whostate (second entry)) "Exhausted"))
+ *known-processes*)
+ ))
+ mailbox))))))
+
+(defimplementation send (thread message)
+ (assert message)
+ (let* ((mbox (mailbox thread))
+ (mutex (mailbox.mutex mbox)))
+ (ccl:with-lock-grabbed (mutex)
+ (setf (mailbox.queue mbox)
+ (nconc (mailbox.queue mbox) (list message)))
+ (ccl:signal-semaphore (mailbox.semaphore mbox)))))
+
+(defimplementation receive ()
+ (let* ((mbox (mailbox ccl:*current-process*))
+ (mutex (mailbox.mutex mbox)))
+ (ccl:wait-on-semaphore (mailbox.semaphore mbox))
+ (ccl:with-lock-grabbed (mutex)
+ (assert (mailbox.queue mbox))
+ (pop (mailbox.queue mbox)))))
+
+(defimplementation quit-lisp ()
+ (ccl::quit))
+
+;;; Weak datastructures
+
+(defimplementation make-weak-key-hash-table (&rest args)
+ (apply #'make-hash-table :weak :key args))
+
+(defimplementation make-weak-value-hash-table (&rest args)
+ (apply #'make-hash-table :weak :value args))
+
+(defimplementation hash-table-weakness (hashtable)
+ (ccl::hash-table-weak-p hashtable))
Added: branches/bos/thirdparty/emacs/slime/swank-sbcl.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-sbcl.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,1327 @@
+;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
+;;;
+;;; swank-sbcl.lisp --- SLIME backend for SBCL.
+;;;
+;;; Created 2003, Daniel Barlow <dan at metacircles.com>
+;;;
+;;; This code has been placed in the Public Domain. All warranties are
+;;; disclaimed.
+
+;;; Requires the SB-INTROSPECT contrib.
+
+;;; Administrivia
+
+(in-package :swank-backend)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ (require 'asdf)
+ (require 'sb-bsd-sockets)
+ (require 'sb-introspect)
+ (require 'sb-posix)
+ (require 'sb-cltl2))
+
+(declaim (optimize (debug 2) (sb-c:insert-step-conditions 0)))
+
+(import-from :sb-gray *gray-stream-symbols* :swank-backend)
+
+;;; backwards compability tests
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+ ;; Generate a form suitable for testing for stepper support (0.9.17)
+ ;; with #+.
+ (defun sbcl-with-new-stepper-p ()
+ (if (find-symbol "ENABLE-STEPPING" "SB-IMPL")
+ '(:and)
+ '(:or)))
+ ;; Ditto for weak hash-tables
+ (defun sbcl-with-weak-hash-tables ()
+ (if (find-symbol "HASH-TABLE-WEAKNESS" "SB-EXT")
+ '(:and)
+ '(:or)))
+ ;; And for xref support (1.0.1)
+ (defun sbcl-with-xref-p ()
+ (if (find-symbol "WHO-CALLS" "SB-INTROSPECT")
+ '(:and)
+ '(:or)))
+ ;; ... for restart-frame support (1.0.2)
+ (defun sbcl-with-restart-frame ()
+ (if (find-symbol "FRAME-HAS-DEBUG-TAG-P" "SB-DEBUG")
+ '(:and)
+ '(:or))))
+
+;;; swank-mop
+
+(import-swank-mop-symbols :sb-mop '(:slot-definition-documentation))
+
+(defun swank-mop:slot-definition-documentation (slot)
+ (sb-pcl::documentation slot t))
+
+;;; TCP Server
+
+(defimplementation preferred-communication-style ()
+ (cond
+ ;; fixme: when SBCL/win32 gains better select() support, remove
+ ;; this.
+ ((member :win32 *features*) nil)
+ ((member :sb-thread *features*) :spawn)
+ (t :fd-handler)))
+
+(defun resolve-hostname (name)
+ (car (sb-bsd-sockets:host-ent-addresses
+ (sb-bsd-sockets:get-host-by-name name))))
+
+(defimplementation create-socket (host port)
+ (let ((socket (make-instance 'sb-bsd-sockets:inet-socket
+ :type :stream
+ :protocol :tcp)))
+ (setf (sb-bsd-sockets:sockopt-reuse-address socket) t)
+ (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port)
+ (sb-bsd-sockets:socket-listen socket 5)
+ socket))
+
+(defimplementation local-port (socket)
+ (nth-value 1 (sb-bsd-sockets:socket-name socket)))
+
+(defimplementation close-socket (socket)
+ (sb-sys:invalidate-descriptor (socket-fd socket))
+ (sb-bsd-sockets:socket-close socket))
+
+(defimplementation accept-connection (socket &key
+ external-format
+ buffering timeout)
+ (declare (ignore timeout))
+ (make-socket-io-stream (accept socket)
+ (or external-format :iso-latin-1-unix)
+ (or buffering :full)))
+
+(defvar *sigio-handlers* '()
+ "List of (key . fn) pairs to be called on SIGIO.")
+
+(defun sigio-handler (signal code scp)
+ (declare (ignore signal code scp))
+ (mapc (lambda (handler)
+ (funcall (the function (cdr handler))))
+ *sigio-handlers*))
+
+(defun set-sigio-handler ()
+ (sb-sys:enable-interrupt sb-unix:sigio (lambda (signal code scp)
+ (sigio-handler signal code scp))))
+
+(defun enable-sigio-on-fd (fd)
+ (sb-posix::fcntl fd sb-posix::f-setfl sb-posix::o-async)
+ (sb-posix::fcntl fd sb-posix::f-setown (getpid)))
+
+(defimplementation add-sigio-handler (socket fn)
+ (set-sigio-handler)
+ (let ((fd (socket-fd socket)))
+ (format *debug-io* "Adding sigio handler: ~S ~%" fd)
+ (enable-sigio-on-fd fd)
+ (push (cons fd fn) *sigio-handlers*)))
+
+(defimplementation remove-sigio-handlers (socket)
+ (let ((fd (socket-fd socket)))
+ (setf *sigio-handlers* (delete fd *sigio-handlers* :key #'car))
+ (sb-sys:invalidate-descriptor fd))
+ (close socket))
+
+(defimplementation add-fd-handler (socket fn)
+ (declare (type function fn))
+ (let ((fd (socket-fd socket)))
+ (format *debug-io* "; Adding fd handler: ~S ~%" fd)
+ (sb-sys:add-fd-handler fd :input (lambda (_)
+ _
+ (funcall fn)))))
+
+(defimplementation remove-fd-handlers (socket)
+ (sb-sys:invalidate-descriptor (socket-fd socket)))
+
+(defun socket-fd (socket)
+ (etypecase socket
+ (fixnum socket)
+ (sb-bsd-sockets:socket (sb-bsd-sockets:socket-file-descriptor socket))
+ (file-stream (sb-sys:fd-stream-fd socket))))
+
+(defvar *external-format-to-coding-system*
+ '((:iso-8859-1
+ "latin-1" "latin-1-unix" "iso-latin-1-unix"
+ "iso-8859-1" "iso-8859-1-unix")
+ (:utf-8 "utf-8" "utf-8-unix")
+ (:euc-jp "euc-jp" "euc-jp-unix")
+ (:us-ascii "us-ascii" "us-ascii-unix")))
+
+(defimplementation find-external-format (coding-system)
+ (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
+ *external-format-to-coding-system*)))
+
+(defun make-socket-io-stream (socket external-format buffering)
+ (sb-bsd-sockets:socket-make-stream socket
+ :output t
+ :input t
+ :element-type 'character
+ :buffering buffering
+ #+sb-unicode :external-format
+ #+sb-unicode external-format
+ ))
+
+(defun accept (socket)
+ "Like socket-accept, but retry on EAGAIN."
+ (loop (handler-case
+ (return (sb-bsd-sockets:socket-accept socket))
+ (sb-bsd-sockets:interrupted-error ()))))
+
+(defimplementation call-without-interrupts (fn)
+ (declare (type function fn))
+ (sb-sys:without-interrupts (funcall fn)))
+
+(defimplementation getpid ()
+ (sb-posix:getpid))
+
+(defimplementation lisp-implementation-type-name ()
+ "sbcl")
+
+
+;;;; Support for SBCL syntax
+
+;;; SBCL's source code is riddled with #! reader macros. Also symbols
+;;; containing `!' have special meaning. We have to work long and
+;;; hard to be able to read the source. To deal with #! reader
+;;; macros, we use a special readtable. The special symbols are
+;;; converted by a condition handler.
+
+(defun feature-in-list-p (feature list)
+ (etypecase feature
+ (symbol (member feature list :test #'eq))
+ (cons (flet ((subfeature-in-list-p (subfeature)
+ (feature-in-list-p subfeature list)))
+ (ecase (first feature)
+ (:or (some #'subfeature-in-list-p (rest feature)))
+ (:and (every #'subfeature-in-list-p (rest feature)))
+ (:not (destructuring-bind (e) (cdr feature)
+ (not (subfeature-in-list-p e)))))))))
+
+(defun shebang-reader (stream sub-character infix-parameter)
+ (declare (ignore sub-character))
+ (when infix-parameter
+ (error "illegal read syntax: #~D!" infix-parameter))
+ (let ((next-char (read-char stream)))
+ (unless (find next-char "+-")
+ (error "illegal read syntax: #!~C" next-char))
+ ;; When test is not satisfied
+ ;; FIXME: clearer if order of NOT-P and (NOT NOT-P) were reversed? then
+ ;; would become "unless test is satisfied"..
+ (when (let* ((*package* (find-package "KEYWORD"))
+ (*read-suppress* nil)
+ (not-p (char= next-char #\-))
+ (feature (read stream)))
+ (if (feature-in-list-p feature *features*)
+ not-p
+ (not not-p)))
+ ;; Read (and discard) a form from input.
+ (let ((*read-suppress* t))
+ (read stream t nil t))))
+ (values))
+
+(defvar *shebang-readtable*
+ (let ((*readtable* (copy-readtable nil)))
+ (set-dispatch-macro-character #\# #\!
+ (lambda (s c n) (shebang-reader s c n))
+ *readtable*)
+ *readtable*))
+
+(defun shebang-readtable ()
+ *shebang-readtable*)
+
+(defun sbcl-package-p (package)
+ (let ((name (package-name package)))
+ (eql (mismatch "SB-" name) 3)))
+
+(defun sbcl-source-file-p (filename)
+ (when filename
+ (loop for (_ pattern) in (logical-pathname-translations "SYS")
+ thereis (pathname-match-p filename pattern))))
+
+(defun guess-readtable-for-filename (filename)
+ (if (sbcl-source-file-p filename)
+ (shebang-readtable)
+ *readtable*))
+
+(defvar *debootstrap-packages* t)
+
+(defun call-with-debootstrapping (fun)
+ (handler-bind ((sb-int:bootstrap-package-not-found
+ #'sb-int:debootstrap-package))
+ (funcall fun)))
+
+(defmacro with-debootstrapping (&body body)
+ `(call-with-debootstrapping (lambda () , at body)))
+
+(defimplementation call-with-syntax-hooks (fn)
+ (cond ((and *debootstrap-packages*
+ (sbcl-package-p *package*))
+ (with-debootstrapping (funcall fn)))
+ (t
+ (funcall fn))))
+
+(defimplementation default-readtable-alist ()
+ (let ((readtable (shebang-readtable)))
+ (loop for p in (remove-if-not #'sbcl-package-p (list-all-packages))
+ collect (cons (package-name p) readtable))))
+
+;;; Utilities
+
+(defimplementation arglist (fname)
+ (sb-introspect:function-arglist fname))
+
+(defimplementation function-name (f)
+ (check-type f function)
+ (sb-impl::%fun-name f))
+
+(defmethod declaration-arglist ((decl-identifier (eql 'optimize)))
+ (flet ((ensure-list (thing) (if (listp thing) thing (list thing))))
+ (let* ((flags (sb-cltl2:declaration-information decl-identifier)))
+ (if flags
+ ;; Symbols aren't printed with package qualifiers, but the FLAGS would
+ ;; have to be fully qualified when used inside a declaration. So we
+ ;; strip those as long as there's no better way. (FIXME)
+ `(&any ,@(remove-if-not #'(lambda (qualifier)
+ (find-symbol (symbol-name (first qualifier)) :cl))
+ flags :key #'ensure-list))
+ (call-next-method)))))
+
+(defvar *buffer-name* nil)
+(defvar *buffer-offset*)
+(defvar *buffer-substring* nil)
+
+(defvar *previous-compiler-condition* nil
+ "Used to detect duplicates.")
+
+(defun handle-notification-condition (condition)
+ "Handle a condition caused by a compiler warning.
+This traps all compiler conditions at a lower-level than using
+C:*COMPILER-NOTIFICATION-FUNCTION*. The advantage is that we get to
+craft our own error messages, which can omit a lot of redundant
+information."
+ (let ((context (sb-c::find-error-context nil)))
+ (unless (eq condition *previous-compiler-condition*)
+ (setq *previous-compiler-condition* condition)
+ (signal-compiler-condition condition context))))
+
+(defun signal-compiler-condition (condition context)
+ (signal (make-condition
+ 'compiler-condition
+ :original-condition condition
+ :severity (etypecase condition
+ (sb-c:compiler-error :error)
+ (sb-ext:compiler-note :note)
+ (style-warning :style-warning)
+ (warning :warning)
+ (error :error))
+ :short-message (brief-compiler-message-for-emacs condition)
+ :references (condition-references (real-condition condition))
+ :message (long-compiler-message-for-emacs condition context)
+ :location (compiler-note-location context))))
+
+(defun real-condition (condition)
+ "Return the encapsulated condition or CONDITION itself."
+ (typecase condition
+ (sb-int:encapsulated-condition (sb-int:encapsulated-condition condition))
+ (t condition)))
+
+(defun condition-references (condition)
+ (if (typep condition 'sb-int:reference-condition)
+ (externalize-reference
+ (sb-int:reference-condition-references condition))))
+
+(defun compiler-note-location (context)
+ (if context
+ (locate-compiler-note
+ (sb-c::compiler-error-context-file-name context)
+ (compiler-source-path context)
+ (sb-c::compiler-error-context-original-source context))
+ (list :error "No error location available")))
+
+(defun locate-compiler-note (file source-path source)
+ (cond ((and (not (eq file :lisp)) *buffer-name*)
+ ;; Compiling from a buffer
+ (let ((position (+ *buffer-offset*
+ (source-path-string-position
+ source-path *buffer-substring*))))
+ (make-location (list :buffer *buffer-name*)
+ (list :position position))))
+ ((and (pathnamep file) (null *buffer-name*))
+ ;; Compiling from a file
+ (make-location (list :file (namestring file))
+ (list :position
+ (1+ (source-path-file-position
+ source-path file)))))
+ ((and (eq file :lisp) (stringp source))
+ ;; Compiling macro generated code
+ (make-location (list :source-form source)
+ (list :position 1)))
+ (t
+ (error "unhandled case in compiler note ~S ~S ~S" file source-path source))))
+
+(defun brief-compiler-message-for-emacs (condition)
+ "Briefly describe a compiler error for Emacs.
+When Emacs presents the message it already has the source popped up
+and the source form highlighted. This makes much of the information in
+the error-context redundant."
+ (let ((sb-int:*print-condition-references* nil))
+ (princ-to-string condition)))
+
+(defun long-compiler-message-for-emacs (condition error-context)
+ "Describe a compiler error for Emacs including context information."
+ (declare (type (or sb-c::compiler-error-context null) error-context))
+ (multiple-value-bind (enclosing source)
+ (if error-context
+ (values (sb-c::compiler-error-context-enclosing-source error-context)
+ (sb-c::compiler-error-context-source error-context)))
+ (let ((sb-int:*print-condition-references* nil))
+ (format nil "~@[--> ~{~<~%--> ~1:;~A~> ~}~%~]~@[~{==>~%~A~%~}~]~A"
+ enclosing source condition))))
+
+(defun compiler-source-path (context)
+ "Return the source-path for the current compiler error.
+Returns NIL if this cannot be determined by examining internal
+compiler state."
+ (cond ((sb-c::node-p context)
+ (reverse
+ (sb-c::source-path-original-source
+ (sb-c::node-source-path context))))
+ ((sb-c::compiler-error-context-p context)
+ (reverse
+ (sb-c::compiler-error-context-original-source-path context)))))
+
+(defimplementation call-with-compilation-hooks (function)
+ (declare (type function function))
+ (handler-bind ((sb-c:fatal-compiler-error #'handle-file-compiler-termination)
+ (sb-c:compiler-error #'handle-notification-condition)
+ (sb-ext:compiler-note #'handle-notification-condition)
+ (style-warning #'handle-notification-condition)
+ (warning #'handle-notification-condition))
+ (funcall function)))
+
+(defun handle-file-compiler-termination (condition)
+ "Handle a condition that caused the file compiler to terminate."
+ (handle-notification-condition
+ (sb-int:encapsulated-condition condition)))
+
+(defvar *trap-load-time-warnings* nil)
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (handler-case
+ (let ((output-file (with-compilation-hooks ()
+ (compile-file filename
+ :external-format external-format))))
+ (when output-file
+ ;; Cache the latest source file for definition-finding.
+ (source-cache-get filename (file-write-date filename))
+ (when load-p
+ (load output-file))))
+ (sb-c:fatal-compiler-error () nil)))
+
+;;;; compile-string
+
+;;; We copy the string to a temporary file in order to get adequate
+;;; semantics for :COMPILE-TOPLEVEL and :LOAD-TOPLEVEL EVAL-WHEN forms
+;;; which the previous approach using
+;;; (compile nil `(lambda () ,(read-from-string string)))
+;;; did not provide.
+
+(sb-alien:define-alien-routine "tmpnam" sb-alien:c-string
+ (dest (* sb-alien:c-string)))
+
+(defun temp-file-name ()
+ "Return a temporary file name to compile strings into."
+ (concatenate 'string (tmpnam nil) ".lisp"))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (let ((*buffer-name* buffer)
+ (*buffer-offset* position)
+ (*buffer-substring* string)
+ (filename (temp-file-name)))
+ (flet ((compile-it (fn)
+ (with-compilation-hooks ()
+ (with-compilation-unit
+ (:source-plist (list :emacs-buffer buffer
+ :emacs-directory directory
+ :emacs-string string
+ :emacs-position position))
+ (funcall fn (compile-file filename))))))
+ (with-open-file (s filename :direction :output :if-exists :error)
+ (write-string string s))
+ (unwind-protect
+ (if *trap-load-time-warnings*
+ (compile-it #'load)
+ (load (compile-it #'identity)))
+ (ignore-errors
+ (delete-file filename)
+ (delete-file (compile-file-pathname filename)))))))
+
+;;;; Definitions
+
+(defvar *debug-definition-finding* nil
+ "When true don't handle errors while looking for definitions.
+This is useful when debugging the definition-finding code.")
+
+(defparameter *definition-types*
+ '(:variable defvar
+ :constant defconstant
+ :type deftype
+ :symbol-macro define-symbol-macro
+ :macro defmacro
+ :compiler-macro define-compiler-macro
+ :function defun
+ :generic-function defgeneric
+ :method defmethod
+ :setf-expander define-setf-expander
+ :structure defstruct
+ :condition define-condition
+ :class defclass
+ :method-combination define-method-combination
+ :package defpackage
+ :transform :deftransform
+ :optimizer :defoptimizer
+ :vop :define-vop
+ :source-transform :define-source-transform)
+ "Map SB-INTROSPECT definition type names to Slime-friendly forms")
+
+(defimplementation find-definitions (name)
+ (loop for type in *definition-types* by #'cddr
+ for locations = (sb-introspect:find-definition-sources-by-name
+ name type)
+ append (loop for source-location in locations collect
+ (make-source-location-specification type name
+ source-location))))
+
+(defun make-source-location-specification (type name source-location)
+ (list (list* (getf *definition-types* type)
+ name
+ (sb-introspect::definition-source-description source-location))
+ (if *debug-definition-finding*
+ (make-definition-source-location source-location type name)
+ (handler-case
+ (make-definition-source-location source-location type name)
+ (error (e)
+ (list :error (format nil "Error: ~A" e)))))))
+
+(defun make-definition-source-location (definition-source type name)
+ (with-struct (sb-introspect::definition-source-
+ pathname form-path character-offset plist
+ file-write-date)
+ definition-source
+ (destructuring-bind (&key emacs-buffer emacs-position emacs-directory
+ emacs-string &allow-other-keys)
+ plist
+ (cond
+ (emacs-buffer
+ (let* ((*readtable* (guess-readtable-for-filename emacs-directory))
+ (pos (if form-path
+ (with-debootstrapping
+ (source-path-string-position form-path emacs-string))
+ character-offset))
+ (snippet (string-path-snippet emacs-string form-path pos)))
+ (make-location `(:buffer ,emacs-buffer)
+ `(:position ,(+ pos emacs-position))
+ `(:snippet ,snippet))))
+ ((not pathname)
+ `(:error ,(format nil "Source of ~A ~A not found"
+ (string-downcase type) name)))
+ (t
+ (let* ((namestring (namestring (translate-logical-pathname pathname)))
+ (pos (source-file-position namestring file-write-date form-path
+ character-offset))
+ (snippet (source-hint-snippet namestring file-write-date pos)))
+ (make-location `(:file ,namestring)
+ `(:position ,pos)
+ `(:snippet ,snippet))))))))
+
+(defun string-path-snippet (string form-path position)
+ (if form-path
+ ;; If we have a form-path, use it to derive a more accurate
+ ;; snippet, so that we can point to the individual form rather
+ ;; than just the toplevel form.
+ (multiple-value-bind (data end)
+ (let ((*read-suppress* t))
+ (read-from-string string nil nil :start position))
+ (declare (ignore data))
+ (subseq string position end))
+ string))
+
+(defun source-file-position (filename write-date form-path character-offset)
+ (let ((source (get-source-code filename write-date))
+ (*readtable* (guess-readtable-for-filename filename)))
+ (1+ (with-debootstrapping
+ (if form-path
+ (source-path-string-position form-path source)
+ (or character-offset 0))))))
+
+(defun source-hint-snippet (filename write-date position)
+ (let ((source (get-source-code filename write-date)))
+ (with-input-from-string (s source)
+ (read-snippet s position))))
+
+(defun function-source-location (function &optional name)
+ (declare (type function function))
+ (let ((location (sb-introspect:find-definition-source function)))
+ (make-definition-source-location location :function name)))
+
+(defun safe-function-source-location (fun name)
+ (if *debug-definition-finding*
+ (function-source-location fun name)
+ (handler-case (function-source-location fun name)
+ (error (e)
+ (list :error (format nil "Error: ~A" e))))))
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ "Return a plist describing SYMBOL.
+Return NIL if the symbol is unbound."
+ (let ((result '()))
+ (flet ((doc (kind)
+ (or (documentation symbol kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (multiple-value-bind (kind recorded-p)
+ (sb-int:info :variable :kind symbol)
+ (declare (ignore kind))
+ (if (or (boundp symbol) recorded-p)
+ (doc 'variable))))
+ (when (fboundp symbol)
+ (maybe-push
+ (cond ((macro-function symbol) :macro)
+ ((special-operator-p symbol) :special-operator)
+ ((typep (fdefinition symbol) 'generic-function)
+ :generic-function)
+ (t :function))
+ (doc 'function)))
+ (maybe-push
+ :setf (if (or (sb-int:info :setf :inverse symbol)
+ (sb-int:info :setf :expander symbol))
+ (doc 'setf)))
+ (maybe-push
+ :type (if (sb-int:info :type :kind symbol)
+ (doc 'type)))
+ result)))
+
+(defimplementation describe-definition (symbol type)
+ (case type
+ (:variable
+ (describe symbol))
+ (:function
+ (describe (symbol-function symbol)))
+ (:setf
+ (describe (or (sb-int:info :setf :inverse symbol)
+ (sb-int:info :setf :expander symbol))))
+ (:class
+ (describe (find-class symbol)))
+ (:type
+ (describe (sb-kernel:values-specifier-type symbol)))))
+
+#+#.(swank-backend::sbcl-with-xref-p)
+(progn
+ (defmacro defxref (name)
+ `(defimplementation ,name (what)
+ (sanitize-xrefs
+ (mapcar #'source-location-for-xref-data
+ (,(find-symbol (symbol-name name) "SB-INTROSPECT")
+ what)))))
+ (defxref who-calls)
+ (defxref who-binds)
+ (defxref who-sets)
+ (defxref who-references)
+ (defxref who-macroexpands))
+
+(defun source-location-for-xref-data (xref-data)
+ (let ((name (car xref-data))
+ (source-location (cdr xref-data)))
+ (list name
+ (handler-case (make-definition-source-location source-location
+ 'function
+ name)
+ (error (e)
+ (list :error (format nil "Error: ~A" e)))))))
+
+(defimplementation list-callers (symbol)
+ (let ((fn (fdefinition symbol)))
+ (sanitize-xrefs
+ (mapcar #'function-dspec (sb-introspect:find-function-callers fn)))))
+
+(defimplementation list-callees (symbol)
+ (let ((fn (fdefinition symbol)))
+ (sanitize-xrefs
+ (mapcar #'function-dspec (sb-introspect:find-function-callees fn)))))
+
+(defun sanitize-xrefs (xrefs)
+ (remove-duplicates
+ (remove-if (lambda (f)
+ (member f (ignored-xref-function-names)))
+ (loop for entry in xrefs
+ for name = (car entry)
+ collect (if (and (consp name)
+ (member (car name)
+ '(sb-pcl::fast-method
+ sb-pcl::slow-method
+ sb-pcl::method)))
+ (cons (cons 'defmethod (cdr name))
+ (cdr entry))
+ entry))
+ :key #'car)
+ :test (lambda (a b)
+ (and (eq (first a) (first b))
+ (equal (second a) (second b))))))
+
+(defun ignored-xref-function-names ()
+ #-#.(swank-backend::sbcl-with-new-stepper-p)
+ '(nil sb-c::step-form sb-c::step-values)
+ #+#.(swank-backend::sbcl-with-new-stepper-p)
+ '(nil))
+
+(defun function-dspec (fn)
+ "Describe where the function FN was defined.
+Return a list of the form (NAME LOCATION)."
+ (let ((name (sb-kernel:%fun-name fn)))
+ (list name (safe-function-source-location fn name))))
+
+;;; macroexpansion
+
+(defimplementation macroexpand-all (form)
+ (let ((sb-walker:*walk-form-expand-macros-p* t))
+ (sb-walker:walk-form form)))
+
+
+;;; Debugging
+
+(defvar *sldb-stack-top*)
+
+(defimplementation install-debugger-globally (function)
+ (setq sb-ext:*invoke-debugger-hook* function))
+
+(defimplementation condition-extras (condition)
+ (cond #+#.(swank-backend::sbcl-with-new-stepper-p)
+ ((typep condition 'sb-impl::step-form-condition)
+ `((:show-frame-source 0)))
+ ((typep condition 'sb-int:reference-condition)
+ (let ((refs (sb-int:reference-condition-references condition)))
+ (if refs
+ `((:references ,(externalize-reference refs))))))))
+
+(defun externalize-reference (ref)
+ (etypecase ref
+ (null nil)
+ (cons (cons (externalize-reference (car ref))
+ (externalize-reference (cdr ref))))
+ ((or string number) ref)
+ (symbol
+ (cond ((eq (symbol-package ref) (symbol-package :test))
+ ref)
+ (t (symbol-name ref))))))
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (declare (type function debugger-loop-fn))
+ (let* ((*sldb-stack-top* (or sb-debug:*stack-top-hint* (sb-di:top-frame)))
+ (sb-debug:*stack-top-hint* nil))
+ (handler-bind ((sb-di:debug-condition
+ (lambda (condition)
+ (signal (make-condition
+ 'sldb-condition
+ :original-condition condition)))))
+ (funcall debugger-loop-fn))))
+
+#+#.(swank-backend::sbcl-with-new-stepper-p)
+(progn
+ (defimplementation activate-stepping (frame)
+ (declare (ignore frame))
+ (sb-impl::enable-stepping))
+ (defimplementation sldb-stepper-condition-p (condition)
+ (typep condition 'sb-ext:step-form-condition))
+ (defimplementation sldb-step-into ()
+ (invoke-restart 'sb-ext:step-into))
+ (defimplementation sldb-step-next ()
+ (invoke-restart 'sb-ext:step-next))
+ (defimplementation sldb-step-out ()
+ (invoke-restart 'sb-ext:step-out)))
+
+(defimplementation call-with-debugger-hook (hook fun)
+ (let ((sb-ext:*invoke-debugger-hook* hook)
+ #+#.(swank-backend::sbcl-with-new-stepper-p)
+ (sb-ext:*stepper-hook*
+ (lambda (condition)
+ (typecase condition
+ (sb-ext:step-form-condition
+ (let ((sb-debug:*stack-top-hint* (sb-di::find-stepped-frame)))
+ (sb-impl::invoke-debugger condition)))))))
+ (handler-bind (#+#.(swank-backend::sbcl-with-new-stepper-p)
+ (sb-ext:step-condition #'sb-impl::invoke-stepper))
+ (funcall fun))))
+
+(defun nth-frame (index)
+ (do ((frame *sldb-stack-top* (sb-di:frame-down frame))
+ (i index (1- i)))
+ ((zerop i) frame)))
+
+(defimplementation compute-backtrace (start end)
+ "Return a list of frames starting with frame number START and
+continuing to frame number END or, if END is nil, the last frame on the
+stack."
+ (let ((end (or end most-positive-fixnum)))
+ (loop for f = (nth-frame start) then (sb-di:frame-down f)
+ for i from start below end
+ while f
+ collect f)))
+
+(defimplementation print-frame (frame stream)
+ (sb-debug::print-frame-call frame stream))
+
+;;;; Code-location -> source-location translation
+
+;;; If debug-block info is avaibale, we determine the file position of
+;;; the source-path for a code-location. If the code was compiled
+;;; with C-c C-c, we have to search the position in the source string.
+;;; If there's no debug-block info, we return the (less precise)
+;;; source-location of the corresponding function.
+
+(defun code-location-source-location (code-location)
+ (let* ((dsource (sb-di:code-location-debug-source code-location))
+ (plist (sb-c::debug-source-plist dsource)))
+ (if (getf plist :emacs-buffer)
+ (emacs-buffer-source-location code-location plist)
+ (ecase (sb-di:debug-source-from dsource)
+ (:file (file-source-location code-location))
+ (:lisp (lisp-source-location code-location))))))
+
+;;; FIXME: The naming policy of source-location functions is a bit
+;;; fuzzy: we have FUNCTION-SOURCE-LOCATION which returns the
+;;; source-location for a function, and we also have FILE-SOURCE-LOCATION &co
+;;; which returns the source location for a _code-location_.
+;;;
+;;; Maybe these should be named code-location-file-source-location,
+;;; etc, turned into generic functions, or something. In the very
+;;; least the names should indicate the main entry point vs. helper
+;;; status.
+
+(defun file-source-location (code-location)
+ (if (code-location-has-debug-block-info-p code-location)
+ (source-file-source-location code-location)
+ (fallback-source-location code-location)))
+
+(defun fallback-source-location (code-location)
+ (let ((fun (code-location-debug-fun-fun code-location)))
+ (cond (fun (function-source-location fun))
+ (t (error "Cannot find source location for: ~A " code-location)))))
+
+(defun lisp-source-location (code-location)
+ (let ((source (prin1-to-string
+ (sb-debug::code-location-source-form code-location 100))))
+ (make-location `(:source-form ,source) '(:position 0))))
+
+(defun emacs-buffer-source-location (code-location plist)
+ (if (code-location-has-debug-block-info-p code-location)
+ (destructuring-bind (&key emacs-buffer emacs-position emacs-string
+ &allow-other-keys)
+ plist
+ (let* ((pos (string-source-position code-location emacs-string))
+ (snipped (with-input-from-string (s emacs-string)
+ (read-snippet s pos))))
+ (make-location `(:buffer ,emacs-buffer)
+ `(:position ,(+ emacs-position pos))
+ `(:snippet ,snipped))))
+ (fallback-source-location code-location)))
+
+(defun source-file-source-location (code-location)
+ (let* ((code-date (code-location-debug-source-created code-location))
+ (filename (code-location-debug-source-name code-location))
+ (*readtable* (guess-readtable-for-filename filename))
+ (source-code (get-source-code filename code-date)))
+ (with-debootstrapping
+ (with-input-from-string (s source-code)
+ (let* ((pos (stream-source-position code-location s))
+ (snippet (read-snippet s pos)))
+ (make-location `(:file ,filename)
+ `(:position ,(1+ pos))
+ `(:snippet ,snippet)))))))
+
+(defun code-location-debug-source-name (code-location)
+ (namestring (truename (sb-c::debug-source-name
+ (sb-di::code-location-debug-source code-location)))))
+
+(defun code-location-debug-source-created (code-location)
+ (sb-c::debug-source-created
+ (sb-di::code-location-debug-source code-location)))
+
+(defun code-location-debug-fun-fun (code-location)
+ (sb-di:debug-fun-fun (sb-di:code-location-debug-fun code-location)))
+
+(defun code-location-has-debug-block-info-p (code-location)
+ (handler-case
+ (progn (sb-di:code-location-debug-block code-location)
+ t)
+ (sb-di:no-debug-blocks () nil)))
+
+(defun stream-source-position (code-location stream)
+ (let* ((cloc (sb-debug::maybe-block-start-location code-location))
+ (tlf-number (sb-di::code-location-toplevel-form-offset cloc))
+ (form-number (sb-di::code-location-form-number cloc)))
+ (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream)
+ (let* ((path-table (sb-di::form-number-translations tlf 0))
+ (path (cond ((<= (length path-table) form-number)
+ (warn "inconsistent form-number-translations")
+ (list 0))
+ (t
+ (reverse (cdr (aref path-table form-number)))))))
+ (source-path-source-position path tlf pos-map)))))
+
+(defun string-source-position (code-location string)
+ (with-input-from-string (s string)
+ (stream-source-position code-location s)))
+
+;;; source-path-file-position and friends are in swank-source-path-parser
+
+(defun safe-source-location-for-emacs (code-location)
+ (if *debug-definition-finding*
+ (code-location-source-location code-location)
+ (handler-case (code-location-source-location code-location)
+ (error (c) (list :error (format nil "~A" c))))))
+
+(defimplementation frame-source-location-for-emacs (index)
+ (safe-source-location-for-emacs
+ (sb-di:frame-code-location (nth-frame index))))
+
+(defun frame-debug-vars (frame)
+ "Return a vector of debug-variables in frame."
+ (sb-di::debug-fun-debug-vars (sb-di:frame-debug-fun frame)))
+
+(defun debug-var-value (var frame location)
+ (ecase (sb-di:debug-var-validity var location)
+ (:valid (sb-di:debug-var-value var frame))
+ ((:invalid :unknown) ':<not-available>)))
+
+(defimplementation frame-locals (index)
+ (let* ((frame (nth-frame index))
+ (loc (sb-di:frame-code-location frame))
+ (vars (frame-debug-vars frame)))
+ (loop for v across vars collect
+ (list :name (sb-di:debug-var-symbol v)
+ :id (sb-di:debug-var-id v)
+ :value (debug-var-value v frame loc)))))
+
+(defimplementation frame-var-value (frame var)
+ (let* ((frame (nth-frame frame))
+ (dvar (aref (frame-debug-vars frame) var)))
+ (debug-var-value dvar frame (sb-di:frame-code-location frame))))
+
+(defimplementation frame-catch-tags (index)
+ (mapcar #'car (sb-di:frame-catches (nth-frame index))))
+
+(defimplementation eval-in-frame (form index)
+ (let ((frame (nth-frame index)))
+ (funcall (the function
+ (sb-di:preprocess-for-eval form
+ (sb-di:frame-code-location frame)))
+ frame)))
+
+#+#.(swank-backend::sbcl-with-restart-frame)
+(progn
+ (defimplementation return-from-frame (index form)
+ (let* ((frame (nth-frame index)))
+ (cond ((sb-debug:frame-has-debug-tag-p frame)
+ (let ((values (multiple-value-list (eval-in-frame form index))))
+ (sb-debug:unwind-to-frame-and-call frame
+ (lambda ()
+ (values-list values)))))
+ (t (format nil "Cannot return from frame: ~S" frame)))))
+
+ (defimplementation restart-frame (index)
+ (let* ((frame (nth-frame index)))
+ (cond ((sb-debug:frame-has-debug-tag-p frame)
+ (let* ((call-list (sb-debug::frame-call-as-list frame))
+ (fun (fdefinition (car call-list)))
+ (thunk (lambda ()
+ ;; Ensure that the thunk gets tail-call-optimized
+ (declare (optimize (debug 1)))
+ (apply fun (cdr call-list)))))
+ (sb-debug:unwind-to-frame-and-call frame thunk)))
+ (t (format nil "Cannot restart frame: ~S" frame))))))
+
+;; FIXME: this implementation doesn't unwind the stack before
+;; re-invoking the function, but it's better than no implementation at
+;; all.
+#-#.(swank-backend::sbcl-with-restart-frame)
+(progn
+ (defun sb-debug-catch-tag-p (tag)
+ (and (symbolp tag)
+ (not (symbol-package tag))
+ (string= tag :sb-debug-catch-tag)))
+
+ (defimplementation return-from-frame (index form)
+ (let* ((frame (nth-frame index))
+ (probe (assoc-if #'sb-debug-catch-tag-p
+ (sb-di::frame-catches frame))))
+ (cond (probe (throw (car probe) (eval-in-frame form index)))
+ (t (format nil "Cannot return from frame: ~S" frame)))))
+
+ (defimplementation restart-frame (index)
+ (let ((frame (nth-frame index)))
+ (return-from-frame index (sb-debug::frame-call-as-list frame)))))
+
+;;;;; reference-conditions
+
+(defimplementation format-sldb-condition (condition)
+ (let ((sb-int:*print-condition-references* nil))
+ (princ-to-string condition)))
+
+
+;;;; Profiling
+
+(defimplementation profile (fname)
+ (when fname (eval `(sb-profile:profile ,fname))))
+
+(defimplementation unprofile (fname)
+ (when fname (eval `(sb-profile:unprofile ,fname))))
+
+(defimplementation unprofile-all ()
+ (sb-profile:unprofile)
+ "All functions unprofiled.")
+
+(defimplementation profile-report ()
+ (sb-profile:report))
+
+(defimplementation profile-reset ()
+ (sb-profile:reset)
+ "Reset profiling counters.")
+
+(defimplementation profiled-functions ()
+ (sb-profile:profile))
+
+(defimplementation profile-package (package callers methods)
+ (declare (ignore callers methods))
+ (eval `(sb-profile:profile ,(package-name (find-package package)))))
+
+
+;;;; Inspector
+
+(defclass sbcl-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'sbcl-inspector))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (cond ((sb-di::indirect-value-cell-p o)
+ (values "A value cell." (label-value-line*
+ (:value (sb-kernel:value-cell-ref o)))))
+ (t
+ (multiple-value-bind (text label parts) (sb-impl::inspected-parts o)
+ (if label
+ (values text (loop for (l . v) in parts
+ append (label-value-line l v)))
+ (values text (loop for value in parts for i from 0
+ append (label-value-line i value))))))))
+
+(defmethod inspect-for-emacs ((o function) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (let ((header (sb-kernel:widetag-of o)))
+ (cond ((= header sb-vm:simple-fun-header-widetag)
+ (values "A simple-fun."
+ (label-value-line*
+ (:name (sb-kernel:%simple-fun-name o))
+ (:arglist (sb-kernel:%simple-fun-arglist o))
+ (:self (sb-kernel:%simple-fun-self o))
+ (:next (sb-kernel:%simple-fun-next o))
+ (:type (sb-kernel:%simple-fun-type o))
+ (:code (sb-kernel:fun-code-header o)))))
+ ((= header sb-vm:closure-header-widetag)
+ (values "A closure."
+ (append
+ (label-value-line :function (sb-kernel:%closure-fun o))
+ `("Closed over values:" (:newline))
+ (loop for i below (1- (sb-kernel:get-closure-length o))
+ append (label-value-line
+ i (sb-kernel:%closure-index-ref o i))))))
+ (t (call-next-method o)))))
+
+(defmethod inspect-for-emacs ((o sb-kernel:code-component) (_ backend-inspector))
+ (declare (ignore _))
+ (values (format nil "~A is a code data-block." o)
+ (append
+ (label-value-line*
+ (:code-size (sb-kernel:%code-code-size o))
+ (:entry-points (sb-kernel:%code-entry-points o))
+ (:debug-info (sb-kernel:%code-debug-info o))
+ (:trace-table-offset (sb-kernel:code-header-ref
+ o sb-vm:code-trace-table-offset-slot)))
+ `("Constants:" (:newline))
+ (loop for i from sb-vm:code-constants-offset
+ below (sb-kernel:get-header-data o)
+ append (label-value-line i (sb-kernel:code-header-ref o i)))
+ `("Code:" (:newline)
+ , (with-output-to-string (s)
+ (cond ((sb-kernel:%code-debug-info o)
+ (sb-disassem:disassemble-code-component o :stream s))
+ (t
+ (sb-disassem:disassemble-memory
+ (sb-disassem::align
+ (+ (logandc2 (sb-kernel:get-lisp-obj-address o)
+ sb-vm:lowtag-mask)
+ (* sb-vm:code-constants-offset
+ sb-vm:n-word-bytes))
+ (ash 1 sb-vm:n-lowtag-bits))
+ (ash (sb-kernel:%code-code-size o) sb-vm:word-shift)
+ :stream s))))))))
+
+(defmethod inspect-for-emacs ((o sb-ext:weak-pointer) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values "A weak pointer."
+ (label-value-line*
+ (:value (sb-ext:weak-pointer-value o)))))
+
+(defmethod inspect-for-emacs ((o sb-kernel:fdefn) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values "A fdefn object."
+ (label-value-line*
+ (:name (sb-kernel:fdefn-name o))
+ (:function (sb-kernel:fdefn-fun o)))))
+
+(defmethod inspect-for-emacs :around ((o generic-function)
+ (inspector backend-inspector))
+ (declare (ignore inspector))
+ (multiple-value-bind (title contents) (call-next-method)
+ (values title
+ (append
+ contents
+ (label-value-line*
+ (:pretty-arglist (sb-pcl::generic-function-pretty-arglist o))
+ (:initial-methods (sb-pcl::generic-function-initial-methods o))
+ )))))
+
+
+;;;; Multiprocessing
+
+#+(and sb-thread
+ #.(cl:if (cl:find-symbol "THREAD-NAME" "SB-THREAD") '(and) '(or)))
+(progn
+ (defvar *thread-id-counter* 0)
+
+ (defvar *thread-id-counter-lock*
+ (sb-thread:make-mutex :name "thread id counter lock"))
+
+ (defun next-thread-id ()
+ (sb-thread:with-mutex (*thread-id-counter-lock*)
+ (incf *thread-id-counter*)))
+
+ (defparameter *thread-id-map* (make-hash-table))
+
+ ;; This should be a thread -> id map but as weak keys are not
+ ;; supported it is id -> map instead.
+ (defvar *thread-id-map-lock*
+ (sb-thread:make-mutex :name "thread id map lock"))
+
+ (defimplementation spawn (fn &key name)
+ (sb-thread:make-thread fn :name name))
+
+ (defimplementation thread-id (thread)
+ (block thread-id
+ (sb-thread:with-mutex (*thread-id-map-lock*)
+ (loop for id being the hash-key in *thread-id-map*
+ using (hash-value thread-pointer)
+ do
+ (let ((maybe-thread (sb-ext:weak-pointer-value thread-pointer)))
+ (cond ((null maybe-thread)
+ ;; the value is gc'd, remove it manually
+ (remhash id *thread-id-map*))
+ ((eq thread maybe-thread)
+ (return-from thread-id id)))))
+ ;; lazy numbering
+ (let ((id (next-thread-id)))
+ (setf (gethash id *thread-id-map*) (sb-ext:make-weak-pointer thread))
+ id))))
+
+ (defimplementation find-thread (id)
+ (sb-thread:with-mutex (*thread-id-map-lock*)
+ (let ((thread-pointer (gethash id *thread-id-map*)))
+ (if thread-pointer
+ (let ((maybe-thread (sb-ext:weak-pointer-value thread-pointer)))
+ (if maybe-thread
+ maybe-thread
+ ;; the value is gc'd, remove it manually
+ (progn
+ (remhash id *thread-id-map*)
+ nil)))
+ nil))))
+
+ (defimplementation thread-name (thread)
+ ;; sometimes the name is not a string (e.g. NIL)
+ (princ-to-string (sb-thread:thread-name thread)))
+
+ (defimplementation thread-status (thread)
+ (if (sb-thread:thread-alive-p thread)
+ "RUNNING"
+ "STOPPED"))
+
+ (defimplementation make-lock (&key name)
+ (sb-thread:make-mutex :name name))
+
+ (defimplementation call-with-lock-held (lock function)
+ (declare (type function function))
+ (sb-thread:with-mutex (lock) (funcall function)))
+
+ (defimplementation make-recursive-lock (&key name)
+ (sb-thread:make-mutex :name name))
+
+ (defimplementation call-with-recursive-lock-held (lock function)
+ (declare (type function function))
+ (sb-thread:with-recursive-lock (lock) (funcall function)))
+
+ (defimplementation current-thread ()
+ sb-thread:*current-thread*)
+
+ (defimplementation all-threads ()
+ (sb-thread:list-all-threads))
+
+ (defimplementation interrupt-thread (thread fn)
+ (sb-thread:interrupt-thread thread fn))
+
+ (defimplementation kill-thread (thread)
+ (sb-thread:terminate-thread thread))
+
+ (defimplementation thread-alive-p (thread)
+ (sb-thread:thread-alive-p thread))
+
+ (defvar *mailbox-lock* (sb-thread:make-mutex :name "mailbox lock"))
+ (defvar *mailboxes* (list))
+ (declaim (type list *mailboxes*))
+
+ (defstruct (mailbox (:conc-name mailbox.))
+ thread
+ (mutex (sb-thread:make-mutex))
+ (waitqueue (sb-thread:make-waitqueue))
+ (queue '() :type list))
+
+ (defun mailbox (thread)
+ "Return THREAD's mailbox."
+ (sb-thread:with-mutex (*mailbox-lock*)
+ (or (find thread *mailboxes* :key #'mailbox.thread)
+ (let ((mb (make-mailbox :thread thread)))
+ (push mb *mailboxes*)
+ mb))))
+
+ (defimplementation send (thread message)
+ (let* ((mbox (mailbox thread))
+ (mutex (mailbox.mutex mbox)))
+ (sb-thread:with-mutex (mutex)
+ (setf (mailbox.queue mbox)
+ (nconc (mailbox.queue mbox) (list message)))
+ (sb-thread:condition-broadcast (mailbox.waitqueue mbox)))))
+
+ (defimplementation receive ()
+ (let* ((mbox (mailbox (current-thread)))
+ (mutex (mailbox.mutex mbox)))
+ (sb-thread:with-mutex (mutex)
+ (loop
+ (let ((q (mailbox.queue mbox)))
+ (cond (q (return (pop (mailbox.queue mbox))))
+ (t (sb-thread:condition-wait (mailbox.waitqueue mbox)
+ mutex))))))))
+
+
+ ;; Auto-flush streams
+
+ (defvar *auto-flush-interval* 0.15
+ "How often to flush interactive streams. This valu is passed
+ directly to cl:sleep.")
+
+ (defvar *auto-flush-lock* (make-recursive-lock :name "auto flush"))
+
+ (defvar *auto-flush-thread* nil)
+
+ (defvar *auto-flush-streams* '())
+
+ (defimplementation make-stream-interactive (stream)
+ (call-with-recursive-lock-held
+ *auto-flush-lock*
+ (lambda ()
+ (pushnew stream *auto-flush-streams*)
+ (unless *auto-flush-thread*
+ (setq *auto-flush-thread*
+ (sb-thread:make-thread #'flush-streams
+ :name "auto-flush-thread"))))))
+
+ (defun flush-streams ()
+ (loop
+ (call-with-recursive-lock-held
+ *auto-flush-lock*
+ (lambda ()
+ (setq *auto-flush-streams*
+ (remove-if (lambda (x)
+ (not (and (open-stream-p x)
+ (output-stream-p x))))
+ *auto-flush-streams*))
+ (mapc #'finish-output *auto-flush-streams*)))
+ (sleep *auto-flush-interval*)))
+
+ )
+
+(defimplementation quit-lisp ()
+ #+sb-thread
+ (dolist (thread (remove (current-thread) (all-threads)))
+ (ignore-errors (sb-thread:interrupt-thread
+ thread (lambda () (sb-ext:quit :recklessly-p t)))))
+ (sb-ext:quit))
+
+
+
+;;Trace implementations
+;;In SBCL, we have:
+;; (trace <name>)
+;; (trace :methods '<name>) ;to trace all methods of the gf <name>
+;; (trace (method <name> <qualifier>? (<specializer>+)))
+;; <name> can be a normal name or a (setf name)
+
+(defun toggle-trace-aux (fspec &rest args)
+ (cond ((member fspec (eval '(trace)) :test #'equal)
+ (eval `(untrace ,fspec))
+ (format nil "~S is now untraced." fspec))
+ (t
+ (eval `(trace ,@(if args `(:encapsulate nil) (list)) ,fspec , at args))
+ (format nil "~S is now traced." fspec))))
+
+(defun process-fspec (fspec)
+ (cond ((consp fspec)
+ (ecase (first fspec)
+ ((:defun :defgeneric) (second fspec))
+ ((:defmethod) `(method ,@(rest fspec)))
+ ((:labels) `(labels ,(process-fspec (second fspec)) ,(third fspec)))
+ ((:flet) `(flet ,(process-fspec (second fspec)) ,(third fspec)))))
+ (t
+ fspec)))
+
+(defimplementation toggle-trace (spec)
+ (ecase (car spec)
+ ((setf)
+ (toggle-trace-aux spec))
+ ((:defmethod)
+ (toggle-trace-aux `(sb-pcl::fast-method ,@(rest (process-fspec spec)))))
+ ((:defgeneric)
+ (toggle-trace-aux (second spec) :methods t))
+ ((:call)
+ (destructuring-bind (caller callee) (cdr spec)
+ (toggle-trace-aux callee :wherein (list (process-fspec caller)))))))
+
+;;; Weak datastructures
+
+(defimplementation make-weak-key-hash-table (&rest args)
+ #+#.(swank-backend::sbcl-with-weak-hash-tables)
+ (apply #'make-hash-table :weakness :key args)
+ #-#.(swank-backend::sbcl-with-weak-hash-tables)
+ (apply #'make-hash-table args))
+
+(defimplementation make-weak-value-hash-table (&rest args)
+ #+#.(swank-backend::sbcl-with-weak-hash-tables)
+ (apply #'make-hash-table :weakness :value args)
+ #-#.(swank-backend::sbcl-with-weak-hash-tables)
+ (apply #'make-hash-table args))
+
+(defimplementation hash-table-weakness (hashtable)
+ #+#.(swank-backend::sbcl-with-weak-hash-tables)
+ (sb-ext:hash-table-weakness hashtable))
Added: branches/bos/thirdparty/emacs/slime/swank-scl.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-scl.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,2072 @@
+;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;+" -*-
+;;;
+;;; Scieneer Common Lisp code for SLIME.
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+
+(in-package :swank-backend)
+
+
+
+;;; swank-mop
+
+(import-swank-mop-symbols :clos '(:slot-definition-documentation))
+
+(defun swank-mop:slot-definition-documentation (slot)
+ (documentation slot t))
+
+
+;;;; TCP server
+;;;
+;;; SCL only supports the :spawn communication style.
+;;;
+
+(defimplementation preferred-communication-style ()
+ :spawn)
+
+(defimplementation create-socket (host port)
+ (let ((addr (resolve-hostname host)))
+ (ext:create-inet-listener port :stream :host addr :reuse-address t)))
+
+(defimplementation local-port (socket)
+ (nth-value 1 (ext::get-socket-host-and-port (socket-fd socket))))
+
+(defimplementation close-socket (socket)
+ (ext:close-socket (socket-fd socket)))
+
+(defimplementation accept-connection (socket
+ &key external-format buffering timeout)
+ (let ((external-format (or external-format :default))
+ (buffering (or buffering :full))
+ (fd (socket-fd socket)))
+ (loop
+ (let ((ready (sys:wait-until-fd-usable fd :input timeout)))
+ (unless ready
+ (error "Timeout accepting connection on socket: ~S~%" socket)))
+ (let ((new-fd (ignore-errors (ext:accept-tcp-connection fd))))
+ (when new-fd
+ (return (make-socket-io-stream new-fd external-format buffering)))))))
+
+(defimplementation set-stream-timeout (stream timeout)
+ (check-type timeout (or null real))
+ (if (fboundp 'ext::stream-timeout)
+ (setf (ext::stream-timeout stream) timeout)
+ (setf (slot-value (slot-value stream 'lisp::stream) 'lisp::timeout)
+ timeout)))
+
+;;;;; Sockets
+
+(defun socket-fd (socket)
+ "Return the file descriptor for the socket represented by 'socket."
+ (etypecase socket
+ (fixnum socket)
+ (stream (sys:fd-stream-fd socket))))
+
+(defun resolve-hostname (hostname)
+ "Return the IP address of 'hostname as an integer (in host byte-order)."
+ (let ((hostent (ext:lookup-host-entry hostname)))
+ (car (ext:host-entry-addr-list hostent))))
+
+(defvar *external-format-to-coding-system*
+ '((:iso-8859-1
+ "latin-1" "latin-1-unix" "iso-latin-1-unix"
+ "iso-8859-1" "iso-8859-1-unix")
+ (:utf-8 "utf-8" "utf-8-unix")
+ (:euc-jp "euc-jp" "euc-jp-unix")))
+
+(defimplementation find-external-format (coding-system)
+ (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
+ *external-format-to-coding-system*)))
+
+(defun make-socket-io-stream (fd external-format buffering)
+ "Create a new input/output fd-stream for 'fd."
+ (let* ((stream (sys:make-fd-stream fd :input t :output t
+ :element-type 'base-char
+ :buffering buffering
+ :external-format external-format)))
+ ;; Ignore character conversion errors. Without this the communication
+ ;; channel is prone to lockup if a character conversion error occurs.
+ (setf (lisp::character-conversion-stream-input-error-value stream) #\?)
+ (setf (lisp::character-conversion-stream-output-error-value stream) #\?)
+ stream))
+
+
+;;;; Stream handling
+
+(defclass slime-input-stream (ext:character-input-stream)
+ ((buffer :initarg :buffer :type string)
+ (index :initarg :index :initform 0 :type fixnum)
+ (position :initarg :position :initform 0 :type integer)
+ (interactive :initarg :interactive :initform nil :type (member nil t))
+ (output-stream :initarg :output-stream :initform nil)
+ (input-fn :initarg :input-fn :type function)
+ ))
+
+(defun make-slime-input-stream (input-fn &optional output-stream)
+ (declare (function input-fn))
+ (make-instance 'slime-input-stream
+ :in-buffer (make-string 256)
+ :in-head 0 :in-tail 0
+ :out-buffer ""
+ :buffer "" :index 0
+ :input-fn input-fn
+ :output-stream output-stream))
+
+(defmethod print-object ((s slime-input-stream) stream)
+ (print-unreadable-object (s stream :type t)))
+
+;;; input-stream-p inherits from input-stream.
+;;; output-stream-p inherits nil.
+
+(defmethod ext:stream-listen ((stream slime-input-stream))
+ (let* ((buffer (slot-value stream 'buffer))
+ (index (slot-value stream 'index))
+ (length (length buffer)))
+ (declare (type string buffer)
+ (fixnum index length))
+ (< index length)))
+
+(defmethod close ((stream slime-input-stream) &key ((:abort abort) nil))
+ (declare (ignore abort))
+ (when (ext:stream-open-p stream)
+ (setf (ext:stream-open-p stream) nil)
+ (setf (ext:stream-in-buffer stream) " ")
+ t))
+
+(defmethod ext:stream-clear-input ((stream slime-input-stream))
+ (let* ((input-buffer (slot-value stream 'buffer))
+ (index (slot-value stream 'index))
+ (input-length (length input-buffer))
+ (available (- input-length index))
+ (position (slot-value stream 'position))
+ (new-position (+ position available)))
+ (declare (type kernel:index index available position new-position))
+ (setf (slot-value stream 'position) new-position))
+ (setf (slot-value stream 'buffer) "")
+ (setf (slot-value stream 'index) 0)
+ nil)
+
+;;; No 'stream-finish-output method.
+;;; No 'stream-force-output method.
+;;; No 'stream-clear-output method.
+
+;;; stream-element-type inherits from character-stream.
+
+;;; No 'stream-line-length method.
+;;; No 'stream-line-column method.
+
+;;; Add the remaining input to the current position.
+(defmethod file-length ((stream slime-input-stream))
+ (let* ((input-buffer (slot-value stream 'buffer))
+ (index (slot-value stream 'index))
+ (input-length (length input-buffer))
+ (available (- input-length index))
+ (position (slot-value stream 'position))
+ (file-length (+ position available)))
+ (declare (type kernel:index index available position file-length))
+ file-length))
+
+(defmethod ext:stream-file-position ((stream slime-input-stream)
+ &optional position)
+ (let ((current-position (slot-value stream 'position)))
+ (declare (type kernel:index current-position))
+ (cond (position
+ ;; Could make an attempt here, but just give up for now.
+ nil)
+ (t
+ current-position))))
+
+(defmethod interactive-stream-p ((stream slime-input-stream))
+ (slot-value stream 'interactive))
+
+;;; No 'file-string-length method.
+
+(defmethod ext:stream-read-chars ((stream slime-input-stream) buffer
+ start requested waitp)
+ (declare (type simple-string buffer)
+ (type kernel:index start requested))
+ (let* ((input-buffer (slot-value stream 'buffer))
+ (index (slot-value stream 'index))
+ (input-length (length input-buffer))
+ (available (- input-length index))
+ (copy (min available requested)))
+ (declare (string input-buffer)
+ (type kernel:index index available copy))
+ (cond ((plusp copy)
+ (dotimes (i copy)
+ (declare (type kernel:index i))
+ (setf (aref buffer (+ start i)) (aref input-buffer (+ index i))))
+ (setf (slot-value stream 'index) (+ index copy))
+ (incf (slot-value stream 'position) copy)
+ copy)
+ (waitp
+ (let ((output-stream (slot-value stream 'output-stream))
+ (input-fn (slot-value stream 'input-fn)))
+ (declare (type function input-fn))
+ (when output-stream
+ (force-output output-stream))
+ (let ((new-input (funcall input-fn)))
+ (cond ((zerop (length new-input))
+ -1)
+ (t
+ (setf (slot-value stream 'buffer) new-input)
+ (setf (slot-value stream 'index) 0)
+ (ext:stream-read-chars stream buffer
+ start requested waitp))))))
+ (t
+ 0))))
+
+;;; Slime output stream.
+
+(defclass slime-output-stream (ext:character-output-stream)
+ ((output-fn :initarg :output-fn :type function)
+ (column :initform 0 :type kernel:index)
+ (interactive :initform nil :type (member nil t))
+ (position :initform 0 :type integer)))
+
+(defun make-slime-output-stream (output-fn)
+ (declare (function output-fn))
+ (make-instance 'slime-output-stream
+ :in-buffer ""
+ :out-buffer (make-string 256)
+ :output-fn output-fn))
+
+(defmethod print-object ((s slime-output-stream) stream)
+ (print-unreadable-object (s stream :type t)))
+
+;;; Use default 'input-stream-p method for 'output-stream which returns 'nil.
+;;; Use default 'output-stream-p method for 'output-stream which returns 't.
+
+;;; No 'stream-listen method.
+
+(defmethod close ((stream slime-output-stream) &key ((:abort abort) nil))
+ (when (ext:stream-open-p stream)
+ (unless abort
+ (finish-output stream))
+ (setf (ext:stream-open-p stream) nil)
+ (setf (ext:stream-out-buffer stream) " ")
+ t))
+
+;;; No 'stream-clear-input method.
+
+(defmethod ext:stream-finish-output ((stream slime-output-stream))
+ nil)
+
+(defmethod ext:stream-force-output ((stream slime-output-stream))
+ nil)
+
+(defmethod ext:stream-clear-output ((stream slime-output-stream))
+ nil)
+
+;;; Use default 'stream-element-type method for 'character-stream which
+;;; returns 'base-char.
+
+(defmethod ext:stream-line-length ((stream slime-output-stream))
+ 80)
+
+(defmethod ext:stream-line-column ((stream slime-output-stream))
+ (slot-value stream 'column))
+
+(defmethod file-length ((stream slime-output-stream))
+ (slot-value stream 'position))
+
+(defmethod ext:stream-file-position ((stream slime-output-stream)
+ &optional position)
+ (declare (optimize (speed 3)))
+ (cond (position
+ (let* ((current-position (slot-value stream 'position))
+ (target-position (etypecase position
+ ((member :start) 0)
+ ((member :end) current-position)
+ (kernel:index position))))
+ (declare (type kernel:index current-position target-position))
+ (cond ((= target-position current-position)
+ t)
+ ((> target-position current-position)
+ (let ((output-fn (slot-value stream 'output-fn))
+ (fill-size (- target-position current-position)))
+ (declare (function output-fn))
+ (funcall output-fn (make-string fill-size
+ :initial-element #\space))
+ (setf (slot-value stream 'position) target-position))
+ t)
+ (t
+ nil))))
+ (t
+ (slot-value stream 'position))))
+
+(defmethod interactive-stream-p ((stream slime-output-stream))
+ (slot-value stream 'interactive))
+
+;;; Use the default 'character-output-stream 'file-string-length method.
+
+;;; stream-write-chars
+;;;
+;;; The stream out-buffer is typically large enough that there is little point
+;;; growing the stream output 'string large than the total size. For typical
+;;; usage this reduces consing. As the string grows larger then grow to
+;;; reduce the cost of copying strings around.
+;;;
+(defmethod ext:stream-write-chars ((stream slime-output-stream)
+ string start end waitp)
+ (declare (simple-string string)
+ (type kernel:index start end)
+ (ignore waitp))
+ (declare (optimize (speed 3)))
+ (unless (ext:stream-open-p stream)
+ (error 'kernel:simple-stream-error
+ :stream stream
+ :format-control "Stream closed."))
+ (let* ((string-length (length string))
+ (start (cond ((< start 0) 0)
+ ((> start string-length) string-length)
+ (t start)))
+ (end (cond ((< end start) start)
+ ((> end string-length) string-length)
+ (t end)))
+ (length (- end start))
+ (output-fn (slot-value stream 'output-fn)))
+ (declare (type kernel:index start end length)
+ (type function output-fn))
+ (unless (zerop length)
+ (funcall output-fn (subseq string start end))
+ (let ((last-newline (position #\newline string :from-end t
+ :start start :end end)))
+ (setf (slot-value stream 'column)
+ (if last-newline
+ (- end last-newline 1)
+ (let ((column (slot-value stream 'column)))
+ (declare (type kernel:index column))
+ (+ column (- end start))))))))
+ (- end start))
+
+;;;
+
+(defimplementation make-fn-streams (input-fn output-fn)
+ (let* ((output (make-slime-output-stream output-fn))
+ (input (make-slime-input-stream input-fn output)))
+ (values input output)))
+
+(defimplementation make-stream-interactive (stream)
+ (when (or (typep stream 'slime-input-stream)
+ (typep stream 'slime-output-stream))
+ (setf (slot-value stream 'interactive) t)))
+
+
+;;;; Compilation Commands
+
+(defvar *previous-compiler-condition* nil
+ "Used to detect duplicates.")
+
+(defvar *previous-context* nil
+ "Previous compiler error context.")
+
+(defvar *buffer-name* nil
+ "The name of the Emacs buffer we are compiling from.
+ Nil if we aren't compiling from a buffer.")
+
+(defvar *buffer-start-position* nil)
+(defvar *buffer-substring* nil)
+
+(defimplementation call-with-compilation-hooks (function)
+ (let ((*previous-compiler-condition* nil)
+ (*previous-context* nil)
+ (*print-readably* nil))
+ (handler-bind ((c::compiler-error #'handle-notification-condition)
+ (c::style-warning #'handle-notification-condition)
+ (c::warning #'handle-notification-condition))
+ (funcall function))))
+
+(defimplementation swank-compile-file (filename load-p external-format)
+ (with-compilation-hooks ()
+ (let ((*buffer-name* nil)
+ (ext:*ignore-extra-close-parentheses* nil))
+ (multiple-value-bind (output-file warnings-p failure-p)
+ (compile-file filename :external-format external-format)
+ (unless failure-p
+ ;; Cache the latest source file for definition-finding.
+ (source-cache-get filename (file-write-date filename))
+ (when load-p (load output-file)))
+ (values output-file warnings-p failure-p)))))
+
+(defimplementation swank-compile-string (string &key buffer position directory)
+ (declare (ignore directory))
+ (with-compilation-hooks ()
+ (let ((*buffer-name* buffer)
+ (*buffer-start-position* position)
+ (*buffer-substring* string))
+ (with-input-from-string (stream string)
+ (ext:compile-from-stream
+ stream
+ :source-info `(:emacs-buffer ,buffer
+ :emacs-buffer-offset ,position
+ :emacs-buffer-string ,string))))))
+
+
+;;;;; Trapping notes
+;;;
+;;; We intercept conditions from the compiler and resignal them as
+;;; `swank:compiler-condition's.
+
+(defun handle-notification-condition (condition)
+ "Handle a condition caused by a compiler warning."
+ (unless (eq condition *previous-compiler-condition*)
+ (let ((context (c::find-error-context nil)))
+ (setq *previous-compiler-condition* condition)
+ (setq *previous-context* context)
+ (signal-compiler-condition condition context))))
+
+(defun signal-compiler-condition (condition context)
+ (signal (make-condition
+ 'compiler-condition
+ :original-condition condition
+ :severity (severity-for-emacs condition)
+ :short-message (brief-compiler-message-for-emacs condition)
+ :message (long-compiler-message-for-emacs condition context)
+ :location (if (read-error-p condition)
+ (read-error-location condition)
+ (compiler-note-location context)))))
+
+(defun severity-for-emacs (condition)
+ "Return the severity of 'condition."
+ (etypecase condition
+ ((satisfies read-error-p) :read-error)
+ (c::compiler-error :error)
+ (c::style-warning :note)
+ (c::warning :warning)))
+
+(defun read-error-p (condition)
+ (eq (type-of condition) 'c::compiler-read-error))
+
+(defun brief-compiler-message-for-emacs (condition)
+ "Briefly describe a compiler error for Emacs.
+ When Emacs presents the message it already has the source popped up
+ and the source form highlighted. This makes much of the information in
+ the error-context redundant."
+ (princ-to-string condition))
+
+(defun long-compiler-message-for-emacs (condition error-context)
+ "Describe a compiler error for Emacs including context information."
+ (declare (type (or c::compiler-error-context null) error-context))
+ (multiple-value-bind (enclosing source)
+ (if error-context
+ (values (c::compiler-error-context-enclosing-source error-context)
+ (c::compiler-error-context-source error-context)))
+ (format nil "~@[--> ~{~<~%--> ~1:;~A~> ~}~%~]~@[~{==>~%~A~^~%~}~]~A"
+ enclosing source condition)))
+
+(defun read-error-location (condition)
+ (let* ((finfo (car (c::source-info-current-file c::*source-info*)))
+ (file (c::file-info-name finfo))
+ (pos (c::compiler-read-error-position condition)))
+ (cond ((and (eq file :stream) *buffer-name*)
+ (make-location (list :buffer *buffer-name*)
+ (list :position (+ *buffer-start-position* pos))))
+ ((and (pathnamep file) (not *buffer-name*))
+ (make-location (list :file (unix-truename file))
+ (list :position (1+ pos))))
+ (t (break)))))
+
+(defun compiler-note-location (context)
+ "Derive the location of a complier message from its context.
+ Return a `location' record, or (:error <reason>) on failure."
+ (if (null context)
+ (note-error-location)
+ (let ((file (c::compiler-error-context-file-name context))
+ (source (c::compiler-error-context-original-source context))
+ (path
+ (reverse (c::compiler-error-context-original-source-path context))))
+ (or (locate-compiler-note file source path)
+ (note-error-location)))))
+
+(defun note-error-location ()
+ "Pseudo-location for notes that can't be located."
+ (list :error "No error location available."))
+
+(defun locate-compiler-note (file source source-path)
+ (cond ((and (eq file :stream) *buffer-name*)
+ ;; Compiling from a buffer
+ (let ((position (+ *buffer-start-position*
+ (source-path-string-position
+ source-path *buffer-substring*))))
+ (make-location (list :buffer *buffer-name*)
+ (list :position position))))
+ ((and (pathnamep file) (null *buffer-name*))
+ ;; Compiling from a file
+ (make-location (list :file (unix-truename file))
+ (list :position
+ (1+ (source-path-file-position
+ source-path file)))))
+ ((and (eq file :lisp) (stringp source))
+ ;; No location known, but we have the source form.
+ ;; XXX How is this case triggered? -luke (16/May/2004)
+ ;; This can happen if the compiler needs to expand a macro
+ ;; but the macro-expander is not yet compiled. Calling the
+ ;; (interpreted) macro-expander triggers IR1 conversion of
+ ;; the lambda expression for the expander and invokes the
+ ;; compiler recursively.
+ (make-location (list :source-form source)
+ (list :position 1)))))
+
+(defun unix-truename (pathname)
+ (ext:unix-namestring (truename pathname)))
+
+
+
+;;; TODO
+(defimplementation who-calls (name) nil)
+(defimplementation who-references (name) nil)
+(defimplementation who-binds (name) nil)
+(defimplementation who-sets (name) nil)
+(defimplementation who-specializes (symbol) nil)
+(defimplementation who-macroexpands (name) nil)
+
+
+;;;; Find callers and callees
+;;;
+;;; Find callers and callees by looking at the constant pool of
+;;; compiled code objects. We assume every fdefn object in the
+;;; constant pool corresponds to a call to that function. A better
+;;; strategy would be to use the disassembler to find actual
+;;; call-sites.
+
+(declaim (inline map-code-constants))
+(defun map-code-constants (code fn)
+ "Call 'fn for each constant in 'code's constant pool."
+ (check-type code kernel:code-component)
+ (loop for i from vm:code-constants-offset below (kernel:get-header-data code)
+ do (funcall fn (kernel:code-header-ref code i))))
+
+(defun function-callees (function)
+ "Return 'function's callees as a list of functions."
+ (let ((callees '()))
+ (map-code-constants
+ (vm::find-code-object function)
+ (lambda (obj)
+ (when (kernel:fdefn-p obj)
+ (push (kernel:fdefn-function obj) callees))))
+ callees))
+
+(declaim (ext:maybe-inline map-allocated-code-components))
+(defun map-allocated-code-components (spaces fn)
+ "Call FN for each allocated code component in one of 'spaces. FN
+ receives the object as argument. 'spaces should be a list of the
+ symbols :dynamic, :static, or :read-only."
+ (dolist (space spaces)
+ (declare (inline vm::map-allocated-objects)
+ (optimize (ext:inhibit-warnings 3)))
+ (vm::map-allocated-objects
+ (lambda (obj header size)
+ (declare (type fixnum size) (ignore size))
+ (when (= vm:code-header-type header)
+ (funcall fn obj)))
+ space)))
+
+(declaim (ext:maybe-inline map-caller-code-components))
+(defun map-caller-code-components (function spaces fn)
+ "Call 'fn for each code component with a fdefn for 'function in its
+ constant pool."
+ (let ((function (coerce function 'function)))
+ (declare (inline map-allocated-code-components))
+ (map-allocated-code-components
+ spaces
+ (lambda (obj)
+ (map-code-constants
+ obj
+ (lambda (constant)
+ (when (and (kernel:fdefn-p constant)
+ (eq (kernel:fdefn-function constant)
+ function))
+ (funcall fn obj))))))))
+
+(defun function-callers (function &optional (spaces '(:read-only :static
+ :dynamic)))
+ "Return 'function's callers. The result is a list of code-objects."
+ (let ((referrers '()))
+ (declare (inline map-caller-code-components))
+ (map-caller-code-components function spaces
+ (lambda (code) (push code referrers)))
+ referrers))
+
+(defun debug-info-definitions (debug-info)
+ "Return the defintions for a debug-info. This should only be used
+ for code-object without entry points, i.e., byte compiled
+ code (are theree others?)"
+ ;; This mess has only been tested with #'ext::skip-whitespace, a
+ ;; byte-compiled caller of #'read-char .
+ (check-type debug-info (and (not c::compiled-debug-info) c::debug-info))
+ (let ((name (c::debug-info-name debug-info))
+ (source (c::debug-info-source debug-info)))
+ (destructuring-bind (first) source
+ (ecase (c::debug-source-from first)
+ (:file
+ (list (list name
+ (make-location
+ (list :file (unix-truename (c::debug-source-name first)))
+ (list :function-name (string name))))))))))
+
+(defun valid-function-name-p (name)
+ (or (symbolp name) (and (consp name)
+ (eq (car name) 'setf)
+ (symbolp (cadr name))
+ (not (cddr name)))))
+
+(defun code-component-entry-points (code)
+ "Return a list ((name location) ...) of function definitons for
+ the code omponent 'code."
+ (let ((names '()))
+ (do ((f (kernel:%code-entry-points code) (kernel::%function-next f)))
+ ((not f))
+ (let ((name (kernel:%function-name f)))
+ (when (valid-function-name-p name)
+ (push (list name (function-location f)) names))))
+ names))
+
+(defimplementation list-callers (symbol)
+ "Return a list ((name location) ...) of callers."
+ (let ((components (function-callers symbol))
+ (xrefs '()))
+ (dolist (code components)
+ (let* ((entry (kernel:%code-entry-points code))
+ (defs (if entry
+ (code-component-entry-points code)
+ ;; byte compiled stuff
+ (debug-info-definitions
+ (kernel:%code-debug-info code)))))
+ (setq xrefs (nconc defs xrefs))))
+ xrefs))
+
+(defimplementation list-callees (symbol)
+ (let ((fns (function-callees symbol)))
+ (mapcar (lambda (fn)
+ (list (kernel:%function-name fn)
+ (function-location fn)))
+ fns)))
+
+
+;;;; Resolving source locations
+;;;
+;;; Our mission here is to "resolve" references to code locations into
+;;; actual file/buffer names and character positions. The references
+;;; we work from come out of the compiler's statically-generated debug
+;;; information, such as `code-location''s and `debug-source''s. For
+;;; more details, see the "Debugger Programmer's Interface" section of
+;;; the SCL manual.
+;;;
+;;; The first step is usually to find the corresponding "source-path"
+;;; for the location. Once we have the source-path we can pull up the
+;;; source file and `READ' our way through to the right position. The
+;;; main source-code groveling work is done in
+;;; `swank-source-path-parser.lisp'.
+
+(defvar *debug-definition-finding* nil
+ "When true don't handle errors while looking for definitions.
+ This is useful when debugging the definition-finding code.")
+
+(defvar *source-snippet-size* 256
+ "Maximum number of characters in a snippet of source code.
+ Snippets at the beginning of definitions are used to tell Emacs what
+ the definitions looks like, so that it can accurately find them by
+ text search.")
+
+(defmacro safe-definition-finding (&body body)
+ "Execute 'body and return the source-location it returns.
+ If an error occurs and `*debug-definition-finding*' is false, then
+ return an error pseudo-location.
+
+ The second return value is 'nil if no error occurs, otherwise it is the
+ condition object."
+ `(flet ((body () , at body))
+ (if *debug-definition-finding*
+ (body)
+ (handler-case (values (progn , at body) nil)
+ (error (c) (values (list :error (princ-to-string c)) c))))))
+
+(defun code-location-source-location (code-location)
+ "Safe wrapper around `code-location-from-source-location'."
+ (safe-definition-finding
+ (source-location-from-code-location code-location)))
+
+(defun source-location-from-code-location (code-location)
+ "Return the source location for 'code-location."
+ (let ((debug-fun (di:code-location-debug-function code-location)))
+ (when (di::bogus-debug-function-p debug-fun)
+ ;; Those lousy cheapskates! They've put in a bogus debug source
+ ;; because the code was compiled at a low debug setting.
+ (error "Bogus debug function: ~A" debug-fun)))
+ (let* ((debug-source (di:code-location-debug-source code-location))
+ (from (di:debug-source-from debug-source))
+ (name (di:debug-source-name debug-source)))
+ (ecase from
+ (:file
+ (location-in-file name code-location debug-source))
+ (:stream
+ (location-in-stream code-location debug-source))
+ (:lisp
+ ;; The location comes from a form passed to `compile'.
+ ;; The best we can do is return the form itself for printing.
+ (make-location
+ (list :source-form (with-output-to-string (*standard-output*)
+ (debug::print-code-location-source-form
+ code-location 100 t)))
+ (list :position 1))))))
+
+(defun location-in-file (filename code-location debug-source)
+ "Resolve the source location for 'code-location in 'filename."
+ (let* ((code-date (di:debug-source-created debug-source))
+ (source-code (get-source-code filename code-date)))
+ (with-input-from-string (s source-code)
+ (make-location (list :file (unix-truename filename))
+ (list :position (1+ (code-location-stream-position
+ code-location s)))
+ `(:snippet ,(read-snippet s))))))
+
+(defun location-in-stream (code-location debug-source)
+ "Resolve the source location for a 'code-location from a stream.
+ This only succeeds if the code was compiled from an Emacs buffer."
+ (unless (debug-source-info-from-emacs-buffer-p debug-source)
+ (error "The code is compiled from a non-SLIME stream."))
+ (let* ((info (c::debug-source-info debug-source))
+ (string (getf info :emacs-buffer-string))
+ (position (code-location-string-offset
+ code-location
+ string)))
+ (make-location
+ (list :buffer (getf info :emacs-buffer))
+ (list :position (+ (getf info :emacs-buffer-offset) position))
+ (list :snippet (with-input-from-string (s string)
+ (file-position s position)
+ (read-snippet s))))))
+
+;;;;; Function-name locations
+;;;
+(defun debug-info-function-name-location (debug-info)
+ "Return a function-name source-location for 'debug-info.
+ Function-name source-locations are a fallback for when precise
+ positions aren't available."
+ (with-struct (c::debug-info- (fname name) source) debug-info
+ (with-struct (c::debug-source- info from name) (car source)
+ (ecase from
+ (:file
+ (make-location (list :file (namestring (truename name)))
+ (list :function-name (string fname))))
+ (:stream
+ (assert (debug-source-info-from-emacs-buffer-p (car source)))
+ (make-location (list :buffer (getf info :emacs-buffer))
+ (list :function-name (string fname))))
+ (:lisp
+ (make-location (list :source-form (princ-to-string (aref name 0)))
+ (list :position 1)))))))
+
+(defun debug-source-info-from-emacs-buffer-p (debug-source)
+ "Does the `info' slot of 'debug-source contain an Emacs buffer location?
+ This is true for functions that were compiled directly from buffers."
+ (info-from-emacs-buffer-p (c::debug-source-info debug-source)))
+
+(defun info-from-emacs-buffer-p (info)
+ (and info
+ (consp info)
+ (eq :emacs-buffer (car info))))
+
+
+;;;;; Groveling source-code for positions
+
+(defun code-location-stream-position (code-location stream)
+ "Return the byte offset of 'code-location in 'stream. Extract the
+ toplevel-form-number and form-number from 'code-location and use that
+ to find the position of the corresponding form.
+
+ Finish with 'stream positioned at the start of the code location."
+ (let* ((location (debug::maybe-block-start-location code-location))
+ (tlf-offset (di:code-location-top-level-form-offset location))
+ (form-number (di:code-location-form-number location)))
+ (let ((pos (form-number-stream-position tlf-offset form-number stream)))
+ (file-position stream pos)
+ pos)))
+
+(defun form-number-stream-position (tlf-number form-number stream)
+ "Return the starting character position of a form in 'stream.
+ 'tlf-number is the top-level-form number.
+ 'form-number is an index into a source-path table for the TLF."
+ (multiple-value-bind (tlf position-map) (read-source-form tlf-number stream)
+ (let* ((path-table (di:form-number-translations tlf 0))
+ (source-path
+ (if (<= (length path-table) form-number) ; source out of sync?
+ (list 0) ; should probably signal a condition
+ (reverse (cdr (aref path-table form-number))))))
+ (source-path-source-position source-path tlf position-map))))
+
+(defun code-location-string-offset (code-location string)
+ "Return the byte offset of 'code-location in 'string.
+ See 'code-location-stream-position."
+ (with-input-from-string (s string)
+ (code-location-stream-position code-location s)))
+
+
+;;;; Finding definitions
+
+;;; There are a great many different types of definition for us to
+;;; find. We search for definitions of every kind and return them in a
+;;; list.
+
+(defimplementation find-definitions (name)
+ (append (function-definitions name)
+ (setf-definitions name)
+ (variable-definitions name)
+ (class-definitions name)
+ (type-definitions name)
+ (compiler-macro-definitions name)
+ (source-transform-definitions name)
+ (function-info-definitions name)
+ (ir1-translator-definitions name)))
+
+;;;;; Functions, macros, generic functions, methods
+;;;
+;;; We make extensive use of the compile-time debug information that
+;;; SCL records, in particular "debug functions" and "code
+;;; locations." Refer to the "Debugger Programmer's Interface" section
+;;; of the SCL manual for more details.
+
+(defun function-definitions (name)
+ "Return definitions for 'name in the \"function namespace\", i.e.,
+ regular functions, generic functions, methods and macros.
+ 'name can any valid function name (e.g, (setf car))."
+ (let ((macro? (and (symbolp name) (macro-function name)))
+ (special? (and (symbolp name) (special-operator-p name)))
+ (function? (and (valid-function-name-p name)
+ (ext:info :function :definition name)
+ (if (symbolp name) (fboundp name) t))))
+ (cond (macro?
+ (list `((defmacro ,name)
+ ,(function-location (macro-function name)))))
+ (special?
+ (list `((:special-operator ,name)
+ (:error ,(format nil "Special operator: ~S" name)))))
+ (function?
+ (let ((function (fdefinition name)))
+ (if (genericp function)
+ (generic-function-definitions name function)
+ (list (list `(function ,name)
+ (function-location function)))))))))
+
+;;;;;; Ordinary (non-generic/macro/special) functions
+;;;
+;;; First we test if FUNCTION is a closure created by defstruct, and
+;;; if so extract the defstruct-description (`dd') from the closure
+;;; and find the constructor for the struct. Defstruct creates a
+;;; defun for the default constructor and we use that as an
+;;; approximation to the source location of the defstruct.
+;;;
+;;; For an ordinary function we return the source location of the
+;;; first code-location we find.
+;;;
+(defun function-location (function)
+ "Return the source location for FUNCTION."
+ (cond ((struct-closure-p function)
+ (struct-closure-location function))
+ ((c::byte-function-or-closure-p function)
+ (byte-function-location function))
+ (t
+ (compiled-function-location function))))
+
+(defun compiled-function-location (function)
+ "Return the location of a regular compiled function."
+ (multiple-value-bind (code-location error)
+ (safe-definition-finding (function-first-code-location function))
+ (cond (error (list :error (princ-to-string error)))
+ (t (code-location-source-location code-location)))))
+
+(defun function-first-code-location (function)
+ "Return the first code-location we can find for 'function."
+ (and (function-has-debug-function-p function)
+ (di:debug-function-start-location
+ (di:function-debug-function function))))
+
+(defun function-has-debug-function-p (function)
+ (di:function-debug-function function))
+
+(defun function-code-object= (closure function)
+ (and (eq (vm::find-code-object closure)
+ (vm::find-code-object function))
+ (not (eq closure function))))
+
+
+(defun byte-function-location (fn)
+ "Return the location of the byte-compiled function 'fn."
+ (etypecase fn
+ ((or c::hairy-byte-function c::simple-byte-function)
+ (let* ((component (c::byte-function-component fn))
+ (debug-info (kernel:%code-debug-info component)))
+ (debug-info-function-name-location debug-info)))
+ (c::byte-closure
+ (byte-function-location (c::byte-closure-function fn)))))
+
+;;; Here we deal with structure accessors. Note that `dd' is a
+;;; "defstruct descriptor" structure in SCL. A `dd' describes a
+;;; `defstruct''d structure.
+
+(defun struct-closure-p (function)
+ "Is 'function a closure created by defstruct?"
+ (or (function-code-object= function #'kernel::structure-slot-accessor)
+ (function-code-object= function #'kernel::structure-slot-setter)
+ (function-code-object= function #'kernel::%defstruct)))
+
+(defun struct-closure-location (function)
+ "Return the location of the structure that 'function belongs to."
+ (assert (struct-closure-p function))
+ (safe-definition-finding
+ (dd-location (struct-closure-dd function))))
+
+(defun struct-closure-dd (function)
+ "Return the defstruct-definition (dd) of FUNCTION."
+ (assert (= (kernel:get-type function) vm:closure-header-type))
+ (flet ((find-layout (function)
+ (sys:find-if-in-closure
+ (lambda (x)
+ (let ((value (if (di::indirect-value-cell-p x)
+ (c:value-cell-ref x)
+ x)))
+ (when (kernel::layout-p value)
+ (return-from find-layout value))))
+ function)))
+ (kernel:layout-info (find-layout function))))
+
+(defun dd-location (dd)
+ "Return the location of a `defstruct'."
+ ;; Find the location in a constructor.
+ (function-location (struct-constructor dd)))
+
+(defun struct-constructor (dd)
+ "Return a constructor function from a defstruct definition.
+Signal an error if no constructor can be found."
+ (let ((constructor (or (kernel:dd-default-constructor dd)
+ (car (kernel::dd-constructors dd)))))
+ (when (or (null constructor)
+ (and (consp constructor) (null (car constructor))))
+ (error "Cannot find structure's constructor: ~S"
+ (kernel::dd-name dd)))
+ (coerce (if (consp constructor) (first constructor) constructor)
+ 'function)))
+
+;;;;;; Generic functions and methods
+
+(defun generic-function-definitions (name function)
+ "Return the definitions of a generic function and its methods."
+ (cons (list `(defgeneric ,name) (gf-location function))
+ (gf-method-definitions function)))
+
+(defun gf-location (gf)
+ "Return the location of the generic function GF."
+ (definition-source-location gf (clos:generic-function-name gf)))
+
+(defun gf-method-definitions (gf)
+ "Return the locations of all methods of the generic function GF."
+ (mapcar #'method-definition (clos:generic-function-methods gf)))
+
+(defun method-definition (method)
+ (list (method-dspec method)
+ (method-location method)))
+
+(defun method-dspec (method)
+ "Return a human-readable \"definition specifier\" for METHOD."
+ (let* ((gf (clos:method-generic-function method))
+ (name (clos:generic-function-name gf))
+ (specializers (clos:method-specializers method))
+ (qualifiers (clos:method-qualifiers method)))
+ `(method ,name , at qualifiers ,specializers #+nil (clos::unparse-specializers specializers))))
+
+;; XXX maybe special case setters/getters
+(defun method-location (method)
+ (function-location (clos:method-function method)))
+
+(defun genericp (fn)
+ (typep fn 'generic-function))
+
+;;;;;; Types and classes
+
+(defun type-definitions (name)
+ "Return `deftype' locations for type NAME."
+ (maybe-make-definition (ext:info :type :expander name) 'deftype name))
+
+(defun maybe-make-definition (function kind name)
+ "If FUNCTION is non-nil then return its definition location."
+ (if function
+ (list (list `(,kind ,name) (function-location function)))))
+
+(defun class-definitions (name)
+ "Return the definition locations for the class called NAME."
+ (if (symbolp name)
+ (let ((class (find-class name nil)))
+ (etypecase class
+ (null '())
+ (structure-class
+ (list (list `(defstruct ,name)
+ (dd-location (find-dd name)))))
+ (standard-class
+ (list (list `(defclass ,name)
+ (class-location (find-class name)))))
+ ((or built-in-class
+ kernel:funcallable-structure-class)
+ (list (list `(kernel::define-type-class ,name)
+ `(:error
+ ,(format nil "No source info for ~A" name)))))))))
+
+(defun class-location (class)
+ "Return the `defclass' location for CLASS."
+ (definition-source-location class (class-name class)))
+
+(defun find-dd (name)
+ "Find the defstruct-definition by the name of its structure-class."
+ (let ((layout (ext:info :type :compiler-layout name)))
+ (if layout
+ (kernel:layout-info layout))))
+
+(defun condition-class-location (class)
+ (let ((name (class-name class)))
+ `(:error ,(format nil "No location info for condition: ~A" name))))
+
+(defun make-name-in-file-location (file string)
+ (multiple-value-bind (filename c)
+ (ignore-errors
+ (unix-truename (merge-pathnames (make-pathname :type "lisp")
+ file)))
+ (cond (filename (make-location `(:file ,filename)
+ `(:function-name ,(string string))))
+ (t (list :error (princ-to-string c))))))
+
+(defun definition-source-location (object name)
+ `(:error ,(format nil "No source info for: ~A" object)))
+
+(defun setf-definitions (name)
+ (let ((function (or (ext:info :setf :inverse name)
+ (ext:info :setf :expander name))))
+ (if function
+ (list (list `(setf ,name)
+ (function-location (coerce function 'function)))))))
+
+
+(defun variable-location (symbol)
+ `(:error ,(format nil "No source info for variable ~S" symbol)))
+
+(defun variable-definitions (name)
+ (if (symbolp name)
+ (multiple-value-bind (kind recorded-p) (ext:info :variable :kind name)
+ (if recorded-p
+ (list (list `(variable ,kind ,name)
+ (variable-location name)))))))
+
+(defun compiler-macro-definitions (symbol)
+ (maybe-make-definition (compiler-macro-function symbol)
+ 'define-compiler-macro
+ symbol))
+
+(defun source-transform-definitions (name)
+ (maybe-make-definition (ext:info :function :source-transform name)
+ 'c:def-source-transform
+ name))
+
+(defun function-info-definitions (name)
+ (let ((info (ext:info :function :info name)))
+ (if info
+ (append (loop for transform in (c::function-info-transforms info)
+ collect (list `(c:deftransform ,name
+ ,(c::type-specifier
+ (c::transform-type transform)))
+ (function-location (c::transform-function
+ transform))))
+ (maybe-make-definition (c::function-info-derive-type info)
+ 'c::derive-type name)
+ (maybe-make-definition (c::function-info-optimizer info)
+ 'c::optimizer name)
+ (maybe-make-definition (c::function-info-ltn-annotate info)
+ 'c::ltn-annotate name)
+ (maybe-make-definition (c::function-info-ir2-convert info)
+ 'c::ir2-convert name)
+ (loop for template in (c::function-info-templates info)
+ collect (list `(c::vop ,(c::template-name template))
+ (function-location
+ (c::vop-info-generator-function
+ template))))))))
+
+(defun ir1-translator-definitions (name)
+ (maybe-make-definition (ext:info :function :ir1-convert name)
+ 'c:def-ir1-translator name))
+
+
+;;;; Documentation.
+
+(defimplementation describe-symbol-for-emacs (symbol)
+ (let ((result '()))
+ (flet ((doc (kind)
+ (or (documentation symbol kind) :not-documented))
+ (maybe-push (property value)
+ (when value
+ (setf result (list* property value result)))))
+ (maybe-push
+ :variable (multiple-value-bind (kind recorded-p)
+ (ext:info variable kind symbol)
+ (declare (ignore kind))
+ (if (or (boundp symbol) recorded-p)
+ (doc 'variable))))
+ (when (fboundp symbol)
+ (maybe-push
+ (cond ((macro-function symbol) :macro)
+ ((special-operator-p symbol) :special-operator)
+ ((genericp (fdefinition symbol)) :generic-function)
+ (t :function))
+ (doc 'function)))
+ (maybe-push
+ :setf (if (or (ext:info setf inverse symbol)
+ (ext:info setf expander symbol))
+ (doc 'setf)))
+ (maybe-push
+ :type (if (ext:info type kind symbol)
+ (doc 'type)))
+ (maybe-push
+ :class (if (find-class symbol nil)
+ (doc 'class)))
+ (maybe-push
+ :alien-type (if (not (eq (ext:info alien-type kind symbol) :unknown))
+ (doc 'alien-type)))
+ (maybe-push
+ :alien-struct (if (ext:info alien-type struct symbol)
+ (doc nil)))
+ (maybe-push
+ :alien-union (if (ext:info alien-type union symbol)
+ (doc nil)))
+ (maybe-push
+ :alien-enum (if (ext:info alien-type enum symbol)
+ (doc nil)))
+ result)))
+
+(defimplementation describe-definition (symbol namespace)
+ (describe (ecase namespace
+ (:variable
+ symbol)
+ ((:function :generic-function)
+ (symbol-function symbol))
+ (:setf
+ (or (ext:info setf inverse symbol)
+ (ext:info setf expander symbol)))
+ (:type
+ (kernel:values-specifier-type symbol))
+ (:class
+ (find-class symbol))
+ (:alien-struct
+ (ext:info :alien-type :struct symbol))
+ (:alien-union
+ (ext:info :alien-type :union symbol))
+ (:alien-enum
+ (ext:info :alien-type :enum symbol))
+ (:alien-type
+ (ecase (ext:info :alien-type :kind symbol)
+ (:primitive
+ (let ((alien::*values-type-okay* t))
+ (funcall (ext:info :alien-type :translator symbol)
+ (list symbol))))
+ ((:defined)
+ (ext:info :alien-type :definition symbol))
+ (:unknown :unknown))))))
+
+;;;;; Argument lists
+
+(defimplementation arglist (fun)
+ (etypecase fun
+ (function (function-arglist fun))
+ (symbol (function-arglist (or (macro-function fun)
+ (symbol-function fun))))))
+
+(defun function-arglist (fun)
+ (flet ((compiled-function-arglist (x)
+ (let ((args (kernel:%function-arglist x)))
+ (if args
+ (read-arglist x)
+ :not-available))))
+ (case (kernel:get-type fun)
+ (#.vm:closure-header-type
+ (compiled-function-arglist
+ (kernel:%closure-function fun)))
+ ((#.vm:function-header-type #.vm:closure-function-header-type)
+ (compiled-function-arglist fun))
+ (#.vm:funcallable-instance-header-type
+ (typecase fun
+ (kernel:byte-function
+ :not-available)
+ (kernel:byte-closure
+ :not-available)
+ (eval:interpreted-function
+ (eval:interpreted-function-arglist fun))
+ (otherwise
+ (clos::generic-function-lambda-list fun))))
+ (t
+ :non-available))))
+
+(defimplementation function-name (function)
+ (cond ((eval:interpreted-function-p function)
+ (eval:interpreted-function-name function))
+ ((typep function 'generic-function)
+ (clos:generic-function-name function))
+ ((c::byte-function-or-closure-p function)
+ (c::byte-function-name function))
+ (t (kernel:%function-name (kernel:%function-self function)))))
+
+;;; A simple case: the arglist is available as a string that we can
+;;; `read'.
+
+(defun read-arglist (fn)
+ "Parse the arglist-string of the function object FN."
+ (let ((string (kernel:%function-arglist
+ (kernel:%function-self fn)))
+ (package (find-package
+ (c::compiled-debug-info-package
+ (kernel:%code-debug-info
+ (vm::find-code-object fn))))))
+ (with-standard-io-syntax
+ (let ((*package* (or package *package*)))
+ (read-from-string string)))))
+
+;;; A harder case: an approximate arglist is derived from available
+;;; debugging information.
+
+(defun debug-function-arglist (debug-function)
+ "Derive the argument list of DEBUG-FUNCTION from debug info."
+ (let ((args (di::debug-function-lambda-list debug-function))
+ (required '())
+ (optional '())
+ (rest '())
+ (key '()))
+ ;; collect the names of debug-vars
+ (dolist (arg args)
+ (etypecase arg
+ (di::debug-variable
+ (push (di::debug-variable-symbol arg) required))
+ ((member :deleted)
+ (push ':deleted required))
+ (cons
+ (ecase (car arg)
+ (:keyword
+ (push (second arg) key))
+ (:optional
+ (push (debug-variable-symbol-or-deleted (second arg)) optional))
+ (:rest
+ (push (debug-variable-symbol-or-deleted (second arg)) rest))))))
+ ;; intersperse lambda keywords as needed
+ (append (nreverse required)
+ (if optional (cons '&optional (nreverse optional)))
+ (if rest (cons '&rest (nreverse rest)))
+ (if key (cons '&key (nreverse key))))))
+
+(defun debug-variable-symbol-or-deleted (var)
+ (etypecase var
+ (di:debug-variable
+ (di::debug-variable-symbol var))
+ ((member :deleted)
+ '#:deleted)))
+
+(defun symbol-debug-function-arglist (fname)
+ "Return FNAME's debug-function-arglist and %function-arglist.
+ A utility for debugging DEBUG-FUNCTION-ARGLIST."
+ (let ((fn (fdefinition fname)))
+ (values (debug-function-arglist (di::function-debug-function fn))
+ (kernel:%function-arglist (kernel:%function-self fn)))))
+
+;;; Deriving arglists for byte-compiled functions:
+;;;
+(defun byte-code-function-arglist (fn)
+ ;; There doesn't seem to be much arglist information around for
+ ;; byte-code functions. Use the arg-count and return something like
+ ;; (arg0 arg1 ...)
+ (etypecase fn
+ (c::simple-byte-function
+ (loop for i from 0 below (c::simple-byte-function-num-args fn)
+ collect (make-arg-symbol i)))
+ (c::hairy-byte-function
+ (hairy-byte-function-arglist fn))
+ (c::byte-closure
+ (byte-code-function-arglist (c::byte-closure-function fn)))))
+
+(defun make-arg-symbol (i)
+ (make-symbol (format nil "~A~D" (string 'arg) i)))
+
+;;; A "hairy" byte-function is one that takes a variable number of
+;;; arguments. `hairy-byte-function' is a type from the bytecode
+;;; interpreter.
+;;;
+(defun hairy-byte-function-arglist (fn)
+ (let ((counter -1))
+ (flet ((next-arg () (make-arg-symbol (incf counter))))
+ (with-struct (c::hairy-byte-function- min-args max-args rest-arg-p
+ keywords-p keywords) fn
+ (let ((arglist '())
+ (optional (- max-args min-args)))
+ ;; XXX isn't there a better way to write this?
+ ;; (Looks fine to me. -luke)
+ (dotimes (i min-args)
+ (push (next-arg) arglist))
+ (when (plusp optional)
+ (push '&optional arglist)
+ (dotimes (i optional)
+ (push (next-arg) arglist)))
+ (when rest-arg-p
+ (push '&rest arglist)
+ (push (next-arg) arglist))
+ (when keywords-p
+ (push '&key arglist)
+ (loop for (key _ __) in keywords
+ do (push key arglist))
+ (when (eq keywords-p :allow-others)
+ (push '&allow-other-keys arglist)))
+ (nreverse arglist))))))
+
+
+;;;; Miscellaneous.
+
+(defimplementation macroexpand-all (form)
+ (macroexpand form))
+
+(defimplementation set-default-directory (directory)
+ (setf (ext:default-directory) (namestring directory))
+ ;; Setting *default-pathname-defaults* to an absolute directory
+ ;; makes the behavior of MERGE-PATHNAMES a bit more intuitive.
+ (setf *default-pathname-defaults* (pathname (ext:default-directory)))
+ (default-directory))
+
+(defimplementation default-directory ()
+ (namestring (ext:default-directory)))
+
+(defimplementation call-without-interrupts (fn)
+ (funcall fn))
+
+(defimplementation getpid ()
+ (unix:unix-getpid))
+
+(defimplementation lisp-implementation-type-name ()
+ (if (eq ext:*case-mode* :upper) "scl" "scl-lower"))
+
+(defimplementation quit-lisp ()
+ (ext:quit))
+
+;;; source-path-{stream,file,string,etc}-position moved into
+;;; swank-source-path-parser
+
+
+;;;; Debugging
+
+(defvar *sldb-stack-top*)
+
+(defimplementation call-with-debugging-environment (debugger-loop-fn)
+ (let* ((*sldb-stack-top* (or debug:*stack-top-hint* (di:top-frame)))
+ (debug:*stack-top-hint* nil)
+ (kernel:*current-level* 0))
+ (handler-bind ((di::unhandled-condition
+ (lambda (condition)
+ (error (make-condition
+ 'sldb-condition
+ :original-condition condition)))))
+ (funcall debugger-loop-fn))))
+
+(defun frame-down (frame)
+ (handler-case (di:frame-down frame)
+ (di:no-debug-info () nil)))
+
+(defun nth-frame (index)
+ (do ((frame *sldb-stack-top* (frame-down frame))
+ (i index (1- i)))
+ ((zerop i) frame)))
+
+(defimplementation compute-backtrace (start end)
+ (let ((end (or end most-positive-fixnum)))
+ (loop for f = (nth-frame start) then (frame-down f)
+ for i from start below end
+ while f
+ collect f)))
+
+(defimplementation print-frame (frame stream)
+ (let ((*standard-output* stream))
+ (handler-case
+ (debug::print-frame-call frame :verbosity 1 :number nil)
+ (error (e)
+ (ignore-errors (princ e stream))))))
+
+(defimplementation frame-source-location-for-emacs (index)
+ (code-location-source-location (di:frame-code-location (nth-frame index))))
+
+(defimplementation eval-in-frame (form index)
+ (di:eval-in-frame (nth-frame index) form))
+
+(defun frame-debug-vars (frame)
+ "Return a vector of debug-variables in frame."
+ (di::debug-function-debug-variables (di:frame-debug-function frame)))
+
+(defun debug-var-value (var frame location)
+ (let ((validity (di:debug-variable-validity var location)))
+ (ecase validity
+ (:valid (di:debug-variable-value var frame))
+ ((:invalid :unknown) (make-symbol (string validity))))))
+
+(defimplementation frame-locals (index)
+ (let* ((frame (nth-frame index))
+ (loc (di:frame-code-location frame))
+ (vars (frame-debug-vars frame)))
+ (loop for v across vars collect
+ (list :name (di:debug-variable-symbol v)
+ :id (di:debug-variable-id v)
+ :value (debug-var-value v frame loc)))))
+
+(defimplementation frame-var-value (frame var)
+ (let* ((frame (nth-frame frame))
+ (dvar (aref (frame-debug-vars frame) var)))
+ (debug-var-value dvar frame (di:frame-code-location frame))))
+
+(defimplementation frame-catch-tags (index)
+ (mapcar #'car (di:frame-catches (nth-frame index))))
+
+(defimplementation return-from-frame (index form)
+ (let ((sym (find-symbol (symbol-name '#:find-debug-tag-for-frame)
+ :debug-internals)))
+ (if sym
+ (let* ((frame (nth-frame index))
+ (probe (funcall sym frame)))
+ (cond (probe (throw (car probe) (eval-in-frame form index)))
+ (t (format nil "Cannot return from frame: ~S" frame))))
+ "return-from-frame is not implemented in this version of SCL.")))
+
+(defimplementation activate-stepping (frame)
+ (set-step-breakpoints (nth-frame frame)))
+
+(defimplementation sldb-break-on-return (frame)
+ (break-on-return (nth-frame frame)))
+
+;;; We set the breakpoint in the caller which might be a bit confusing.
+;;;
+(defun break-on-return (frame)
+ (let* ((caller (di:frame-down frame))
+ (cl (di:frame-code-location caller)))
+ (flet ((hook (frame bp)
+ (when (frame-pointer= frame caller)
+ (di:delete-breakpoint bp)
+ (signal-breakpoint bp frame))))
+ (let* ((info (ecase (di:code-location-kind cl)
+ ((:single-value-return :unknown-return) nil)
+ (:known-return (debug-function-returns
+ (di:frame-debug-function frame)))))
+ (bp (di:make-breakpoint #'hook cl :kind :code-location
+ :info info)))
+ (di:activate-breakpoint bp)
+ `(:ok ,(format nil "Set breakpoint in ~A" caller))))))
+
+(defun frame-pointer= (frame1 frame2)
+ "Return true if the frame pointers of FRAME1 and FRAME2 are the same."
+ (sys:sap= (di::frame-pointer frame1) (di::frame-pointer frame2)))
+
+;;; The PC in escaped frames at a single-return-value point is
+;;; actually vm:single-value-return-byte-offset bytes after the
+;;; position given in the debug info. Here we try to recognize such
+;;; cases.
+;;;
+(defun next-code-locations (frame code-location)
+ "Like `debug::next-code-locations' but be careful in escaped frames."
+ (let ((next (debug::next-code-locations code-location)))
+ (flet ((adjust-pc ()
+ (let ((cl (di::copy-compiled-code-location code-location)))
+ (incf (di::compiled-code-location-pc cl)
+ vm:single-value-return-byte-offset)
+ cl)))
+ (cond ((and (di::compiled-frame-escaped frame)
+ (eq (di:code-location-kind code-location)
+ :single-value-return)
+ (= (length next) 1)
+ (di:code-location= (car next) (adjust-pc)))
+ (debug::next-code-locations (car next)))
+ (t
+ next)))))
+
+(defun set-step-breakpoints (frame)
+ (let ((cl (di:frame-code-location frame)))
+ (when (di:debug-block-elsewhere-p (di:code-location-debug-block cl))
+ (error "Cannot step in elsewhere code"))
+ (let* ((debug::*bad-code-location-types*
+ (remove :call-site debug::*bad-code-location-types*))
+ (next (next-code-locations frame cl)))
+ (cond (next
+ (let ((steppoints '()))
+ (flet ((hook (bp-frame bp)
+ (signal-breakpoint bp bp-frame)
+ (mapc #'di:delete-breakpoint steppoints)))
+ (dolist (code-location next)
+ (let ((bp (di:make-breakpoint #'hook code-location
+ :kind :code-location)))
+ (di:activate-breakpoint bp)
+ (push bp steppoints))))))
+ (t
+ (break-on-return frame))))))
+
+
+;; XXX the return values at return breakpoints should be passed to the
+;; user hooks. debug-int.lisp should be changed to do this cleanly.
+
+;;; The sigcontext and the PC for a breakpoint invocation are not
+;;; passed to user hook functions, but we need them to extract return
+;;; values. So we advice di::handle-breakpoint and bind the values to
+;;; special variables.
+;;;
+(defvar *breakpoint-sigcontext*)
+(defvar *breakpoint-pc*)
+
+(defun sigcontext-object (sc index)
+ "Extract the lisp object in sigcontext SC at offset INDEX."
+ (kernel:make-lisp-obj (vm:ucontext-register sc index)))
+
+(defun known-return-point-values (sigcontext sc-offsets)
+ (let ((fp (system:int-sap (vm:ucontext-register sigcontext
+ vm::cfp-offset))))
+ (system:without-gcing
+ (loop for sc-offset across sc-offsets
+ collect (di::sub-access-debug-var-slot fp sc-offset sigcontext)))))
+
+;;; SCL returns the first few values in registers and the rest on
+;;; the stack. In the multiple value case, the number of values is
+;;; stored in a dedicated register. The values of the registers can be
+;;; accessed in the sigcontext for the breakpoint. There are 3 kinds
+;;; of return conventions: :single-value-return, :unknown-return, and
+;;; :known-return.
+;;;
+;;; The :single-value-return convention returns the value in a
+;;; register without setting the nargs registers.
+;;;
+;;; The :unknown-return variant is used for multiple values. A
+;;; :unknown-return point consists actually of 2 breakpoints: one for
+;;; the single value case and one for the general case. The single
+;;; value breakpoint comes vm:single-value-return-byte-offset after
+;;; the multiple value breakpoint.
+;;;
+;;; The :known-return convention is used by local functions.
+;;; :known-return is currently not supported because we don't know
+;;; where the values are passed.
+;;;
+(defun breakpoint-values (breakpoint)
+ "Return the list of return values for a return point."
+ (flet ((1st (sc) (sigcontext-object sc (car vm::register-arg-offsets))))
+ (let ((sc (locally (declare (optimize (ext:inhibit-warnings 3)))
+ (alien:sap-alien *breakpoint-sigcontext* (* unix:ucontext))))
+ (cl (di:breakpoint-what breakpoint)))
+ (ecase (di:code-location-kind cl)
+ (:single-value-return
+ (list (1st sc)))
+ (:known-return
+ (let ((info (di:breakpoint-info breakpoint)))
+ (if (vectorp info)
+ (known-return-point-values sc info)
+ (progn
+ ;;(break)
+ (list "<<known-return convention not supported>>" info)))))
+ (:unknown-return
+ (let ((mv-return-pc (di::compiled-code-location-pc cl)))
+ (if (= mv-return-pc *breakpoint-pc*)
+ (mv-function-end-breakpoint-values sc)
+ (list (1st sc)))))))))
+
+(defun mv-function-end-breakpoint-values (sigcontext)
+ (let ((sym (find-symbol (symbol-name '#:function-end-breakpoint-values/standard)
+ :debug-internals)))
+ (cond (sym (funcall sym sigcontext))
+ (t (di::get-function-end-breakpoint-values sigcontext)))))
+
+(defun debug-function-returns (debug-fun)
+ "Return the return style of DEBUG-FUN."
+ (let* ((cdfun (di::compiled-debug-function-compiler-debug-fun debug-fun)))
+ (c::compiled-debug-function-returns cdfun)))
+
+(define-condition breakpoint (simple-condition)
+ ((message :initarg :message :reader breakpoint.message)
+ (values :initarg :values :reader breakpoint.values))
+ (:report (lambda (c stream) (princ (breakpoint.message c) stream))))
+
+#+nil
+(defimplementation condition-extras ((c breakpoint))
+ ;; simply pop up the source buffer
+ `((:short-frame-source 0)))
+
+(defun signal-breakpoint (breakpoint frame)
+ "Signal a breakpoint condition for BREAKPOINT in FRAME.
+Try to create a informative message."
+ (flet ((brk (values fstring &rest args)
+ (let ((msg (apply #'format nil fstring args))
+ (debug:*stack-top-hint* frame))
+ (break 'breakpoint :message msg :values values))))
+ (with-struct (di::breakpoint- kind what) breakpoint
+ (case kind
+ (:code-location
+ (case (di:code-location-kind what)
+ ((:single-value-return :known-return :unknown-return)
+ (let ((values (breakpoint-values breakpoint)))
+ (brk values "Return value: ~{~S ~}" values)))
+ (t
+ #+(or)
+ (when (eq (di:code-location-kind what) :call-site)
+ (call-site-function breakpoint frame))
+ (brk nil "Breakpoint: ~S ~S"
+ (di:code-location-kind what)
+ (di::compiled-code-location-pc what)))))
+ (:function-start
+ (brk nil "Function start breakpoint"))
+ (t (brk nil "Breakpoint: ~A in ~A" breakpoint frame))))))
+
+#+nil
+(defimplementation sldb-break-at-start (fname)
+ (let ((debug-fun (di:function-debug-function (coerce fname 'function))))
+ (cond ((not debug-fun)
+ `(:error ,(format nil "~S has no debug-function" fname)))
+ (t
+ (flet ((hook (frame bp &optional args cookie)
+ (declare (ignore args cookie))
+ (signal-breakpoint bp frame)))
+ (let ((bp (di:make-breakpoint #'hook debug-fun
+ :kind :function-start)))
+ (di:activate-breakpoint bp)
+ `(:ok ,(format nil "Set breakpoint in ~S" fname))))))))
+
+(defun frame-cfp (frame)
+ "Return the Control-Stack-Frame-Pointer for FRAME."
+ (etypecase frame
+ (di::compiled-frame (di::frame-pointer frame))
+ ((or di::interpreted-frame null) -1)))
+
+(defun frame-ip (frame)
+ "Return the (absolute) instruction pointer and the relative pc of FRAME."
+ (if (not frame)
+ -1
+ (let ((debug-fun (di::frame-debug-function frame)))
+ (etypecase debug-fun
+ (di::compiled-debug-function
+ (let* ((code-loc (di:frame-code-location frame))
+ (component (di::compiled-debug-function-component debug-fun))
+ (pc (di::compiled-code-location-pc code-loc))
+ (ip (sys:without-gcing
+ (sys:sap-int
+ (sys:sap+ (kernel:code-instructions component) pc)))))
+ (values ip pc)))
+ ((or di::bogus-debug-function di::interpreted-debug-function)
+ -1)))))
+
+(defun frame-registers (frame)
+ "Return the lisp registers CSP, CFP, IP, OCFP, LRA for FRAME-NUMBER."
+ (let* ((cfp (frame-cfp frame))
+ (csp (frame-cfp (di::frame-up frame)))
+ (ip (frame-ip frame))
+ (ocfp (frame-cfp (di::frame-down frame)))
+ (lra (frame-ip (di::frame-down frame))))
+ (values csp cfp ip ocfp lra)))
+
+(defun print-frame-registers (frame-number)
+ (let ((frame (di::frame-real-frame (nth-frame frame-number))))
+ (flet ((fixnum (p) (etypecase p
+ (integer p)
+ (sys:system-area-pointer (sys:sap-int p)))))
+ (apply #'format t "~
+CSP = ~X
+CFP = ~X
+IP = ~X
+OCFP = ~X
+LRA = ~X~%" (mapcar #'fixnum
+ (multiple-value-list (frame-registers frame)))))))
+
+
+(defimplementation disassemble-frame (frame-number)
+ "Return a string with the disassembly of frames code."
+ (print-frame-registers frame-number)
+ (terpri)
+ (let* ((frame (di::frame-real-frame (nth-frame frame-number)))
+ (debug-fun (di::frame-debug-function frame)))
+ (etypecase debug-fun
+ (di::compiled-debug-function
+ (let* ((component (di::compiled-debug-function-component debug-fun))
+ (fun (di:debug-function-function debug-fun)))
+ (if fun
+ (disassemble fun)
+ (disassem:disassemble-code-component component))))
+ (di::bogus-debug-function
+ (format t "~%[Disassembling bogus frames not implemented]")))))
+
+
+;;;; Inspecting
+
+(defclass scl-inspector (backend-inspector) ())
+
+(defimplementation make-default-inspector ()
+ (make-instance 'scl-inspector))
+
+(defconstant +lowtag-symbols+
+ '(vm:even-fixnum-type
+ vm:instance-pointer-type
+ vm:other-immediate-0-type
+ vm:list-pointer-type
+ vm:odd-fixnum-type
+ vm:function-pointer-type
+ vm:other-immediate-1-type
+ vm:other-pointer-type)
+ "Names of the constants that specify type tags.
+The `symbol-value' of each element is a type tag.")
+
+(defconstant +header-type-symbols+
+ (labels ((suffixp (suffix string)
+ (and (>= (length string) (length suffix))
+ (string= string suffix :start1 (- (length string)
+ (length suffix)))))
+ (header-type-symbol-p (x)
+ (and (suffixp (symbol-name '#:-type) (symbol-name x))
+ (not (member x +lowtag-symbols+))
+ (boundp x)
+ (typep (symbol-value x) 'fixnum))))
+ (remove-if-not #'header-type-symbol-p
+ (append (apropos-list (symbol-name '#:-type) :vm)
+ (apropos-list (symbol-name '#:-type) :bignum))))
+ "A list of names of the type codes in boxed objects.")
+
+(defimplementation describe-primitive-type (object)
+ (with-output-to-string (*standard-output*)
+ (let* ((lowtag (kernel:get-lowtag object))
+ (lowtag-symbol (find lowtag +lowtag-symbols+ :key #'symbol-value)))
+ (format t "lowtag: ~A" lowtag-symbol)
+ (when (member lowtag (list vm:other-pointer-type
+ vm:function-pointer-type
+ vm:other-immediate-0-type
+ vm:other-immediate-1-type
+ ))
+ (let* ((type (kernel:get-type object))
+ (type-symbol (find type +header-type-symbols+
+ :key #'symbol-value)))
+ (format t ", type: ~A" type-symbol))))))
+
+(defmethod inspect-for-emacs ((o t) (inspector backend-inspector))
+ (cond ((di::indirect-value-cell-p o)
+ (values (format nil "~A is a value cell." o)
+ `("Value: " (:value ,(c:value-cell-ref o)))))
+ ((alien::alien-value-p o)
+ (inspect-alien-value o))
+ (t
+ (scl-inspect o))))
+
+(defun scl-inspect (o)
+ (destructuring-bind (text labeledp . parts)
+ (inspect::describe-parts o)
+ (values (format nil "~A~%" text)
+ (if labeledp
+ (loop for (label . value) in parts
+ append (label-value-line label value))
+ (loop for value in parts for i from 0
+ append (label-value-line i value))))))
+
+(defmethod inspect-for-emacs ((o function) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (let ((header (kernel:get-type o)))
+ (cond ((= header vm:function-header-type)
+ (values (format nil "~A is a function." o)
+ (append (label-value-line*
+ ("Self" (kernel:%function-self o))
+ ("Next" (kernel:%function-next o))
+ ("Name" (kernel:%function-name o))
+ ("Arglist" (kernel:%function-arglist o))
+ ("Type" (kernel:%function-type o))
+ ("Code" (kernel:function-code-header o)))
+ (list
+ (with-output-to-string (s)
+ (disassem:disassemble-function o :stream s))))))
+ ((= header vm:closure-header-type)
+ (values (format nil "~A is a closure" o)
+ (append
+ (label-value-line "Function" (kernel:%closure-function o))
+ `("Environment:" (:newline))
+ (loop for i from 0 below (- (kernel:get-closure-length o)
+ (1- vm:closure-info-offset))
+ append (label-value-line
+ i (kernel:%closure-index-ref o i))))))
+ ((eval::interpreted-function-p o)
+ (scl-inspect o))
+ (t
+ (call-next-method)))))
+
+
+(defmethod inspect-for-emacs ((o kernel:code-component) (_ backend-inspector))
+ (declare (ignore _))
+ (values (format nil "~A is a code data-block." o)
+ (append
+ (label-value-line*
+ ("code-size" (kernel:%code-code-size o))
+ ("entry-points" (kernel:%code-entry-points o))
+ ("debug-info" (kernel:%code-debug-info o))
+ ("trace-table-offset" (kernel:code-header-ref
+ o vm:code-trace-table-offset-slot)))
+ `("Constants:" (:newline))
+ (loop for i from vm:code-constants-offset
+ below (kernel:get-header-data o)
+ append (label-value-line i (kernel:code-header-ref o i)))
+ `("Code:" (:newline)
+ , (with-output-to-string (s)
+ (cond ((kernel:%code-debug-info o)
+ (disassem:disassemble-code-component o :stream s))
+ (t
+ (disassem:disassemble-memory
+ (disassem::align
+ (+ (logandc2 (kernel:get-lisp-obj-address o)
+ vm:lowtag-mask)
+ (* vm:code-constants-offset vm:word-bytes))
+ (ash 1 vm:lowtag-bits))
+ (ash (kernel:%code-code-size o) vm:word-shift)
+ :stream s))))))))
+
+(defmethod inspect-for-emacs ((o kernel:fdefn) (inspector backend-inspector))
+ (declare (ignore inspector))
+ (values (format nil "~A is a fdenf object." o)
+ (label-value-line*
+ ("name" (kernel:fdefn-name o))
+ ("function" (kernel:fdefn-function o))
+ ("raw-addr" (sys:sap-ref-32
+ (sys:int-sap (kernel:get-lisp-obj-address o))
+ (* vm:fdefn-raw-addr-slot vm:word-bytes))))))
+
+(defmethod inspect-for-emacs ((o array) (inspector backend-inspector))
+ inspector
+ (cond ((kernel:array-header-p o)
+ (values (format nil "~A is an array." o)
+ (label-value-line*
+ (:header (describe-primitive-type o))
+ (:rank (array-rank o))
+ (:fill-pointer (kernel:%array-fill-pointer o))
+ (:fill-pointer-p (kernel:%array-fill-pointer-p o))
+ (:elements (kernel:%array-available-elements o))
+ (:data (kernel:%array-data-vector o))
+ (:displacement (kernel:%array-displacement o))
+ (:displaced-p (kernel:%array-displaced-p o))
+ (:dimensions (array-dimensions o)))))
+ (t
+ (values (format nil "~A is an simple-array." o)
+ (label-value-line*
+ (:header (describe-primitive-type o))
+ (:length (length o)))))))
+
+(defmethod inspect-for-emacs ((o simple-vector) (inspector backend-inspector))
+ inspector
+ (values (format nil "~A is a vector." o)
+ (append
+ (label-value-line*
+ (:header (describe-primitive-type o))
+ (:length (c::vector-length o)))
+ (unless (eq (array-element-type o) 'nil)
+ (loop for i below (length o)
+ append (label-value-line i (aref o i)))))))
+
+(defun inspect-alien-record (alien)
+ (values
+ (format nil "~A is an alien value." alien)
+ (with-struct (alien::alien-value- sap type) alien
+ (with-struct (alien::alien-record-type- kind name fields) type
+ (append
+ (label-value-line*
+ (:sap sap)
+ (:kind kind)
+ (:name name))
+ (loop for field in fields
+ append (let ((slot (alien::alien-record-field-name field)))
+ (label-value-line slot (alien:slot alien slot)))))))))
+
+(defun inspect-alien-pointer (alien)
+ (values
+ (format nil "~A is an alien value." alien)
+ (with-struct (alien::alien-value- sap type) alien
+ (label-value-line*
+ (:sap sap)
+ (:type type)
+ (:to (alien::deref alien))))))
+
+(defun inspect-alien-value (alien)
+ (typecase (alien::alien-value-type alien)
+ (alien::alien-record-type (inspect-alien-record alien))
+ (alien::alien-pointer-type (inspect-alien-pointer alien))
+ (t (scl-inspect alien))))
+
+;;;; Profiling
+(defimplementation profile (fname)
+ (eval `(profile:profile ,fname)))
+
+(defimplementation unprofile (fname)
+ (eval `(profile:unprofile ,fname)))
+
+(defimplementation unprofile-all ()
+ (eval `(profile:unprofile))
+ "All functions unprofiled.")
+
+(defimplementation profile-report ()
+ (eval `(profile:report-time)))
+
+(defimplementation profile-reset ()
+ (eval `(profile:reset-time))
+ "Reset profiling counters.")
+
+(defimplementation profiled-functions ()
+ profile:*timed-functions*)
+
+(defimplementation profile-package (package callers methods)
+ (profile:profile-all :package package
+ :callers-p callers
+ #+nil :methods #+nil methods))
+
+
+;;;; Multiprocessing
+
+(defimplementation spawn (fn &key name)
+ (thread:thread-create fn :name (or name "Anonymous")))
+
+(defvar *thread-id-counter* 0)
+(defvar *thread-id-counter-lock* (thread:make-lock "Thread ID counter"))
+
+(defimplementation thread-id (thread)
+ (thread:with-lock-held (*thread-id-counter-lock*)
+ (or (getf (thread:thread-plist thread) 'id)
+ (setf (getf (thread:thread-plist thread) 'id)
+ (incf *thread-id-counter*)))))
+
+(defimplementation find-thread (id)
+ (block find-thread
+ (thread:map-over-threads
+ #'(lambda (thread)
+ (when (eql (getf (thread:thread-plist thread) 'id) id)
+ (return-from find-thread thread))))))
+
+(defimplementation thread-name (thread)
+ (princ-to-string (thread:thread-name thread)))
+
+(defimplementation thread-status (thread)
+ (let ((dynamic-values (thread::thread-dynamic-values thread)))
+ (if (zerop dynamic-values) "Exited" "Running")))
+
+(defimplementation make-lock (&key name)
+ (thread:make-lock name))
+
+(defimplementation call-with-lock-held (lock function)
+ (declare (type function function))
+ (thread:with-lock-held (lock) (funcall function)))
+
+(defimplementation current-thread ()
+ thread:*thread*)
+
+(defimplementation all-threads ()
+ (let ((all-threads nil))
+ (thread:map-over-threads #'(lambda (thread) (push thread all-threads)))
+ all-threads))
+
+(defimplementation interrupt-thread (thread fn)
+ (thread:thread-interrupt thread #'(lambda ()
+ (sys:with-interrupts
+ (funcall fn)))))
+
+(defimplementation kill-thread (thread)
+ (thread:destroy-thread thread))
+
+(defimplementation thread-alive-p (thread)
+ (not (zerop (thread::thread-dynamic-values thread))))
+
+(defvar *mailbox-lock* (thread:make-lock "Mailbox lock"))
+
+(defstruct (mailbox)
+ (lock (thread:make-lock "Thread mailbox" :type :error-check
+ :interruptible nil)
+ :type thread:error-check-lock)
+ (queue '() :type list))
+
+(defun mailbox (thread)
+ "Return 'thread's mailbox."
+ (thread:with-lock-held (*mailbox-lock*)
+ (or (getf (thread:thread-plist thread) 'mailbox)
+ (setf (getf (thread:thread-plist thread) 'mailbox) (make-mailbox)))))
+
+(defimplementation send (thread message)
+ (let* ((mbox (mailbox thread))
+ (lock (mailbox-lock mbox)))
+ (sys:without-interrupts
+ (thread:with-lock-held (lock "Mailbox Send")
+ (setf (mailbox-queue mbox) (nconc (mailbox-queue mbox)
+ (list message)))))
+ (mp:process-wakeup thread)
+ message))
+
+(defimplementation receive ()
+ (let* ((mbox (mailbox thread:*thread*))
+ (lock (mailbox-lock mbox)))
+ (loop
+ (mp:process-wait-with-timeout "Mailbox read wait" 1
+ #'(lambda () (mailbox-queue mbox)))
+ (multiple-value-bind (message winp)
+ (sys:without-interrupts
+ (mp:with-lock-held (lock "Mailbox read")
+ (let ((queue (mailbox-queue mbox)))
+ (cond (queue
+ (setf (mailbox-queue mbox) (cdr queue))
+ (values (car queue) t))
+ (t
+ (values nil nil))))))
+ (when winp
+ (return message))))))
+
+
+
+(defimplementation emacs-connected ())
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;Trace implementations
+;; In SCL, we have:
+;; (trace <name>)
+;; (trace (method <name> <qualifier>? (<specializer>+)))
+;; (trace :methods t '<name>) ;;to trace all methods of the gf <name>
+;; <name> can be a normal name or a (setf name)
+
+(defun tracedp (spec)
+ (member spec (eval '(trace)) :test #'equal))
+
+(defun toggle-trace-aux (spec &rest options)
+ (cond ((tracedp spec)
+ (eval `(untrace ,spec))
+ (format nil "~S is now untraced." spec))
+ (t
+ (eval `(trace ,spec , at options))
+ (format nil "~S is now traced." spec))))
+
+(defimplementation toggle-trace (spec)
+ (ecase (car spec)
+ ((setf)
+ (toggle-trace-aux spec))
+ ((:defgeneric)
+ (let ((name (second spec)))
+ (toggle-trace-aux name :methods name)))
+ ((:defmethod)
+ nil)
+ ((:call)
+ (destructuring-bind (caller callee) (cdr spec)
+ (toggle-trace-aux (process-fspec callee)
+ :wherein (list (process-fspec caller)))))))
+
+(defun process-fspec (fspec)
+ (cond ((consp fspec)
+ (ecase (first fspec)
+ ((:defun :defgeneric) (second fspec))
+ ((:defmethod)
+ `(method ,(second fspec) ,@(third fspec) ,(fourth fspec)))
+ ;; this isn't actually supported
+ ((:labels) `(labels ,(process-fspec (second fspec)) ,(third fspec)))
+ ((:flet) `(flet ,(process-fspec (second fspec)) ,(third fspec)))))
+ (t
+ fspec)))
+
+;;; Weak datastructures
+
+;;; Not implemented in SCL.
+(defimplementation make-weak-key-hash-table (&rest args)
+ (apply #'make-hash-table :weak-p t args))
+
+;; Local Variables:
+;; pbook-heading-regexp: "^;;;\\(;+\\)"
+;; pbook-commentary-regexp: "^;;;\\($\\|[^;]\\)"
+;; End:
Added: branches/bos/thirdparty/emacs/slime/swank-source-file-cache.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-source-file-cache.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,118 @@
+;;;; Source-file cache
+;;;
+;;; To robustly find source locations in CMUCL and SBCL it's useful to
+;;; have the exact source code that the loaded code was compiled from.
+;;; In this source we can accurately find the right location, and from
+;;; that location we can extract a "snippet" of code to show what the
+;;; definition looks like. Emacs can use this snippet in a best-match
+;;; search to locate the right definition, which works well even if
+;;; the buffer has been modified.
+;;;
+;;; The idea is that if a definition previously started with
+;;; `(define-foo bar' then it probably still does.
+;;;
+;;; Whenever we see that the file on disk has the same
+;;; `file-write-date' as a location we're looking for we cache the
+;;; whole file inside Lisp. That way we will still have the matching
+;;; version even if the file is later modified on disk. If the file is
+;;; later recompiled and reloaded then we replace our cache entry.
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+
+(in-package :swank-backend)
+
+(defvar *cache-sourcecode* t
+ "When true complete source files are cached.
+The cache is used to keep known good copies of the source text which
+correspond to the loaded code. Finding definitions is much more
+reliable when the exact source is available, so we cache it in case it
+gets edited on disk later.")
+
+(defvar *source-file-cache* (make-hash-table :test 'equal)
+ "Cache of source file contents.
+Maps from truename to source-cache-entry structure.")
+
+(defstruct (source-cache-entry
+ (:conc-name source-cache-entry.)
+ (:constructor make-source-cache-entry (text date)))
+ text date)
+
+(defimplementation buffer-first-change (filename)
+ "Load a file into the cache when the user modifies its buffer.
+This is a win if the user then saves the file and tries to M-. into it."
+ (unless (source-cached-p filename)
+ (ignore-errors
+ (source-cache-get filename (file-write-date filename))))
+ nil)
+
+(defun get-source-code (filename code-date)
+ "Return the source code for FILENAME as written on DATE in a string.
+If the exact version cannot be found then return the current one from disk."
+ (or (source-cache-get filename code-date)
+ (read-file filename)))
+
+(defun source-cache-get (filename date)
+ "Return the source code for FILENAME as written on DATE in a string.
+Return NIL if the right version cannot be found."
+ (when *cache-sourcecode*
+ (let ((entry (gethash filename *source-file-cache*)))
+ (cond ((and entry (equal date (source-cache-entry.date entry)))
+ ;; Cache hit.
+ (source-cache-entry.text entry))
+ ((or (null entry)
+ (not (equal date (source-cache-entry.date entry))))
+ ;; Cache miss.
+ (if (equal (file-write-date filename) date)
+ ;; File on disk has the correct version.
+ (let ((source (read-file filename)))
+ (setf (gethash filename *source-file-cache*)
+ (make-source-cache-entry source date))
+ source)
+ nil))))))
+
+(defun source-cached-p (filename)
+ "Is any version of FILENAME in the source cache?"
+ (if (gethash filename *source-file-cache*) t))
+
+(defun read-file (filename)
+ "Return the entire contents of FILENAME as a string."
+ (with-open-file (s filename :direction :input
+ :external-format (or (guess-external-format filename)
+ (find-external-format "latin-1")
+ :default))
+ (let ((string (make-string (file-length s))))
+ (read-sequence string s)
+ string)))
+
+;;;; Snippets
+
+(defvar *source-snippet-size* 256
+ "Maximum number of characters in a snippet of source code.
+Snippets at the beginning of definitions are used to tell Emacs what
+the definitions looks like, so that it can accurately find them by
+text search.")
+
+(defun read-snippet (stream &optional position)
+ "Read a string of upto *SOURCE-SNIPPET-SIZE* characters from STREAM.
+If POSITION is given, set the STREAM's file position first."
+ (when position
+ (file-position stream position))
+ #+SBCL (skip-comments-and-whitespace stream)
+ (read-upto-n-chars stream *source-snippet-size*))
+
+(defun skip-comments-and-whitespace (stream)
+ (case (peek-char nil stream)
+ ((#\Space #\Tab #\Newline #\Linefeed)
+ (read-char stream)
+ (skip-comments-and-whitespace stream))
+ (#\;
+ (read-line stream)
+ (skip-comments-and-whitespace stream))))
+
+(defun read-upto-n-chars (stream n)
+ "Return a string of upto N chars from STREAM."
+ (let* ((string (make-string n))
+ (chars (read-sequence string stream)))
+ (subseq string 0 chars)))
+
Added: branches/bos/thirdparty/emacs/slime/swank-source-path-parser.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank-source-path-parser.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,131 @@
+;;;; Source-paths
+
+;;; CMUCL/SBCL use a data structure called "source-path" to locate
+;;; subforms. The compiler assigns a source-path to each form in a
+;;; compilation unit. Compiler notes usually contain the source-path
+;;; of the error location.
+;;;
+;;; Compiled code objects don't contain source paths, only the
+;;; "toplevel-form-number" and the (sub-) "form-number". To get from
+;;; the form-number to the source-path we need the entire toplevel-form
+;;; (i.e. we have to read the source code). CMUCL has already some
+;;; utilities to do this translation, but we use some extended
+;;; versions, because we need more exact position info. Apparently
+;;; Hemlock is happy with the position of the toplevel-form; we also
+;;; need the position of subforms.
+;;;
+;;; We use a special readtable to get the positions of the subforms.
+;;; The readtable stores the start and end position for each subform in
+;;; hashtable for later retrieval.
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+
+;;; Taken from swank-cmucl.lisp, by Helmut Eller
+
+(in-package :swank-backend)
+
+;; Some test to ensure the required conformance
+(let ((rt (copy-readtable nil)))
+ (assert (or (not (get-macro-character #\space rt))
+ (nth-value 1 (get-macro-character #\space rt))))
+ (assert (not (get-macro-character #\\ rt))))
+
+(defun make-source-recorder (fn source-map)
+ "Return a macro character function that does the same as FN, but
+additionally stores the result together with the stream positions
+before and after of calling FN in the hashtable SOURCE-MAP."
+ (declare (type function fn))
+ (lambda (stream char)
+ (let ((start (file-position stream))
+ (values (multiple-value-list (funcall fn stream char)))
+ (end (file-position stream)))
+ ;;(format t "[~D ~{~A~^, ~} ~D ~D]~%" start values end (char-code char))
+ (unless (null values)
+ (push (cons start end) (gethash (car values) source-map)))
+ (values-list values))))
+
+(defun make-source-recording-readtable (readtable source-map)
+ "Return a source position recording copy of READTABLE.
+The source locations are stored in SOURCE-MAP."
+ (let* ((tab (copy-readtable readtable))
+ (*readtable* tab))
+ (dotimes (code 128)
+ (let ((char (code-char code)))
+ (multiple-value-bind (fn term) (get-macro-character char tab)
+ (when fn
+ (set-macro-character char (make-source-recorder fn source-map)
+ term tab)))))
+ (suppress-sharp-dot tab)
+ tab))
+
+(defun suppress-sharp-dot (readtable)
+ (when (get-macro-character #\# readtable)
+ (let ((sharp-dot (get-dispatch-macro-character #\# #\. readtable)))
+ (set-dispatch-macro-character #\# #\. (lambda (&rest args)
+ (let ((*read-suppress* t))
+ (apply sharp-dot args))
+ (if *read-suppress*
+ (values)
+ (list (gensym "#."))))
+ readtable))))
+
+(defun read-and-record-source-map (stream)
+ "Read the next object from STREAM.
+Return the object together with a hashtable that maps
+subexpressions of the object to stream positions."
+ (let* ((source-map (make-hash-table :test #'eq))
+ (*readtable* (make-source-recording-readtable *readtable* source-map))
+ (start (file-position stream))
+ (form (read stream))
+ (end (file-position stream)))
+ ;; ensure that at least FORM is in the source-map
+ (unless (gethash form source-map)
+ (push (cons start end) (gethash form source-map)))
+ (values form source-map)))
+
+(defun read-source-form (n stream)
+ "Read the Nth toplevel form number with source location recording.
+Return the form and the source-map."
+ (let ((*read-suppress* t))
+ (dotimes (i n)
+ (read stream)))
+ (let ((*read-suppress* nil)
+ (*read-eval* nil))
+ (read-and-record-source-map stream)))
+
+(defun source-path-stream-position (path stream)
+ "Search the source-path PATH in STREAM and return its position."
+ (check-source-path path)
+ (destructuring-bind (tlf-number . path) path
+ (multiple-value-bind (form source-map) (read-source-form tlf-number stream)
+ (source-path-source-position (cons 0 path) form source-map))))
+
+(defun check-source-path (path)
+ (unless (and (consp path)
+ (every #'integerp path))
+ (error "The source-path ~S is not valid." path)))
+
+(defun source-path-string-position (path string)
+ (with-input-from-string (s string)
+ (source-path-stream-position path s)))
+
+(defun source-path-file-position (path filename)
+ (with-open-file (file filename)
+ (source-path-stream-position path file)))
+
+(defun source-path-source-position (path form source-map)
+ "Return the start position of PATH from FORM and SOURCE-MAP. All
+subforms along the path are considered and the start and end position
+of the deepest (i.e. smallest) possible form is returned."
+ ;; compute all subforms along path
+ (let ((forms (loop for n in path
+ for f = form then (nth n f)
+ collect f)))
+ ;; select the first subform present in source-map
+ (loop for form in (reverse forms)
+ for positions = (gethash form source-map)
+ until (and positions (null (cdr positions)))
+ finally (destructuring-bind ((start . end)) positions
+ (return (values (1- start) end))))))
+
Added: branches/bos/thirdparty/emacs/slime/swank.asd
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank.asd Fri Jan 18 06:05:59 2008
@@ -0,0 +1,48 @@
+;;; -*- lisp -*-
+
+;; ASDF system definition for loading the Swank server independently
+;; of Emacs.
+;;
+;; This is only useful if you want to start a Swank server in a Lisp
+;; processes that doesn't run under Emacs. Lisp processes created by
+;; `M-x slime' automatically start the server.
+
+;; Usage:
+;;
+;; (require :swank)
+;; (swank:create-swank-server PORT) => ACTUAL-PORT
+;;
+;; (PORT can be zero to mean "any available port".)
+;; Then the Swank server is running on localhost:ACTUAL-PORT. You can
+;; use `M-x slime-connect' to connect Emacs to it.
+;;
+;; This code has been placed in the Public Domain. All warranties
+;; are disclaimed.
+
+(defpackage :swank-loader
+ (:use :cl))
+
+(in-package :swank-loader)
+
+(defclass cl-script-file (asdf:source-file) ())
+
+(defmethod asdf:perform ((o asdf:compile-op) (f cl-script-file))
+ t)
+(defmethod asdf:perform ((o asdf:load-op) (f cl-script-file))
+ (mapcar #'load (asdf:input-files o f)))
+(defmethod asdf:output-files ((o asdf:compile-op) (f cl-script-file))
+ nil)
+(defmethod asdf:input-files ((o asdf:load-op) (c cl-script-file))
+ (list (asdf:component-pathname c)))
+(defmethod asdf:operation-done-p ((o asdf:compile-op) (c cl-script-file))
+ t)
+(defmethod asdf:source-file-type ((c cl-script-file) (s asdf:module))
+ "lisp")
+
+(asdf:defsystem :swank
+ :default-component-class cl-script-file
+ :components ((:file "swank-loader")))
+
+(defparameter *source-directory*
+ (asdf:component-pathname (asdf:find-system :swank)))
+
Added: branches/bos/thirdparty/emacs/slime/swank.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/swank.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,3262 @@
+;;; -*- outline-regexp:";;;;;*" indent-tabs-mode:nil coding:latin-1-unix -*-
+;;;
+;;; This code has been placed in the Public Domain. All warranties
+;;; are disclaimed.
+;;;
+;;;; swank.lisp
+;;;
+;;; This file defines the "Swank" TCP server for Emacs to talk to. The
+;;; code in this file is purely portable Common Lisp. We do require a
+;;; smattering of non-portable functions in order to write the server,
+;;; so we have defined them in `swank-backend.lisp' and implemented
+;;; them separately for each Lisp implementation. These extensions are
+;;; available to us here via the `SWANK-BACKEND' package.
+
+(defpackage :swank
+ (:use :common-lisp :swank-backend)
+ (:export #:startup-multiprocessing
+ #:start-server
+ #:create-server
+ #:stop-server
+ #:restart-server
+ #:ed-in-emacs
+ #:inspect-in-emacs
+ #:print-indentation-lossage
+ #:swank-debugger-hook
+ #:run-after-init-hook
+ #:inspect-for-emacs
+ #:inspect-slot-for-emacs
+ ;; These are user-configurable variables:
+ #:*communication-style*
+ #:*dont-close*
+ #:*log-events*
+ #:*log-output*
+ #:*use-dedicated-output-stream*
+ #:*dedicated-output-stream-port*
+ #:*configure-emacs-indentation*
+ #:*readtable-alist*
+ #:*globally-redirect-io*
+ #:*global-debugger*
+ #:*sldb-printer-bindings*
+ #:*swank-pprint-bindings*
+ #:*default-worker-thread-bindings*
+ #:*macroexpand-printer-bindings*
+ #:*record-repl-results*
+ #:*debug-on-swank-error*
+ ;; These are re-exported directly from the backend:
+ #:buffer-first-change
+ #:frame-source-location-for-emacs
+ #:restart-frame
+ #:sldb-step
+ #:sldb-break
+ #:sldb-break-on-return
+ #:profiled-functions
+ #:profile-report
+ #:profile-reset
+ #:unprofile-all
+ #:profile-package
+ #:default-directory
+ #:set-default-directory
+ #:quit-lisp))
+
+(in-package :swank)
+
+
+;;;; Top-level variables, constants, macros
+
+(defconstant cl-package (find-package :cl)
+ "The COMMON-LISP package.")
+
+(defconstant keyword-package (find-package :keyword)
+ "The KEYWORD package.")
+
+(defvar *canonical-package-nicknames*
+ `((:common-lisp-user . :cl-user))
+ "Canonical package names to use instead of shortest name/nickname.")
+
+(defvar *auto-abbreviate-dotted-packages* t
+ "Abbreviate dotted package names to their last component if T.")
+
+(defvar *swank-io-package*
+ (let ((package (make-package :swank-io-package :use '())))
+ (import '(nil t quote) package)
+ package))
+
+(defconstant default-server-port 4005
+ "The default TCP port for the server (when started manually).")
+
+(defvar *swank-debug-p* t
+ "When true, print extra debugging information.")
+
+(defvar *redirect-io* t
+ "When non-nil redirect Lisp standard I/O to Emacs.
+Redirection is done while Lisp is processing a request for Emacs.")
+
+(defvar *sldb-printer-bindings*
+ `((*print-pretty* . t)
+ (*print-level* . 4)
+ (*print-length* . 10)
+ (*print-circle* . t)
+ (*print-readably* . nil)
+ (*print-pprint-dispatch* . ,(copy-pprint-dispatch nil))
+ (*print-gensym* . t)
+ (*print-base* . 10)
+ (*print-radix* . nil)
+ (*print-array* . t)
+ (*print-lines* . 10)
+ (*print-escape* . t)
+ (*print-right-margin* . 65))
+ "A set of printer variables used in the debugger.")
+
+(defvar *backtrace-printer-bindings*
+ `((*print-pretty* . nil)
+ (*print-level* . 4)
+ (*print-length* . 6))
+ "Pretter settings for printing backtraces.")
+
+(defvar *default-worker-thread-bindings* '()
+ "An alist to initialize dynamic variables in worker threads.
+The list has the form ((VAR . VALUE) ...). Each variable VAR will be
+bound to the corresponding VALUE.")
+
+(defun call-with-bindings (alist fun)
+ "Call FUN with variables bound according to ALIST.
+ALIST is a list of the form ((VAR . VAL) ...)."
+ (let* ((rlist (reverse alist))
+ (vars (mapcar #'car rlist))
+ (vals (mapcar #'cdr rlist)))
+ (progv vars vals
+ (funcall fun))))
+
+(defmacro with-bindings (alist &body body)
+ "See `call-with-bindings'."
+ `(call-with-bindings ,alist (lambda () , at body)))
+
+;;; The `DEFSLIMEFUN' macro defines a function that Emacs can call via
+;;; RPC.
+
+(defmacro defslimefun (name arglist &body rest)
+ "A DEFUN for functions that Emacs can call by RPC."
+ `(progn
+ (defun ,name ,arglist , at rest)
+ ;; see <http://www.franz.com/support/documentation/6.2/doc/pages/variables/compiler/s_cltl1-compile-file-toplevel-compatibility-p_s.htm>
+ (eval-when (:compile-toplevel :load-toplevel :execute)
+ (export ',name :swank))))
+
+(defun missing-arg ()
+ "A function that the compiler knows will never to return a value.
+You can use (MISSING-ARG) as the initform for defstruct slots that
+must always be supplied. This way the :TYPE slot option need not
+include some arbitrary initial value like NIL."
+ (error "A required &KEY or &OPTIONAL argument was not supplied."))
+
+
+;;;; Hooks
+;;;
+;;; We use Emacs-like `add-hook' and `run-hook' utilities to support
+;;; simple indirection. The interface is more CLish than the Emacs
+;;; Lisp one.
+
+(defmacro add-hook (place function)
+ "Add FUNCTION to the list of values on PLACE."
+ `(pushnew ,function ,place))
+
+(defun run-hook (functions &rest arguments)
+ "Call each of FUNCTIONS with ARGUMENTS."
+ (dolist (function functions)
+ (apply function arguments)))
+
+(defvar *new-connection-hook* '()
+ "This hook is run each time a connection is established.
+The connection structure is given as the argument.
+Backend code should treat the connection structure as opaque.")
+
+(defvar *connection-closed-hook* '()
+ "This hook is run when a connection is closed.
+The connection as passed as an argument.
+Backend code should treat the connection structure as opaque.")
+
+(defvar *pre-reply-hook* '()
+ "Hook run (without arguments) immediately before replying to an RPC.")
+
+(defvar *after-init-hook* '()
+ "Hook run after user init files are loaded.")
+
+(defun run-after-init-hook ()
+ (run-hook *after-init-hook*))
+
+
+;;;; Connections
+;;;
+;;; Connection structures represent the network connections between
+;;; Emacs and Lisp. Each has a socket stream, a set of user I/O
+;;; streams that redirect to Emacs, and optionally a second socket
+;;; used solely to pipe user-output to Emacs (an optimization).
+;;;
+
+(defstruct (connection
+ (:conc-name connection.)
+ (:print-function print-connection))
+ ;; Raw I/O stream of socket connection.
+ (socket-io (missing-arg) :type stream :read-only t)
+ ;; Optional dedicated output socket (backending `user-output' slot).
+ ;; Has a slot so that it can be closed with the connection.
+ (dedicated-output nil :type (or stream null))
+ ;; Streams that can be used for user interaction, with requests
+ ;; redirected to Emacs.
+ (user-input nil :type (or stream null))
+ (user-output nil :type (or stream null))
+ (user-io nil :type (or stream null))
+ ;; A stream that we use for *trace-output*; if nil, we user user-output.
+ (trace-output nil :type (or stream null))
+ ;; A stream where we send REPL results.
+ (repl-results nil :type (or stream null))
+ ;; In multithreaded systems we delegate certain tasks to specific
+ ;; threads. The `reader-thread' is responsible for reading network
+ ;; requests from Emacs and sending them to the `control-thread'; the
+ ;; `control-thread' is responsible for dispatching requests to the
+ ;; threads that should handle them; the `repl-thread' is the one
+ ;; that evaluates REPL expressions. The control thread dispatches
+ ;; all REPL evaluations to the REPL thread and for other requests it
+ ;; spawns new threads.
+ reader-thread
+ control-thread
+ repl-thread
+ ;; Callback functions:
+ ;; (SERVE-REQUESTS <this-connection>) serves all pending requests
+ ;; from Emacs.
+ (serve-requests (missing-arg) :type function)
+ ;; (READ) is called to read and return one message from Emacs.
+ (read (missing-arg) :type function)
+ ;; (SEND OBJECT) is called to send one message to Emacs.
+ (send (missing-arg) :type function)
+ ;; (CLEANUP <this-connection>) is called when the connection is
+ ;; closed.
+ (cleanup nil :type (or null function))
+ ;; Cache of macro-indentation information that has been sent to Emacs.
+ ;; This is used for preparing deltas to update Emacs's knowledge.
+ ;; Maps: symbol -> indentation-specification
+ (indentation-cache (make-hash-table :test 'eq) :type hash-table)
+ ;; The list of packages represented in the cache:
+ (indentation-cache-packages '())
+ ;; The communication style used.
+ (communication-style nil :type (member nil :spawn :sigio :fd-handler))
+ ;; The coding system for network streams.
+ (coding-system ))
+
+(defun print-connection (conn stream depth)
+ (declare (ignore depth))
+ (print-unreadable-object (conn stream :type t :identity t)))
+
+(defvar *connections* '()
+ "List of all active connections, with the most recent at the front.")
+
+(defvar *emacs-connection* nil
+ "The connection to Emacs currently in use.")
+
+(defvar *swank-state-stack* '()
+ "A list of symbols describing the current state. Used for debugging
+and to detect situations where interrupts can be ignored.")
+
+(defun default-connection ()
+ "Return the 'default' Emacs connection.
+This connection can be used to talk with Emacs when no specific
+connection is in use, i.e. *EMACS-CONNECTION* is NIL.
+
+The default connection is defined (quite arbitrarily) as the most
+recently established one."
+ (first *connections*))
+
+(defslimefun state-stack ()
+ "Return the value of *SWANK-STATE-STACK*."
+ *swank-state-stack*)
+
+;; A conditions to include backtrace information
+(define-condition swank-error (error)
+ ((condition :initarg :condition :reader swank-error.condition)
+ (backtrace :initarg :backtrace :reader swank-error.backtrace))
+ (:report (lambda (condition stream)
+ (princ (swank-error.condition condition) stream))))
+
+(defun make-swank-error (condition)
+ (let ((bt (ignore-errors
+ (call-with-debugging-environment
+ (lambda () (backtrace 0 nil))))))
+ (make-condition 'swank-error :condition condition :backtrace bt)))
+
+(add-hook *new-connection-hook* 'notify-backend-of-connection)
+(defun notify-backend-of-connection (connection)
+ (declare (ignore connection))
+ (emacs-connected))
+
+
+;;;; Utilities
+
+;;;;; Helper macros
+
+(defmacro with-io-redirection ((connection) &body body)
+ "Execute BODY I/O redirection to CONNECTION.
+If *REDIRECT-IO* is true then all standard I/O streams are redirected."
+ `(maybe-call-with-io-redirection ,connection (lambda () , at body)))
+
+(defun maybe-call-with-io-redirection (connection fun)
+ (if *redirect-io*
+ (call-with-redirected-io connection fun)
+ (funcall fun)))
+
+(defmacro with-connection ((connection) &body body)
+ "Execute BODY in the context of CONNECTION."
+ `(call-with-connection ,connection (lambda () , at body)))
+
+(defun call-with-connection (connection fun)
+ (let ((*emacs-connection* connection))
+ (with-io-redirection (*emacs-connection*)
+ (call-with-debugger-hook #'swank-debugger-hook fun))))
+
+(defmacro without-interrupts (&body body)
+ `(call-without-interrupts (lambda () , at body)))
+
+(defmacro destructure-case (value &rest patterns)
+ "Dispatch VALUE to one of PATTERNS.
+A cross between `case' and `destructuring-bind'.
+The pattern syntax is:
+ ((HEAD . ARGS) . BODY)
+The list of patterns is searched for a HEAD `eq' to the car of
+VALUE. If one is found, the BODY is executed with ARGS bound to the
+corresponding values in the CDR of VALUE."
+ (let ((operator (gensym "op-"))
+ (operands (gensym "rand-"))
+ (tmp (gensym "tmp-")))
+ `(let* ((,tmp ,value)
+ (,operator (car ,tmp))
+ (,operands (cdr ,tmp)))
+ (case ,operator
+ ,@(loop for (pattern . body) in patterns collect
+ (if (eq pattern t)
+ `(t , at body)
+ (destructuring-bind (op &rest rands) pattern
+ `(,op (destructuring-bind ,rands ,operands
+ , at body)))))
+ ,@(if (eq (caar (last patterns)) t)
+ '()
+ `((t (error "destructure-case failed: ~S" ,tmp))))))))
+
+(defmacro with-temp-package (var &body body)
+ "Execute BODY with VAR bound to a temporary package.
+The package is deleted before returning."
+ `(let ((,var (make-package (gensym "TEMP-PACKAGE-"))))
+ (unwind-protect (progn , at body)
+ (delete-package ,var))))
+
+(defmacro do-symbols* ((var &optional (package '*package*) result-form) &body body)
+ "Just like do-symbols, but makes sure a symbol is visited only once."
+ (let ((seen-ht (gensym "SEEN-HT")))
+ `(let ((,seen-ht (make-hash-table :test #'eq)))
+ (do-symbols (,var ,package ,result-form)
+ (unless (gethash ,var ,seen-ht)
+ (setf (gethash ,var ,seen-ht) t)
+ , at body)))))
+
+
+;;;;; Logging
+
+(defvar *log-events* nil)
+(defvar *log-output* *error-output*)
+(defvar *event-history* (make-array 40 :initial-element nil)
+ "A ring buffer to record events for better error messages.")
+(defvar *event-history-index* 0)
+(defvar *enable-event-history* t)
+
+(defun log-event (format-string &rest args)
+ "Write a message to *terminal-io* when *log-events* is non-nil.
+Useful for low level debugging."
+ (with-standard-io-syntax
+ (let ((*print-readably* nil)
+ (*print-pretty* nil)
+ (*package* *swank-io-package*))
+ (when *enable-event-history*
+ (setf (aref *event-history* *event-history-index*)
+ (format nil "~?" format-string args))
+ (setf *event-history-index*
+ (mod (1+ *event-history-index*) (length *event-history*))))
+ (when *log-events*
+ (apply #'format *log-output* format-string args)
+ (force-output *log-output*)))))
+
+(defun event-history-to-list ()
+ "Return the list of events (older events first)."
+ (let ((arr *event-history*)
+ (idx *event-history-index*))
+ (concatenate 'list (subseq arr idx) (subseq arr 0 idx))))
+
+(defun dump-event-history (stream)
+ (dolist (e (event-history-to-list))
+ (dump-event e stream)))
+
+(defun dump-event (event stream)
+ (cond ((stringp event)
+ (write-string (escape-non-ascii event) stream))
+ ((null event))
+ (t (format stream "Unexpected event: ~A~%" event))))
+
+(defun escape-non-ascii (string)
+ "Return a string like STRING but with non-ascii chars escaped."
+ (cond ((ascii-string-p string) string)
+ (t (with-output-to-string (out)
+ (loop for c across string do
+ (cond ((ascii-char-p c) (write-char c out))
+ (t (format out "\\x~4,'0X" (char-code c)))))))))
+
+(defun ascii-string-p (o)
+ (and (stringp o)
+ (every #'ascii-char-p o)))
+
+(defun ascii-char-p (c)
+ (<= (char-code c) 127))
+
+
+;;;;; Misc
+
+(defun length= (seq n)
+ "Test for whether SEQ contains N number of elements. I.e. it's equivalent
+ to (= (LENGTH SEQ) N), but besides being more concise, it may also be more
+ efficiently implemented."
+ (etypecase seq
+ (list (do ((i n (1- i))
+ (list seq (cdr list)))
+ ((or (<= i 0) (null list))
+ (and (zerop i) (null list)))))
+ (sequence (= (length seq) n))))
+
+(defun ensure-list (thing)
+ (if (listp thing) thing (list thing)))
+
+(defun recursively-empty-p (list)
+ "Returns whether LIST consists only of arbitrarily nested empty lists."
+ (cond ((not (listp list)) nil)
+ ((null list) t)
+ (t (every #'recursively-empty-p list))))
+
+(defun maybecall (bool fn &rest args)
+ "Call FN with ARGS if BOOL is T. Otherwise return ARGS as multiple values."
+ (if bool (apply fn args) (values-list args)))
+
+(defun exactly-one-p (&rest values)
+ "If exactly one value in VALUES is non-NIL, this value is returned.
+Otherwise NIL is returned."
+ (let ((found nil))
+ (dolist (v values)
+ (when v (if found
+ (return-from exactly-one-p nil)
+ (setq found v))))
+ found))
+
+
+;;;;; Symbols
+
+(defun symbol-status (symbol &optional (package (symbol-package symbol)))
+ "Returns one of
+
+ :INTERNAL if the symbol is _present_ in PACKAGE as an _internal_ symbol,
+
+ :EXTERNAL if the symbol is _present_ in PACKAGE as an _external_ symbol,
+
+ :INHERITED if the symbol is _inherited_ by PACKAGE through USE-PACKAGE,
+ but is not _present_ in PACKAGE,
+
+ or NIL if SYMBOL is not _accessible_ in PACKAGE.
+
+
+Be aware not to get confused with :INTERNAL and how \"internal
+symbols\" are defined in the spec; there is a slight mismatch of
+definition with the Spec and what's commonly meant when talking
+about internal symbols most times. As the spec says:
+
+ In a package P, a symbol S is
+
+ _accessible_ if S is either _present_ in P itself or was
+ inherited from another package Q (which implies
+ that S is _external_ in Q.)
+
+ You can check that with: (AND (SYMBOL-STATUS S P) T)
+
+
+ _present_ if either P is the /home package/ of S or S has been
+ imported into P or exported from P by IMPORT, or
+ EXPORT respectively.
+
+ Or more simply, if S is not _inherited_.
+
+ You can check that with: (LET ((STATUS (SYMBOL-STATUS S P)))
+ (AND STATUS
+ (NOT (EQ STATUS :INHERITED))))
+
+
+ _external_ if S is going to be inherited into any package that
+ /uses/ P by means of USE-PACKAGE, MAKE-PACKAGE, or
+ DEFPACKAGE.
+
+ Note that _external_ implies _present_, since to
+ make a symbol _external_, you'd have to use EXPORT
+ which will automatically make the symbol _present_.
+
+ You can check that with: (EQ (SYMBOL-STATUS S P) :EXTERNAL)
+
+
+ _internal_ if S is _accessible_ but not _external_.
+
+ You can check that with: (LET ((STATUS (SYMBOL-STATUS S P)))
+ (AND STATUS
+ (NOT (EQ STATUS :EXTERNAL))))
+
+
+ Notice that this is *different* to
+ (EQ (SYMBOL-STATUS S P) :INTERNAL)
+ because what the spec considers _internal_ is split up into two
+ explicit pieces: :INTERNAL, and :INHERITED; just as, for instance,
+ CL:FIND-SYMBOL does.
+
+ The rationale is that most times when you speak about \"internal\"
+ symbols, you're actually not including the symbols inherited
+ from other packages, but only about the symbols directly specific
+ to the package in question.
+"
+ (when package ; may be NIL when symbol is completely uninterned.
+ (check-type symbol symbol) (check-type package package)
+ (multiple-value-bind (present-symbol status)
+ (find-symbol (symbol-name symbol) package)
+ (and (eq symbol present-symbol) status))))
+
+(defun symbol-external-p (symbol &optional (package (symbol-package symbol)))
+ "True if SYMBOL is external in PACKAGE.
+If PACKAGE is not specified, the home package of SYMBOL is used."
+ (eq (symbol-status symbol package) :external))
+
+
+(defun classify-symbol (symbol)
+ "Returns a list of classifiers that classify SYMBOL according
+to its underneath objects (e.g. :BOUNDP if SYMBOL constitutes a
+special variable.) The list may contain the following classification
+keywords: :BOUNDP, :FBOUNDP, :GENERIC-FUNCTION, :CLASS, :MACRO,
+:SPECIAL-OPERATOR, and/or :PACKAGE"
+ (check-type symbol symbol)
+ (let (result)
+ (when (boundp symbol) (push :boundp result))
+ (when (fboundp symbol) (push :fboundp result))
+ (when (find-class symbol nil) (push :class result))
+ (when (macro-function symbol) (push :macro result))
+ (when (special-operator-p symbol) (push :special-operator result))
+ (when (find-package symbol) (push :package result))
+ (when (typep (ignore-errors (fdefinition symbol))
+ 'generic-function)
+ (push :generic-function result))
+ result))
+
+(defun symbol-classification->string (flags)
+ (format nil "~A~A~A~A~A~A~A"
+ (if (member :boundp flags) "b" "-")
+ (if (member :fboundp flags) "f" "-")
+ (if (member :generic-function flags) "g" "-")
+ (if (member :class flags) "c" "-")
+ (if (member :macro flags) "m" "-")
+ (if (member :special-operator flags) "s" "-")
+ (if (member :package flags) "p" "-")))
+
+
+;;;; TCP Server
+
+(defvar *use-dedicated-output-stream* nil
+ "When T swank will attempt to create a second connection to
+ Emacs which is used just to send output.")
+
+(defvar *dedicated-output-stream-port* 0
+ "Which port we should use for the dedicated output stream.")
+
+(defvar *communication-style* (preferred-communication-style))
+
+(defvar *dont-close* nil
+ "Default value of :dont-close argument to start-server and
+ create-server.")
+
+(defvar *dedicated-output-stream-buffering*
+ (if (eq *communication-style* :spawn) :full :none)
+ "The buffering scheme that should be used for the output stream.
+Valid values are :none, :line, and :full.")
+
+(defvar *coding-system* "iso-latin-1-unix")
+
+(defvar *listener-sockets* nil
+ "A property list of lists containing style, socket pairs used
+ by swank server listeners, keyed on socket port number. They
+ are used to close sockets on server shutdown or restart.")
+
+(defun start-server (port-file &key (style *communication-style*)
+ (dont-close *dont-close*)
+ (coding-system *coding-system*))
+ "Start the server and write the listen port number to PORT-FILE.
+This is the entry point for Emacs."
+ (setup-server 0 (lambda (port)
+ (announce-server-port port-file port))
+ style dont-close
+ (find-external-format-or-lose coding-system)))
+
+(defun create-server (&key (port default-server-port)
+ (style *communication-style*)
+ (dont-close *dont-close*)
+ (coding-system *coding-system*))
+ "Start a SWANK server on PORT running in STYLE.
+If DONT-CLOSE is true then the listen socket will accept multiple
+connections, otherwise it will be closed after the first."
+ (setup-server port #'simple-announce-function style dont-close
+ (find-external-format-or-lose coding-system)))
+
+(defun find-external-format-or-lose (coding-system)
+ (or (find-external-format coding-system)
+ (error "Unsupported coding system: ~s" coding-system)))
+
+(defparameter *loopback-interface* "127.0.0.1")
+
+(defun setup-server (port announce-fn style dont-close external-format)
+ (declare (type function announce-fn))
+ (let* ((socket (create-socket *loopback-interface* port))
+ (local-port (local-port socket)))
+ (funcall announce-fn local-port)
+ (flet ((serve ()
+ (serve-connection socket style dont-close external-format)))
+ (ecase style
+ (:spawn
+ (initialize-multiprocessing
+ (lambda ()
+ (spawn (lambda ()
+ (loop do (ignore-errors (serve)) while dont-close))
+ :name (concatenate 'string "Swank "
+ (princ-to-string port))))))
+ ((:fd-handler :sigio)
+ (add-fd-handler socket (lambda () (serve))))
+ ((nil) (loop do (serve) while dont-close)))
+ (setf (getf *listener-sockets* port) (list style socket))
+ local-port)))
+
+(defun stop-server (port)
+ "Stop server running on PORT."
+ (let* ((socket-description (getf *listener-sockets* port))
+ (style (first socket-description))
+ (socket (second socket-description)))
+ (ecase style
+ (:spawn
+ (let ((thread-position
+ (position-if
+ (lambda (x)
+ (string-equal (first x)
+ (concatenate 'string "Swank "
+ (princ-to-string port))))
+ (list-threads))))
+ (when thread-position
+ (kill-nth-thread thread-position)
+ (close-socket socket)
+ (remf *listener-sockets* port))))
+ ((:fd-handler :sigio)
+ (remove-fd-handlers socket)
+ (close-socket socket)
+ (remf *listener-sockets* port)))))
+
+(defun restart-server (&key (port default-server-port)
+ (style *communication-style*)
+ (dont-close *dont-close*)
+ (coding-system *coding-system*))
+ "Stop the server listening on PORT, then start a new SWANK server
+on PORT running in STYLE. If DONT-CLOSE is true then the listen socket
+will accept multiple connections, otherwise it will be closed after the
+first."
+ (stop-server port)
+ (sleep 5)
+ (create-server :port port :style style :dont-close dont-close
+ :coding-system coding-system))
+
+
+(defun serve-connection (socket style dont-close external-format)
+ (let ((closed-socket-p nil))
+ (unwind-protect
+ (let ((client (accept-authenticated-connection
+ socket :external-format external-format)))
+ (unless dont-close
+ (close-socket socket)
+ (setf closed-socket-p t))
+ (let ((connection (create-connection client style)))
+ (run-hook *new-connection-hook* connection)
+ (push connection *connections*)
+ (serve-requests connection)))
+ (unless (or dont-close closed-socket-p)
+ (close-socket socket)))))
+
+(defun accept-authenticated-connection (&rest args)
+ (let ((new (apply #'accept-connection args))
+ (success nil))
+ (unwind-protect
+ (let ((secret (slime-secret)))
+ (when secret
+ (set-stream-timeout new 20)
+ (let ((first-val (decode-message new)))
+ (unless (and (stringp first-val) (string= first-val secret))
+ (error "Incoming connection doesn't know the password."))))
+ (set-stream-timeout new nil)
+ (setf success t))
+ (unless success
+ (close new :abort t)))
+ new))
+
+(defun slime-secret ()
+ "Finds the magic secret from the user's home directory. Returns nil
+if the file doesn't exist; otherwise the first line of the file."
+ (with-open-file (in
+ (merge-pathnames (user-homedir-pathname) #p".slime-secret")
+ :if-does-not-exist nil)
+ (and in (read-line in nil ""))))
+
+(defun serve-requests (connection)
+ "Read and process all requests on connections."
+ (funcall (connection.serve-requests connection) connection))
+
+(defun announce-server-port (file port)
+ (with-open-file (s file
+ :direction :output
+ :if-exists :error
+ :if-does-not-exist :create)
+ (format s "~S~%" port))
+ (simple-announce-function port))
+
+(defun simple-announce-function (port)
+ (when *swank-debug-p*
+ (format *log-output* "~&;; Swank started at port: ~D.~%" port)
+ (force-output *log-output*)))
+
+(defun open-streams (connection)
+ "Return the 5 streams for IO redirection:
+DEDICATED-OUTPUT INPUT OUTPUT IO REPL-RESULTS"
+ (multiple-value-bind (output-fn dedicated-output)
+ (make-output-function connection)
+ (let ((input-fn
+ (lambda ()
+ (with-connection (connection)
+ (with-simple-restart (abort-read
+ "Abort reading input from Emacs.")
+ (read-user-input-from-emacs))))))
+ (multiple-value-bind (in out) (make-fn-streams input-fn output-fn)
+ (let ((out (or dedicated-output out)))
+ (let ((io (make-two-way-stream in out)))
+ (mapc #'make-stream-interactive (list in out io))
+ (let ((repl-results
+ (make-output-stream-for-target connection :repl-result)))
+ (values dedicated-output in out io repl-results))))))))
+
+(defun make-output-function (connection)
+ "Create function to send user output to Emacs.
+This function may open a dedicated socket to send output. It
+returns two values: the output function, and the dedicated
+stream (or NIL if none was created)."
+ (if *use-dedicated-output-stream*
+ (let ((stream (open-dedicated-output-stream
+ (connection.socket-io connection))))
+ (values (lambda (string)
+ (write-string string stream)
+ (force-output stream))
+ stream))
+ (values (lambda (string)
+ (with-connection (connection)
+ (with-simple-restart
+ (abort "Abort sending output to Emacs.")
+ (send-to-emacs `(:write-string ,string)))))
+ nil)))
+
+(defun make-output-function-for-target (connection target)
+ "Create a function to send user output to a specific TARGET in Emacs."
+ (lambda (string)
+ (with-connection (connection)
+ (with-simple-restart
+ (abort "Abort sending output to Emacs.")
+ (send-to-emacs `(:write-string ,string ,target))))))
+
+(defun make-output-stream-for-target (connection target)
+ "Create a stream that sends output to a specific TARGET in Emacs."
+ (nth-value 1 (make-fn-streams
+ (lambda ()
+ (error "Should never be called"))
+ (make-output-function-for-target connection target))))
+
+(defun open-dedicated-output-stream (socket-io)
+ "Open a dedicated output connection to the Emacs on SOCKET-IO.
+Return an output stream suitable for writing program output.
+
+This is an optimized way for Lisp to deliver output to Emacs."
+ (let ((socket (create-socket *loopback-interface*
+ *dedicated-output-stream-port*)))
+ (unwind-protect
+ (let ((port (local-port socket)))
+ (encode-message `(:open-dedicated-output-stream ,port) socket-io)
+ (let ((dedicated (accept-authenticated-connection
+ socket
+ :external-format
+ (or (ignore-errors
+ (stream-external-format socket-io))
+ :default)
+ :buffering *dedicated-output-stream-buffering*
+ :timeout 30)))
+ (close-socket socket)
+ (setf socket nil)
+ dedicated))
+ (when socket
+ (close-socket socket)))))
+
+(defvar *sldb-quit-restart* 'abort
+ "What restart should swank attempt to invoke when the user sldb-quits.")
+
+(defun handle-request (connection)
+ "Read and process one request. The processing is done in the extent
+of the toplevel restart."
+ (assert (null *swank-state-stack*))
+ (let ((*swank-state-stack* '(:handle-request)))
+ (with-connection (connection)
+ (with-simple-restart (abort "Return to SLIME's top level.")
+ (let ((*sldb-quit-restart* (find-restart 'abort)))
+ (read-from-emacs))))))
+
+(defun current-socket-io ()
+ (connection.socket-io *emacs-connection*))
+
+(defun close-connection (c &optional condition backtrace)
+ (format *log-output* "~&;; swank:close-connection: ~A~%" condition)
+ (let ((cleanup (connection.cleanup c)))
+ (when cleanup
+ (funcall cleanup c)))
+ (close (connection.socket-io c))
+ (when (connection.dedicated-output c)
+ (close (connection.dedicated-output c)))
+ (setf *connections* (remove c *connections*))
+ (run-hook *connection-closed-hook* c)
+ (when (and condition (not (typep condition 'end-of-file)))
+ (finish-output *log-output*)
+ (format *log-output* "~&;; Event history start:~%")
+ (dump-event-history *log-output*)
+ (format *log-output* ";; Event history end.~%~
+ ;; Backtrace:~%~{~A~%~}~
+ ;; Connection to Emacs lost. [~%~
+ ;; condition: ~A~%~
+ ;; type: ~S~%~
+ ;; encoding: ~A style: ~S dedicated: ~S]~%"
+ backtrace
+ (escape-non-ascii (safe-condition-message condition) )
+ (type-of condition)
+ (ignore-errors (stream-external-format (connection.socket-io c)))
+ (connection.communication-style c)
+ *use-dedicated-output-stream*)
+ (finish-output *log-output*)))
+
+(defvar *debug-on-swank-error* nil
+ "When non-nil internal swank errors will drop to a
+ debugger (not an sldb buffer). Do not set this to T unless you
+ want to debug swank internals.")
+
+(defmacro with-reader-error-handler ((connection) &body body)
+ (let ((con (gensym))
+ (blck (gensym)))
+ `(let ((,con ,connection))
+ (block ,blck
+ (handler-bind ((swank-error
+ (lambda (e)
+ (if *debug-on-swank-error*
+ (invoke-debugger e)
+ (return-from ,blck
+ (close-connection
+ ,con
+ (swank-error.condition e)
+ (swank-error.backtrace e)))))))
+ (progn , at body))))))
+
+(defslimefun simple-break ()
+ (with-simple-restart (continue "Continue from interrupt.")
+ (call-with-debugger-hook
+ #'swank-debugger-hook
+ (lambda ()
+ (invoke-debugger
+ (make-condition 'simple-error
+ :format-control "Interrupt from Emacs")))))
+ nil)
+
+;;;;;; Thread based communication
+
+(defvar *active-threads* '())
+
+(defun read-loop (control-thread input-stream connection)
+ (with-reader-error-handler (connection)
+ (loop (send control-thread (decode-message input-stream)))))
+
+(defun dispatch-loop (socket-io connection)
+ (let ((*emacs-connection* connection))
+ (handler-bind ((error (lambda (e)
+ (if *debug-on-swank-error*
+ (invoke-debugger e)
+ (return-from dispatch-loop
+ (close-connection connection e))))))
+ (loop (dispatch-event (receive) socket-io)))))
+
+(defun repl-thread (connection)
+ (let ((thread (connection.repl-thread connection)))
+ (when (not thread)
+ (log-event "ERROR: repl-thread is nil"))
+ (assert thread)
+ (cond ((thread-alive-p thread)
+ thread)
+ (t
+ (setf (connection.repl-thread connection)
+ (spawn-repl-thread connection "new-repl-thread"))))))
+
+(defun find-worker-thread (id)
+ (etypecase id
+ ((member t)
+ (car *active-threads*))
+ ((member :repl-thread)
+ (repl-thread *emacs-connection*))
+ (fixnum
+ (find-thread id))))
+
+(defun interrupt-worker-thread (id)
+ (let ((thread (or (find-worker-thread id)
+ (repl-thread *emacs-connection*))))
+ (interrupt-thread thread #'simple-break)))
+
+(defun thread-for-evaluation (id)
+ "Find or create a thread to evaluate the next request."
+ (let ((c *emacs-connection*))
+ (etypecase id
+ ((member t)
+ (spawn-worker-thread c))
+ ((member :repl-thread)
+ (repl-thread c))
+ (fixnum
+ (find-thread id)))))
+
+(defun spawn-worker-thread (connection)
+ (spawn (lambda ()
+ (with-bindings *default-worker-thread-bindings*
+ (handle-request connection)))
+ :name "worker"))
+
+(defun spawn-repl-thread (connection name)
+ (spawn (lambda ()
+ (with-bindings *default-worker-thread-bindings*
+ (repl-loop connection)))
+ :name name))
+
+(defun dispatch-event (event socket-io)
+ "Handle an event triggered either by Emacs or within Lisp."
+ (log-event "DISPATCHING: ~S~%" event)
+ (destructure-case event
+ ((:emacs-rex form package thread-id id)
+ (let ((thread (thread-for-evaluation thread-id)))
+ (push thread *active-threads*)
+ (send thread `(eval-for-emacs ,form ,package ,id))))
+ ((:return thread &rest args)
+ (let ((tail (member thread *active-threads*)))
+ (setq *active-threads* (nconc (ldiff *active-threads* tail)
+ (cdr tail))))
+ (encode-message `(:return , at args) socket-io))
+ ((:emacs-interrupt thread-id)
+ (interrupt-worker-thread thread-id))
+ (((:debug :debug-condition :debug-activate :debug-return)
+ thread &rest args)
+ (encode-message `(,(car event) ,(thread-id thread) , at args) socket-io))
+ ((:read-string thread &rest args)
+ (encode-message `(:read-string ,(thread-id thread) , at args) socket-io))
+ ((:y-or-n-p thread &rest args)
+ (encode-message `(:y-or-n-p ,(thread-id thread) , at args) socket-io))
+ ((:read-aborted thread &rest args)
+ (encode-message `(:read-aborted ,(thread-id thread) , at args) socket-io))
+ ((:emacs-return-string thread-id tag string)
+ (send (find-thread thread-id) `(take-input ,tag ,string)))
+ ((:eval thread &rest args)
+ (encode-message `(:eval ,(thread-id thread) , at args) socket-io))
+ ((:emacs-return thread-id tag value)
+ (send (find-thread thread-id) `(take-input ,tag ,value)))
+ (((:write-string :presentation-start :presentation-end
+ :new-package :new-features :ed :%apply :indentation-update
+ :eval-no-wait :background-message :inspect)
+ &rest _)
+ (declare (ignore _))
+ (encode-message event socket-io))))
+
+(defun spawn-threads-for-connection (connection)
+ (macrolet ((without-debugger-hook (&body body)
+ `(call-with-debugger-hook nil (lambda () , at body))))
+ (let* ((socket-io (connection.socket-io connection))
+ (control-thread (spawn (lambda ()
+ (without-debugger-hook
+ (dispatch-loop socket-io connection)))
+ :name "control-thread")))
+ (setf (connection.control-thread connection) control-thread)
+ (let ((reader-thread (spawn (lambda ()
+ (let ((go (receive)))
+ (assert (eq go 'accept-input)))
+ (without-debugger-hook
+ (read-loop control-thread socket-io
+ connection)))
+ :name "reader-thread"))
+ (repl-thread (spawn-repl-thread connection "repl-thread")))
+ (setf (connection.repl-thread connection) repl-thread)
+ (setf (connection.reader-thread connection) reader-thread)
+ (send reader-thread 'accept-input)
+ connection))))
+
+(defun cleanup-connection-threads (connection)
+ (let ((threads (list (connection.repl-thread connection)
+ (connection.reader-thread connection)
+ (connection.control-thread connection))))
+ (dolist (thread threads)
+ (when (and thread
+ (thread-alive-p thread)
+ (not (equal (current-thread) thread)))
+ (kill-thread thread)))))
+
+(defun repl-loop (connection)
+ (loop (handle-request connection)))
+
+(defun process-available-input (stream fn)
+ (loop while (input-available-p stream)
+ do (funcall fn)))
+
+(defun input-available-p (stream)
+ ;; return true iff we can read from STREAM without waiting or if we
+ ;; hit EOF
+ (let ((c (read-char-no-hang stream nil :eof)))
+ (cond ((not c) nil)
+ ((eq c :eof) t)
+ (t
+ (unread-char c stream)
+ t))))
+
+;;;;;; Signal driven IO
+
+(defun install-sigio-handler (connection)
+ (let ((client (connection.socket-io connection)))
+ (flet ((handler ()
+ (cond ((null *swank-state-stack*)
+ (with-reader-error-handler (connection)
+ (process-available-input
+ client (lambda () (handle-request connection)))))
+ ((eq (car *swank-state-stack*) :read-next-form))
+ (t (process-available-input client #'read-from-emacs)))))
+ (add-sigio-handler client #'handler)
+ (handler))))
+
+(defun deinstall-sigio-handler (connection)
+ (remove-sigio-handlers (connection.socket-io connection)))
+
+;;;;;; SERVE-EVENT based IO
+
+(defun install-fd-handler (connection)
+ (let ((client (connection.socket-io connection)))
+ (flet ((handler ()
+ (cond ((null *swank-state-stack*)
+ (with-reader-error-handler (connection)
+ (process-available-input
+ client (lambda () (handle-request connection)))))
+ ((eq (car *swank-state-stack*) :read-next-form))
+ (t
+ (process-available-input client #'read-from-emacs)))))
+ ;;;; handle sigint
+ ;;(install-debugger-globally
+ ;; (lambda (c h)
+ ;; (with-reader-error-handler (connection)
+ ;; (block debugger
+ ;; (with-connection (connection)
+ ;; (swank-debugger-hook c h)
+ ;; (return-from debugger))
+ ;; (abort)))))
+ (add-fd-handler client #'handler)
+ (handler))))
+
+(defun deinstall-fd-handler (connection)
+ (remove-fd-handlers (connection.socket-io connection)))
+
+;;;;;; Simple sequential IO
+
+(defun simple-serve-requests (connection)
+ (unwind-protect
+ (with-simple-restart (close-connection "Close SLIME connection")
+ (with-reader-error-handler (connection)
+ (loop
+ (handle-request connection))))
+ (close-connection connection)))
+
+(defun read-from-socket-io ()
+ (let ((event (decode-message (current-socket-io))))
+ (log-event "DISPATCHING: ~S~%" event)
+ (destructure-case event
+ ((:emacs-rex form package thread id)
+ (declare (ignore thread))
+ `(eval-for-emacs ,form ,package ,id))
+ ((:emacs-interrupt thread)
+ (declare (ignore thread))
+ '(simple-break))
+ ((:emacs-return-string thread tag string)
+ (declare (ignore thread))
+ `(take-input ,tag ,string))
+ ((:emacs-return thread tag value)
+ (declare (ignore thread))
+ `(take-input ,tag ,value)))))
+
+(defun send-to-socket-io (event)
+ (log-event "DISPATCHING: ~S~%" event)
+ (flet ((send (o)
+ (without-interrupts
+ (encode-message o (current-socket-io)))))
+ (destructure-case event
+ (((:debug-activate :debug :debug-return :read-string :read-aborted
+ :y-or-n-p :eval)
+ thread &rest args)
+ (declare (ignore thread))
+ (send `(,(car event) 0 , at args)))
+ ((:return thread &rest args)
+ (declare (ignore thread))
+ (send `(:return , at args)))
+ (((:write-string :new-package :new-features :debug-condition
+ :presentation-start :presentation-end
+ :indentation-update :ed :%apply :eval-no-wait
+ :background-message :inspect)
+ &rest _)
+ (declare (ignore _))
+ (send event)))))
+
+(defun initialize-streams-for-connection (connection)
+ (multiple-value-bind (dedicated in out io repl-results)
+ (open-streams connection)
+ (setf (connection.dedicated-output connection) dedicated
+ (connection.user-io connection) io
+ (connection.user-output connection) out
+ (connection.user-input connection) in
+ (connection.repl-results connection) repl-results)
+ connection))
+
+(defun create-connection (socket-io style)
+ (let ((success nil))
+ (unwind-protect
+ (let ((c (ecase style
+ (:spawn
+ (make-connection :socket-io socket-io
+ :read #'read-from-control-thread
+ :send #'send-to-control-thread
+ :serve-requests #'spawn-threads-for-connection
+ :cleanup #'cleanup-connection-threads))
+ (:sigio
+ (make-connection :socket-io socket-io
+ :read #'read-from-socket-io
+ :send #'send-to-socket-io
+ :serve-requests #'install-sigio-handler
+ :cleanup #'deinstall-sigio-handler))
+ (:fd-handler
+ (make-connection :socket-io socket-io
+ :read #'read-from-socket-io
+ :send #'send-to-socket-io
+ :serve-requests #'install-fd-handler
+ :cleanup #'deinstall-fd-handler))
+ ((nil)
+ (make-connection :socket-io socket-io
+ :read #'read-from-socket-io
+ :send #'send-to-socket-io
+ :serve-requests #'simple-serve-requests)))))
+ (setf (connection.communication-style c) style)
+ (initialize-streams-for-connection c)
+ (setf success t)
+ c)
+ (unless success
+ (close socket-io :abort t)))))
+
+
+;;;; IO to Emacs
+;;;
+;;; This code handles redirection of the standard I/O streams
+;;; (`*standard-output*', etc) into Emacs. The `connection' structure
+;;; contains the appropriate streams, so all we have to do is make the
+;;; right bindings.
+
+;;;;; Global I/O redirection framework
+;;;
+;;; Optionally, the top-level global bindings of the standard streams
+;;; can be assigned to be redirected to Emacs. When Emacs connects we
+;;; redirect the streams into the connection, and they keep going into
+;;; that connection even if more are established. If the connection
+;;; handling the streams closes then another is chosen, or if there
+;;; are no connections then we revert to the original (real) streams.
+;;;
+;;; It is slightly tricky to assign the global values of standard
+;;; streams because they are often shadowed by dynamic bindings. We
+;;; solve this problem by introducing an extra indirection via synonym
+;;; streams, so that *STANDARD-INPUT* is a synonym stream to
+;;; *CURRENT-STANDARD-INPUT*, etc. We never shadow the "current"
+;;; variables, so they can always be assigned to affect a global
+;;; change.
+
+(defvar *globally-redirect-io* nil
+ "When non-nil globally redirect all standard streams to Emacs.")
+
+;;;;; Global redirection setup
+
+(defvar *saved-global-streams* '()
+ "A plist to save and restore redirected stream objects.
+E.g. the value for '*standard-output* holds the stream object
+for *standard-output* before we install our redirection.")
+
+(defun setup-stream-indirection (stream-var &optional stream)
+ "Setup redirection scaffolding for a global stream variable.
+Supposing (for example) STREAM-VAR is *STANDARD-INPUT*, this macro:
+
+1. Saves the value of *STANDARD-INPUT* in `*SAVED-GLOBAL-STREAMS*'.
+
+2. Creates *CURRENT-STANDARD-INPUT*, initially with the same value as
+*STANDARD-INPUT*.
+
+3. Assigns *STANDARD-INPUT* to a synonym stream pointing to
+*CURRENT-STANDARD-INPUT*.
+
+This has the effect of making *CURRENT-STANDARD-INPUT* contain the
+effective global value for *STANDARD-INPUT*. This way we can assign
+the effective global value even when *STANDARD-INPUT* is shadowed by a
+dynamic binding."
+ (let ((current-stream-var (prefixed-var '#:current stream-var))
+ (stream (or stream (symbol-value stream-var))))
+ ;; Save the real stream value for the future.
+ (setf (getf *saved-global-streams* stream-var) stream)
+ ;; Define a new variable for the effective stream.
+ ;; This can be reassigned.
+ (proclaim `(special ,current-stream-var))
+ (set current-stream-var stream)
+ ;; Assign the real binding as a synonym for the current one.
+ (set stream-var (make-synonym-stream current-stream-var))))
+
+(defun prefixed-var (prefix variable-symbol)
+ "(PREFIXED-VAR \"FOO\" '*BAR*) => SWANK::*FOO-BAR*"
+ (let ((basename (subseq (symbol-name variable-symbol) 1)))
+ (intern (format nil "*~A-~A" (string prefix) basename) :swank)))
+
+(defvar *standard-output-streams*
+ '(*standard-output* *error-output* *trace-output*)
+ "The symbols naming standard output streams.")
+
+(defvar *standard-input-streams*
+ '(*standard-input*)
+ "The symbols naming standard input streams.")
+
+(defvar *standard-io-streams*
+ '(*debug-io* *query-io* *terminal-io*)
+ "The symbols naming standard io streams.")
+
+(defun init-global-stream-redirection ()
+ (when *globally-redirect-io*
+ (mapc #'setup-stream-indirection
+ (append *standard-output-streams*
+ *standard-input-streams*
+ *standard-io-streams*))))
+
+(add-hook *after-init-hook* 'init-global-stream-redirection)
+
+(defun globally-redirect-io-to-connection (connection)
+ "Set the standard I/O streams to redirect to CONNECTION.
+Assigns *CURRENT-<STREAM>* for all standard streams."
+ (dolist (o *standard-output-streams*)
+ (set (prefixed-var '#:current o)
+ (connection.user-output connection)))
+ ;; FIXME: If we redirect standard input to Emacs then we get the
+ ;; regular Lisp top-level trying to read from our REPL.
+ ;;
+ ;; Perhaps the ideal would be for the real top-level to run in a
+ ;; thread with local bindings for all the standard streams. Failing
+ ;; that we probably would like to inhibit it from reading while
+ ;; Emacs is connected.
+ ;;
+ ;; Meanwhile we just leave *standard-input* alone.
+ #+NIL
+ (dolist (i *standard-input-streams*)
+ (set (prefixed-var '#:current i)
+ (connection.user-input connection)))
+ (dolist (io *standard-io-streams*)
+ (set (prefixed-var '#:current io)
+ (connection.user-io connection))))
+
+(defun revert-global-io-redirection ()
+ "Set *CURRENT-<STREAM>* to *REAL-<STREAM>* for all standard streams."
+ (dolist (stream-var (append *standard-output-streams*
+ *standard-input-streams*
+ *standard-io-streams*))
+ (set (prefixed-var '#:current stream-var)
+ (getf *saved-global-streams* stream-var))))
+
+;;;;; Global redirection hooks
+
+(defvar *global-stdio-connection* nil
+ "The connection to which standard I/O streams are globally redirected.
+NIL if streams are not globally redirected.")
+
+(defun maybe-redirect-global-io (connection)
+ "Consider globally redirecting to a newly-established CONNECTION."
+ (when (and *globally-redirect-io* (null *global-stdio-connection*))
+ (setq *global-stdio-connection* connection)
+ (globally-redirect-io-to-connection connection)))
+
+(defun update-redirection-after-close (closed-connection)
+ "Update redirection after a connection closes."
+ (check-type closed-connection connection)
+ (when (eq *global-stdio-connection* closed-connection)
+ (if (and (default-connection) *globally-redirect-io*)
+ ;; Redirect to another connection.
+ (globally-redirect-io-to-connection (default-connection))
+ ;; No more connections, revert to the real streams.
+ (progn (revert-global-io-redirection)
+ (setq *global-stdio-connection* nil)))))
+
+(add-hook *new-connection-hook* 'maybe-redirect-global-io)
+(add-hook *connection-closed-hook* 'update-redirection-after-close)
+
+;;;;; Redirection during requests
+;;;
+;;; We always redirect the standard streams to Emacs while evaluating
+;;; an RPC. This is done with simple dynamic bindings.
+
+(defun call-with-redirected-io (connection function)
+ "Call FUNCTION with I/O streams redirected via CONNECTION."
+ (declare (type function function))
+ (let* ((io (connection.user-io connection))
+ (in (connection.user-input connection))
+ (out (connection.user-output connection))
+ (trace (or (connection.trace-output connection) out))
+ (*standard-output* out)
+ (*error-output* out)
+ (*trace-output* trace)
+ (*debug-io* io)
+ (*query-io* io)
+ (*standard-input* in)
+ (*terminal-io* io))
+ (funcall function)))
+
+(defun read-from-emacs ()
+ "Read and process a request from Emacs."
+ (apply #'funcall (funcall (connection.read *emacs-connection*))))
+
+(defun read-from-control-thread ()
+ (receive))
+
+(defun decode-message (stream)
+ "Read an S-expression from STREAM using the SLIME protocol."
+ (let ((*swank-state-stack* (cons :read-next-form *swank-state-stack*)))
+ (handler-bind ((error (lambda (c) (error (make-swank-error c)))))
+ (let* ((length (decode-message-length stream))
+ (string (make-string length))
+ (pos (read-sequence string stream)))
+ (assert (= pos length) ()
+ "Short read: length=~D pos=~D" length pos)
+ (log-event "READ: ~S~%" string)
+ (read-form string)))))
+
+(defun decode-message-length (stream)
+ (let ((buffer (make-string 6)))
+ (dotimes (i 6)
+ (setf (aref buffer i) (read-char stream)))
+ (parse-integer buffer :radix #x10)))
+
+(defun read-form (string)
+ (with-standard-io-syntax
+ (let ((*package* *swank-io-package*))
+ (read-from-string string))))
+
+(defvar *slime-features* nil
+ "The feature list that has been sent to Emacs.")
+
+(defun send-to-emacs (object)
+ "Send OBJECT to Emacs."
+ (funcall (connection.send *emacs-connection*) object))
+
+(defun send-oob-to-emacs (object)
+ (send-to-emacs object))
+
+(defun send-to-control-thread (object)
+ (send (connection.control-thread *emacs-connection*) object))
+
+(defun encode-message (message stream)
+ (let* ((string (prin1-to-string-for-emacs message))
+ (length (length string)))
+ (log-event "WRITE: ~A~%" string)
+ (let ((*print-pretty* nil))
+ (format stream "~6,'0x" length))
+ (write-string string stream)
+ ;;(terpri stream)
+ (finish-output stream)))
+
+(defun prin1-to-string-for-emacs (object)
+ (with-standard-io-syntax
+ (let ((*print-case* :downcase)
+ (*print-readably* nil)
+ (*print-pretty* nil)
+ (*package* *swank-io-package*))
+ (prin1-to-string object))))
+
+(defun force-user-output ()
+ (force-output (connection.user-io *emacs-connection*))
+ (finish-output (connection.user-output *emacs-connection*)))
+
+(defun clear-user-input ()
+ (clear-input (connection.user-input *emacs-connection*)))
+
+(defvar *read-input-catch-tag* 0)
+
+(defun intern-catch-tag (tag)
+ ;; fixnums aren't eq in ABCL, so we use intern to create tags
+ (intern (format nil "~D" tag) :swank))
+
+(defun read-user-input-from-emacs ()
+ (let ((tag (incf *read-input-catch-tag*)))
+ (force-output)
+ (send-to-emacs `(:read-string ,(current-thread) ,tag))
+ (let ((ok nil))
+ (unwind-protect
+ (prog1 (catch (intern-catch-tag tag)
+ (loop (read-from-emacs)))
+ (setq ok t))
+ (unless ok
+ (send-to-emacs `(:read-aborted ,(current-thread) ,tag)))))))
+
+(defun y-or-n-p-in-emacs (format-string &rest arguments)
+ "Like y-or-n-p, but ask in the Emacs minibuffer."
+ (let ((tag (incf *read-input-catch-tag*))
+ (question (apply #'format nil format-string arguments)))
+ (force-output)
+ (send-to-emacs `(:y-or-n-p ,(current-thread) ,tag ,question))
+ (catch (intern-catch-tag tag)
+ (loop (read-from-emacs)))))
+
+(defslimefun take-input (tag input)
+ "Return the string INPUT to the continuation TAG."
+ (throw (intern-catch-tag tag) input))
+
+(defun process-form-for-emacs (form)
+ "Returns a string which emacs will read as equivalent to
+FORM. FORM can contain lists, strings, characters, symbols and
+numbers.
+
+Characters are converted emacs' ?<char> notaion, strings are left
+as they are (except for espacing any nested \" chars, numbers are
+printed in base 10 and symbols are printed as their symbol-name
+converted to lower case."
+ (etypecase form
+ (string (format nil "~S" form))
+ (cons (format nil "(~A . ~A)"
+ (process-form-for-emacs (car form))
+ (process-form-for-emacs (cdr form))))
+ (character (format nil "?~C" form))
+ (symbol (concatenate 'string (when (eq (symbol-package form)
+ #.(find-package "KEYWORD"))
+ ":")
+ (string-downcase (symbol-name form))))
+ (number (let ((*print-base* 10))
+ (princ-to-string form)))))
+
+(defun eval-in-emacs (form &optional nowait)
+ "Eval FORM in Emacs."
+ (cond (nowait
+ (send-to-emacs `(:eval-no-wait ,(process-form-for-emacs form))))
+ (t
+ (force-output)
+ (let* ((tag (incf *read-input-catch-tag*))
+ (value (catch (intern-catch-tag tag)
+ (send-to-emacs
+ `(:eval ,(current-thread) ,tag
+ ,(process-form-for-emacs form)))
+ (loop (read-from-emacs)))))
+ (destructure-case value
+ ((:ok value) value)
+ ((:abort) (abort)))))))
+
+(defvar *swank-wire-protocol-version* nil
+ "The version of the swank/slime communication protocol.")
+
+(defslimefun connection-info ()
+ "Return a key-value list of the form:
+\(&key PID STYLE LISP-IMPLEMENTATION MACHINE FEATURES PACKAGE VERSION)
+PID: is the process-id of Lisp process (or nil, depending on the STYLE)
+STYLE: the communication style
+LISP-IMPLEMENTATION: a list (&key TYPE NAME VERSION)
+FEATURES: a list of keywords
+PACKAGE: a list (&key NAME PROMPT)
+VERSION: the protocol version"
+ (setq *slime-features* *features*)
+ `(:pid ,(getpid) :style ,(connection.communication-style *emacs-connection*)
+ :lisp-implementation (:type ,(lisp-implementation-type)
+ :name ,(lisp-implementation-type-name)
+ :version ,(lisp-implementation-version))
+ :machine (:instance ,(machine-instance)
+ :type ,(machine-type)
+ :version ,(machine-version))
+ :features ,(features-for-emacs)
+ :modules ,*modules*
+ :package (:name ,(package-name *package*)
+ :prompt ,(package-string-for-prompt *package*))
+ :version ,*swank-wire-protocol-version*))
+
+(defslimefun io-speed-test (&optional (n 5000) (m 1))
+ (let* ((s *standard-output*)
+ (*trace-output* (make-broadcast-stream s *log-output*)))
+ (time (progn
+ (dotimes (i n)
+ (format s "~D abcdefghijklm~%" i)
+ (when (zerop (mod n m))
+ (force-output s)))
+ (finish-output s)
+ (when *emacs-connection*
+ (eval-in-emacs '(message "done.")))))
+ (terpri *trace-output*)
+ (finish-output *trace-output*)
+ nil))
+
+
+;;;; Reading and printing
+
+(defmacro define-special (name doc)
+ "Define a special variable NAME with doc string DOC.
+This is like defvar, but NAME will not be initialized."
+ `(progn
+ (defvar ,name)
+ (setf (documentation ',name 'variable) ,doc)))
+
+(define-special *buffer-package*
+ "Package corresponding to slime-buffer-package.
+
+EVAL-FOR-EMACS binds *buffer-package*. Strings originating from a slime
+buffer are best read in this package. See also FROM-STRING and TO-STRING.")
+
+(define-special *buffer-readtable*
+ "Readtable associated with the current buffer")
+
+(defmacro with-buffer-syntax ((&rest _) &body body)
+ "Execute BODY with appropriate *package* and *readtable* bindings.
+
+This should be used for code that is conceptionally executed in an
+Emacs buffer."
+ (destructuring-bind () _
+ `(call-with-buffer-syntax (lambda () , at body))))
+
+(defun call-with-buffer-syntax (fun)
+ (let ((*package* *buffer-package*))
+ ;; Don't shadow *readtable* unnecessarily because that prevents
+ ;; the user from assigning to it.
+ (if (eq *readtable* *buffer-readtable*)
+ (call-with-syntax-hooks fun)
+ (let ((*readtable* *buffer-readtable*))
+ (call-with-syntax-hooks fun)))))
+
+(defun to-string (object)
+ "Write OBJECT in the *BUFFER-PACKAGE*.
+The result may not be readable. Handles problems with PRINT-OBJECT methods
+gracefully."
+ (with-buffer-syntax ()
+ (let ((*print-readably* nil))
+ (handler-case
+ (prin1-to-string object)
+ (error ()
+ (with-output-to-string (s)
+ (print-unreadable-object (object s :type t :identity t)
+ (princ "<<error printing object>>" s))))))))
+
+(defun from-string (string)
+ "Read string in the *BUFFER-PACKAGE*"
+ (with-buffer-syntax ()
+ (let ((*read-suppress* nil))
+ (read-from-string string))))
+
+(defun read-softly-from-string (string)
+ "Returns three values:
+
+ 1. the object resulting from READing STRING.
+
+ 2. The index of the first character in STRING that was not read.
+
+ 3. T if the object is a symbol that had to be newly interned
+ in some package. (This does not work for symbols in
+ compound forms like lists or vectors.)"
+ (multiple-value-bind (symbol found? symbol-name package) (parse-symbol string)
+ (if found?
+ (values symbol (length string) nil)
+ (multiple-value-bind (sexp pos) (read-from-string string)
+ (values sexp pos
+ (when (symbolp sexp)
+ (prog1 t
+ ;; assert that PARSE-SYMBOL didn't parse incorrectly.
+ (assert (and (equal symbol-name (symbol-name sexp))
+ (eq package (symbol-package sexp)))))))))))
+
+(defun unintern-in-home-package (symbol)
+ (unintern symbol (symbol-package symbol)))
+
+;; FIXME: deal with #\| etc. hard to do portably.
+(defun tokenize-symbol (string)
+ "STRING is interpreted as the string representation of a symbol
+and is tokenized accordingly. The result is returned in three
+values: The package identifier part, the actual symbol identifier
+part, and a flag if the STRING represents a symbol that is
+internal to the package identifier part. (Notice that the flag is
+also true with an empty package identifier part, as the STRING is
+considered to represent a symbol internal to some current package.)"
+ (let ((package (let ((pos (position #\: string)))
+ (if pos (subseq string 0 pos) nil)))
+ (symbol (let ((pos (position #\: string :from-end t)))
+ (if pos (subseq string (1+ pos)) string)))
+ (internp (not (= (count #\: string) 1))))
+ (values symbol package internp)))
+
+(defun tokenize-symbol-thoroughly (string)
+ "This version of TOKENIZE-SYMBOL handles escape characters."
+ (let ((package nil)
+ (token (make-array (length string) :element-type 'character
+ :fill-pointer 0))
+ (backslash nil)
+ (vertical nil)
+ (internp nil))
+ (loop for char across string
+ do (cond
+ (backslash
+ (vector-push-extend char token)
+ (setq backslash nil))
+ ((char= char #\\) ; Quotes next character, even within |...|
+ (setq backslash t))
+ ((char= char #\|)
+ (setq vertical t))
+ (vertical
+ (vector-push-extend char token))
+ ((char= char #\:)
+ (if package
+ (setq internp t)
+ (setq package token
+ token (make-array (length string)
+ :element-type 'character
+ :fill-pointer 0))))
+ (t
+ (vector-push-extend (casify-char char) token))))
+ (values token package (or (not package) internp))))
+
+(defun untokenize-symbol (package-name internal-p symbol-name)
+ "The inverse of TOKENIZE-SYMBOL.
+
+ (untokenize-symbol \"quux\" nil \"foo\") ==> \"quux:foo\"
+ (untokenize-symbol \"quux\" t \"foo\") ==> \"quux::foo\"
+ (untokenize-symbol nil nil \"foo\") ==> \"foo\"
+"
+ (cond ((not package-name) symbol-name)
+ (internal-p (cat package-name "::" symbol-name))
+ (t (cat package-name ":" symbol-name))))
+
+(defun casify-char (char)
+ "Convert CHAR accoring to readtable-case."
+ (ecase (readtable-case *readtable*)
+ (:preserve char)
+ (:upcase (char-upcase char))
+ (:downcase (char-downcase char))
+ (:invert (if (upper-case-p char)
+ (char-downcase char)
+ (char-upcase char)))))
+
+(defun parse-symbol (string &optional (package *package*))
+ "Find the symbol named STRING.
+Return the symbol and a flag indicating whether the symbols was found."
+ (multiple-value-bind (sname pname) (tokenize-symbol-thoroughly string)
+ (let ((package (cond ((string= pname "") keyword-package)
+ (pname (find-package pname))
+ (t package))))
+ (if package
+ (multiple-value-bind (symbol flag) (find-symbol sname package)
+ (values symbol flag sname package))
+ (values nil nil nil nil)))))
+
+(defun parse-symbol-or-lose (string &optional (package *package*))
+ (multiple-value-bind (symbol status) (parse-symbol string package)
+ (if status
+ (values symbol status)
+ (error "Unknown symbol: ~A [in ~A]" string package))))
+
+(defun parse-package (string)
+ "Find the package named STRING.
+Return the package or nil."
+ ;; STRING comes usually from a (in-package STRING) form.
+ (ignore-errors
+ (find-package (let ((*package* *swank-io-package*))
+ (read-from-string string)))))
+
+(defun unparse-name (string)
+ "Print the name STRING according to the current printer settings."
+ ;; this is intended for package or symbol names
+ (subseq (prin1-to-string (make-symbol string)) 2))
+
+(defun guess-package (string)
+ "Guess which package corresponds to STRING.
+Return nil if no package matches."
+ (or (find-package string)
+ (parse-package string)
+ (if (find #\! string) ; for SBCL
+ (guess-package (substitute #\- #\! string)))))
+
+(defvar *readtable-alist* (default-readtable-alist)
+ "An alist mapping package names to readtables.")
+
+(defun guess-buffer-readtable (package-name)
+ (let ((package (guess-package package-name)))
+ (or (and package
+ (cdr (assoc (package-name package) *readtable-alist*
+ :test #'string=)))
+ *readtable*)))
+
+
+;;;; Evaluation
+
+(defvar *pending-continuations* '()
+ "List of continuations for Emacs. (thread local)")
+
+(defun guess-buffer-package (string)
+ "Return a package for STRING.
+Fall back to the the current if no such package exists."
+ (or (and string (guess-package string))
+ *package*))
+
+(defun eval-for-emacs (form buffer-package id)
+ "Bind *BUFFER-PACKAGE* to BUFFER-PACKAGE and evaluate FORM.
+Return the result to the continuation ID.
+Errors are trapped and invoke our debugger."
+ (call-with-debugger-hook
+ #'swank-debugger-hook
+ (lambda ()
+ (let (ok result)
+ (unwind-protect
+ (let ((*buffer-package* (guess-buffer-package buffer-package))
+ (*buffer-readtable* (guess-buffer-readtable buffer-package))
+ (*pending-continuations* (cons id *pending-continuations*)))
+ (check-type *buffer-package* package)
+ (check-type *buffer-readtable* readtable)
+ ;; APPLY would be cleaner than EVAL.
+ ;;(setq result (apply (car form) (cdr form)))
+ (setq result (eval form))
+ (run-hook *pre-reply-hook*)
+ (finish-output)
+ (setq ok t))
+ (force-user-output)
+ (send-to-emacs `(:return ,(current-thread)
+ ,(if ok
+ `(:ok ,result)
+ `(:abort))
+ ,id)))))))
+
+(defvar *echo-area-prefix* "=> "
+ "A prefix that `format-values-for-echo-area' should use.")
+
+(defun format-values-for-echo-area (values)
+ (with-buffer-syntax ()
+ (let ((*print-readably* nil))
+ (cond ((null values) "; No value")
+ ((and (length= values 1) (integerp (car values)))
+ (let ((i (car values)))
+ (format nil "~A~D (#x~X, #o~O, #b~B)"
+ *echo-area-prefix* i i i i)))
+ (t (format nil "~a~{~S~^, ~}" *echo-area-prefix* values))))))
+
+(defslimefun interactive-eval (string)
+ (with-buffer-syntax ()
+ (let ((values (multiple-value-list (eval (from-string string)))))
+ (fresh-line)
+ (finish-output)
+ (format-values-for-echo-area values))))
+
+(defslimefun eval-and-grab-output (string)
+ (with-buffer-syntax ()
+ (let* ((s (make-string-output-stream))
+ (*standard-output* s)
+ (values (multiple-value-list (eval (from-string string)))))
+ (list (get-output-stream-string s)
+ (format nil "~{~S~^~%~}" values)))))
+
+(defun eval-region (string)
+ "Evaluate STRING.
+Return the results of the last form as a list and as secondary value the
+last form."
+ (with-input-from-string (stream string)
+ (let (- values)
+ (loop
+ (let ((form (read stream nil stream)))
+ (when (eq form stream)
+ (return (values values -)))
+ (setq - form)
+ (setq values (multiple-value-list (eval form)))
+ (finish-output))))))
+
+(defslimefun interactive-eval-region (string)
+ (with-buffer-syntax ()
+ (format-values-for-echo-area (eval-region string))))
+
+(defslimefun re-evaluate-defvar (form)
+ (with-buffer-syntax ()
+ (let ((form (read-from-string form)))
+ (destructuring-bind (dv name &optional value doc) form
+ (declare (ignore value doc))
+ (assert (eq dv 'defvar))
+ (makunbound name)
+ (prin1-to-string (eval form))))))
+
+(defvar *swank-pprint-bindings*
+ `((*print-pretty* . t)
+ (*print-level* . nil)
+ (*print-length* . nil)
+ (*print-circle* . t)
+ (*print-gensym* . t)
+ (*print-readably* . nil))
+ "A list of variables bindings during pretty printing.
+Used by pprint-eval.")
+
+(defun swank-pprint (list)
+ "Bind some printer variables and pretty print each object in LIST."
+ (with-buffer-syntax ()
+ (with-bindings *swank-pprint-bindings*
+ (cond ((null list) "; No value")
+ (t (with-output-to-string (*standard-output*)
+ (dolist (o list)
+ (pprint o)
+ (terpri))))))))
+
+(defslimefun pprint-eval (string)
+ (with-buffer-syntax ()
+ (swank-pprint (multiple-value-list (eval (read-from-string string))))))
+
+(defslimefun set-package (name)
+ "Set *package* to the package named NAME.
+Return the full package-name and the string to use in the prompt."
+ (let ((p (guess-package name)))
+ (assert (packagep p))
+ (setq *package* p)
+ (list (package-name p) (package-string-for-prompt p))))
+
+;;;;; Listener eval
+
+(defvar *listener-eval-function* 'repl-eval)
+
+(defslimefun listener-eval (string)
+ (funcall *listener-eval-function* string))
+
+(defvar *send-repl-results-function* 'send-repl-results-to-emacs)
+
+(defun repl-eval (string)
+ (clear-user-input)
+ (with-buffer-syntax ()
+ (track-package
+ (lambda ()
+ (multiple-value-bind (values last-form) (eval-region string)
+ (setq *** ** ** * * (car values)
+ /// // // / / values
+ +++ ++ ++ + + last-form)
+ (funcall *send-repl-results-function* values)))))
+ nil)
+
+(defun track-package (fun)
+ (let ((p *package*))
+ (unwind-protect (funcall fun)
+ (unless (eq *package* p)
+ (send-to-emacs (list :new-package (package-name *package*)
+ (package-string-for-prompt *package*)))))))
+
+(defun send-repl-results-to-emacs (values)
+ (fresh-line)
+ (finish-output)
+ (if (null values)
+ (send-to-emacs `(:write-string "; No value" :repl-result))
+ (dolist (v values)
+ (send-to-emacs `(:write-string ,(cat (prin1-to-string v) #\newline)
+ :repl-result)))))
+
+(defun cat (&rest strings)
+ "Concatenate all arguments and make the result a string."
+ (with-output-to-string (out)
+ (dolist (s strings)
+ (etypecase s
+ (string (write-string s out))
+ (character (write-char s out))))))
+
+(defun package-string-for-prompt (package)
+ "Return the shortest nickname (or canonical name) of PACKAGE."
+ (unparse-name
+ (or (canonical-package-nickname package)
+ (auto-abbreviated-package-name package)
+ (shortest-package-nickname package))))
+
+(defun canonical-package-nickname (package)
+ "Return the canonical package nickname, if any, of PACKAGE."
+ (let ((name (cdr (assoc (package-name package) *canonical-package-nicknames*
+ :test #'string=))))
+ (and name (string name))))
+
+(defun auto-abbreviated-package-name (package)
+ "Return an abbreviated 'name' for PACKAGE.
+
+N.B. this is not an actual package name or nickname."
+ (when *auto-abbreviate-dotted-packages*
+ (let ((last-dot (position #\. (package-name package) :from-end t)))
+ (when last-dot (subseq (package-name package) (1+ last-dot))))))
+
+(defun shortest-package-nickname (package)
+ "Return the shortest nickname (or canonical name) of PACKAGE."
+ (loop for name in (cons (package-name package) (package-nicknames package))
+ for shortest = name then (if (< (length name) (length shortest))
+ name
+ shortest)
+ finally (return shortest)))
+
+(defslimefun ed-in-emacs (&optional what)
+ "Edit WHAT in Emacs.
+
+WHAT can be:
+ A pathname or a string,
+ A list (PATHNAME-OR-STRING LINE [COLUMN]),
+ A function name (symbol or cons),
+ NIL.
+
+Returns true if it actually called emacs, or NIL if not."
+ (flet ((pathname-or-string-p (thing)
+ (or (pathnamep thing) (typep thing 'string))))
+ (let ((target
+ (cond ((and (listp what) (pathname-or-string-p (first what)))
+ (cons (canonicalize-filename (car what)) (cdr what)))
+ ((pathname-or-string-p what)
+ (canonicalize-filename what))
+ ((symbolp what) what)
+ ((consp what) what)
+ (t (return-from ed-in-emacs nil)))))
+ (cond
+ (*emacs-connection* (send-oob-to-emacs `(:ed ,target)))
+ ((default-connection)
+ (with-connection ((default-connection))
+ (send-oob-to-emacs `(:ed ,target))))
+ (t nil)))))
+
+(defslimefun inspect-in-emacs (what)
+ "Inspect WHAT in Emacs."
+ (flet ((send-it ()
+ (with-buffer-syntax ()
+ (reset-inspector)
+ (send-oob-to-emacs `(:inspect ,(inspect-object what))))))
+ (cond
+ (*emacs-connection*
+ (send-it))
+ ((default-connection)
+ (with-connection ((default-connection))
+ (send-it))))
+ what))
+
+(defslimefun value-for-editing (form)
+ "Return a readable value of FORM for editing in Emacs.
+FORM is expected, but not required, to be SETF'able."
+ ;; FIXME: Can we check FORM for setfability? -luke (12/Mar/2005)
+ (with-buffer-syntax ()
+ (prin1-to-string (eval (read-from-string form)))))
+
+(defslimefun commit-edited-value (form value)
+ "Set the value of a setf'able FORM to VALUE.
+FORM and VALUE are both strings from Emacs."
+ (with-buffer-syntax ()
+ (eval `(setf ,(read-from-string form)
+ ,(read-from-string (concatenate 'string "`" value))))
+ t))
+
+(defun background-message (format-string &rest args)
+ "Display a message in Emacs' echo area.
+
+Use this function for informative messages only. The message may even
+be dropped, if we are too busy with other things."
+ (when *emacs-connection*
+ (send-to-emacs `(:background-message
+ ,(apply #'format nil format-string args)))))
+
+
+;;;; Debugger
+
+(defun swank-debugger-hook (condition hook)
+ "Debugger function for binding *DEBUGGER-HOOK*.
+Sends a message to Emacs declaring that the debugger has been entered,
+then waits to handle further requests from Emacs. Eventually returns
+after Emacs causes a restart to be invoked."
+ (declare (ignore hook))
+ (cond (*emacs-connection*
+ (debug-in-emacs condition))
+ ((default-connection)
+ (with-connection ((default-connection))
+ (debug-in-emacs condition)))))
+
+(defvar *global-debugger* t
+ "Non-nil means the Swank debugger hook will be installed globally.")
+
+(add-hook *new-connection-hook* 'install-debugger)
+(defun install-debugger (connection)
+ (declare (ignore connection))
+ (when *global-debugger*
+ (install-debugger-globally #'swank-debugger-hook)))
+
+;;;;; Debugger loop
+;;;
+;;; These variables are dynamically bound during debugging.
+;;;
+(defvar *swank-debugger-condition* nil
+ "The condition being debugged.")
+
+(defvar *sldb-level* 0
+ "The current level of recursive debugging.")
+
+(defvar *sldb-initial-frames* 20
+ "The initial number of backtrace frames to send to Emacs.")
+
+(defvar *sldb-restarts* nil
+ "The list of currenlty active restarts.")
+
+(defvar *sldb-stepping-p* nil
+ "True during execution of a step command.")
+
+(defun debug-in-emacs (condition)
+ (let ((*swank-debugger-condition* condition)
+ (*sldb-restarts* (compute-sane-restarts condition))
+ (*package* (or (and (boundp '*buffer-package*)
+ (symbol-value '*buffer-package*))
+ *package*))
+ (*sldb-level* (1+ *sldb-level*))
+ (*sldb-stepping-p* nil)
+ (*swank-state-stack* (cons :swank-debugger-hook *swank-state-stack*)))
+ (force-user-output)
+ (call-with-debugging-environment
+ (lambda ()
+ (with-bindings *sldb-printer-bindings*
+ (sldb-loop *sldb-level*))))))
+
+(defun sldb-loop (level)
+ (unwind-protect
+ (catch 'sldb-enter-default-debugger
+ (send-to-emacs
+ (list* :debug (current-thread) level
+ (debugger-info-for-emacs 0 *sldb-initial-frames*)))
+ (loop (catch 'sldb-loop-catcher
+ (with-simple-restart (abort "Return to sldb level ~D." level)
+ (send-to-emacs (list :debug-activate (current-thread)
+ level))
+ (handler-bind ((sldb-condition #'handle-sldb-condition))
+ (read-from-emacs))))))
+ (send-to-emacs `(:debug-return
+ ,(current-thread) ,level ,*sldb-stepping-p*))))
+
+(defun handle-sldb-condition (condition)
+ "Handle an internal debugger condition.
+Rather than recursively debug the debugger (a dangerous idea!), these
+conditions are simply reported."
+ (let ((real-condition (original-condition condition)))
+ (send-to-emacs `(:debug-condition ,(current-thread)
+ ,(princ-to-string real-condition))))
+ (throw 'sldb-loop-catcher nil))
+
+(defun safe-condition-message (condition)
+ "Safely print condition to a string, handling any errors during
+printing."
+ (let ((*print-pretty* t) (*print-right-margin* 65))
+ (handler-case
+ (format-sldb-condition condition)
+ (error (cond)
+ ;; Beware of recursive errors in printing, so only use the condition
+ ;; if it is printable itself:
+ (format nil "Unable to display error condition~@[: ~A~]"
+ (ignore-errors (princ-to-string cond)))))))
+
+(defun debugger-condition-for-emacs ()
+ (list (safe-condition-message *swank-debugger-condition*)
+ (format nil " [Condition of type ~S]"
+ (type-of *swank-debugger-condition*))
+ (condition-extras *swank-debugger-condition*)))
+
+(defun format-restarts-for-emacs ()
+ "Return a list of restarts for *swank-debugger-condition* in a
+format suitable for Emacs."
+ (let ((*print-right-margin* most-positive-fixnum))
+ (loop for restart in *sldb-restarts*
+ collect (list (princ-to-string (restart-name restart))
+ (princ-to-string restart)))))
+
+
+;;;;; SLDB entry points
+
+(defslimefun sldb-break-with-default-debugger ()
+ "Invoke the default debugger by returning from our debugger-loop."
+ (throw 'sldb-enter-default-debugger nil))
+
+(defslimefun backtrace (start end)
+ "Return a list ((I FRAME) ...) of frames from START to END.
+I is an integer describing and FRAME a string."
+ (loop for frame in (compute-backtrace start end)
+ for i from start
+ collect (list i (with-output-to-string (stream)
+ (handler-case
+ (with-bindings *backtrace-printer-bindings*
+ (print-frame frame stream))
+ (t ()
+ (format stream "[error printing frame]")))))))
+
+(defslimefun debugger-info-for-emacs (start end)
+ "Return debugger state, with stack frames from START to END.
+The result is a list:
+ (condition ({restart}*) ({stack-frame}*) (cont*))
+where
+ condition ::= (description type [extra])
+ restart ::= (name description)
+ stack-frame ::= (number description)
+ extra ::= (:references and other random things)
+ cont ::= continutation
+condition---a pair of strings: message, and type. If show-source is
+not nil it is a frame number for which the source should be displayed.
+
+restart---a pair of strings: restart name, and description.
+
+stack-frame---a number from zero (the top), and a printed
+representation of the frame's call.
+
+continutation---the id of a pending Emacs continuation.
+
+Below is an example return value. In this case the condition was a
+division by zero (multi-line description), and only one frame is being
+fetched (start=0, end=1).
+
+ ((\"Arithmetic error DIVISION-BY-ZERO signalled.
+Operation was KERNEL::DIVISION, operands (1 0).\"
+ \"[Condition of type DIVISION-BY-ZERO]\")
+ ((\"ABORT\" \"Return to Slime toplevel.\")
+ (\"ABORT\" \"Return to Top-Level.\"))
+ ((0 \"(KERNEL::INTEGER-/-INTEGER 1 0)\"))
+ (4))"
+ (list (debugger-condition-for-emacs)
+ (format-restarts-for-emacs)
+ (backtrace start end)
+ *pending-continuations*))
+
+(defun nth-restart (index)
+ (nth index *sldb-restarts*))
+
+(defslimefun invoke-nth-restart (index)
+ (invoke-restart-interactively (nth-restart index)))
+
+(defslimefun sldb-abort ()
+ (invoke-restart (find 'abort *sldb-restarts* :key #'restart-name)))
+
+(defslimefun sldb-continue ()
+ (continue))
+
+(defslimefun throw-to-toplevel ()
+ "Invoke the ABORT-REQUEST restart abort an RPC from Emacs.
+If we are not evaluating an RPC then ABORT instead."
+ (let ((restart (find-restart *sldb-quit-restart*)))
+ (cond (restart (invoke-restart restart))
+ (t (format nil
+ "Restart not found: ~a"
+ *sldb-quit-restart*)))))
+
+(defslimefun invoke-nth-restart-for-emacs (sldb-level n)
+ "Invoke the Nth available restart.
+SLDB-LEVEL is the debug level when the request was made. If this
+has changed, ignore the request."
+ (when (= sldb-level *sldb-level*)
+ (invoke-nth-restart n)))
+
+(defun wrap-sldb-vars (form)
+ `(let ((*sldb-level* ,*sldb-level*))
+ ,form))
+
+(defslimefun eval-string-in-frame (string index)
+ (to-string (eval-in-frame (wrap-sldb-vars (from-string string))
+ index)))
+
+(defslimefun pprint-eval-string-in-frame (string index)
+ (swank-pprint
+ (multiple-value-list
+ (eval-in-frame (wrap-sldb-vars (from-string string)) index))))
+
+(defslimefun frame-locals-for-emacs (index)
+ "Return a property list ((&key NAME ID VALUE) ...) describing
+the local variables in the frame INDEX."
+ (with-bindings *backtrace-printer-bindings*
+ (mapcar (lambda (frame-locals)
+ (destructuring-bind (&key name id value) frame-locals
+ (list :name (prin1-to-string name) :id id
+ :value (to-string value))))
+ (frame-locals index))))
+
+(defslimefun frame-catch-tags-for-emacs (frame-index)
+ (mapcar #'to-string (frame-catch-tags frame-index)))
+
+(defslimefun sldb-disassemble (index)
+ (with-output-to-string (*standard-output*)
+ (disassemble-frame index)))
+
+(defslimefun sldb-return-from-frame (index string)
+ (let ((form (from-string string)))
+ (to-string (multiple-value-list (return-from-frame index form)))))
+
+(defslimefun sldb-break (name)
+ (with-buffer-syntax ()
+ (sldb-break-at-start (read-from-string name))))
+
+(defmacro define-stepper-function (name backend-function-name)
+ `(defslimefun ,name (frame)
+ (cond ((sldb-stepper-condition-p *swank-debugger-condition*)
+ (setq *sldb-stepping-p* t)
+ (,backend-function-name))
+ ((find-restart 'continue)
+ (activate-stepping frame)
+ (setq *sldb-stepping-p* t)
+ (continue))
+ (t
+ (error "Not currently single-stepping, and no continue restart available.")))))
+
+(define-stepper-function sldb-step sldb-step-into)
+(define-stepper-function sldb-next sldb-step-next)
+(define-stepper-function sldb-out sldb-step-out)
+
+
+;;;; Compilation Commands.
+
+(defvar *compiler-notes* '()
+ "List of compiler notes for the last compilation unit.")
+
+(defun clear-compiler-notes ()
+ (setf *compiler-notes* '()))
+
+(defun canonicalize-filename (filename)
+ (namestring (truename filename)))
+
+(defslimefun compiler-notes-for-emacs ()
+ "Return the list of compiler notes for the last compilation unit."
+ (reverse *compiler-notes*))
+
+(defun measure-time-interval (fn)
+ "Call FN and return the first return value and the elapsed time.
+The time is measured in microseconds."
+ (declare (type function fn))
+ (let ((before (get-internal-real-time)))
+ (values
+ (funcall fn)
+ (* (- (get-internal-real-time) before)
+ (/ 1000000 internal-time-units-per-second)))))
+
+(defun record-note-for-condition (condition)
+ "Record a note for a compiler-condition."
+ (push (make-compiler-note condition) *compiler-notes*))
+
+(defun make-compiler-note (condition)
+ "Make a compiler note data structure from a compiler-condition."
+ (declare (type compiler-condition condition))
+ (list* :message (message condition)
+ :severity (severity condition)
+ :location (location condition)
+ :references (references condition)
+ (let ((s (short-message condition)))
+ (if s (list :short-message s)))))
+
+(defun swank-compiler (function)
+ (clear-compiler-notes)
+ (multiple-value-bind (result usecs)
+ (with-simple-restart (abort "Abort SLIME compilation.")
+ (handler-bind ((compiler-condition #'record-note-for-condition))
+ (measure-time-interval function)))
+ ;; WITH-SIMPLE-RESTART returns (values nil t) if its restart is invoked;
+ ;; unfortunately the SWANK protocol doesn't support returning multiple
+ ;; values, so we gotta convert it explicitely to a list in either case.
+ (if (and (not result) (eq usecs 't))
+ (list nil nil)
+ (list (to-string result)
+ (format nil "~,2F" (/ usecs 1000000.0))))))
+
+(defslimefun compile-file-for-emacs (filename load-p)
+ "Compile FILENAME and, when LOAD-P, load the result.
+Record compiler notes signalled as `compiler-condition's."
+ (with-buffer-syntax ()
+ (let ((*compile-print* nil))
+ (swank-compiler
+ (lambda ()
+ (swank-compile-file filename load-p
+ (or (guess-external-format filename)
+ :default)))))))
+
+(defslimefun compile-string-for-emacs (string buffer position directory)
+ "Compile STRING (exerpted from BUFFER at POSITION).
+Record compiler notes signalled as `compiler-condition's."
+ (with-buffer-syntax ()
+ (swank-compiler
+ (lambda ()
+ (let ((*compile-print* nil) (*compile-verbose* t))
+ (swank-compile-string string :buffer buffer :position position
+ :directory directory))))))
+
+(defun file-newer-p (new-file old-file)
+ "Returns true if NEW-FILE is newer than OLD-FILE."
+ (> (file-write-date new-file) (file-write-date old-file)))
+
+(defun requires-compile-p (source-file)
+ (let ((fasl-file (probe-file (compile-file-pathname source-file))))
+ (or (not fasl-file)
+ (file-newer-p source-file fasl-file))))
+
+(defslimefun compile-file-if-needed (filename loadp)
+ (cond ((requires-compile-p filename)
+ (compile-file-for-emacs filename loadp))
+ (loadp
+ (load (compile-file-pathname filename))
+ nil)))
+
+
+;;;; Loading
+
+(defslimefun load-file (filename)
+ (to-string (load filename)))
+
+(defslimefun load-file-set-package (filename &optional package)
+ (load-file filename)
+ (if package
+ (set-package package)))
+
+
+;;;;; swank-require
+
+(defslimefun swank-require (modules &optional filename)
+ "Load the module MODULE."
+ (dolist (module (if (listp modules) modules (list modules)))
+ (unless (member (string module) *modules* :test #'string=)
+ (require module (or filename (module-filename module)))))
+ *modules*)
+
+(defvar *find-module* 'find-module
+ "Pluggable function to locate modules.
+The function receives a module name as argument and should return
+the filename of the module (or nil if the file doesn't exist).")
+
+(defun module-filename (module)
+ "Return the filename for the module MODULE."
+ (or (funcall *find-module* module)
+ (error "Can't locate module: ~s" module)))
+
+;;;;;; Simple *find-module* function.
+
+(defun merged-directory (dirname defaults)
+ (pathname-directory
+ (merge-pathnames
+ (make-pathname :directory `(:relative ,dirname) :defaults defaults)
+ defaults)))
+
+(defvar *load-path*
+ (list (make-pathname :directory (merged-directory "contrib" *load-truename*)
+ :name nil :type nil :version nil
+ :defaults *load-truename*))
+ "A list of directories to search for modules.")
+
+(defun module-canditates (name dir)
+ (list (compile-file-pathname (make-pathname :name name :defaults dir))
+ (make-pathname :name name :type "lisp" :defaults dir)))
+
+(defun find-module (module)
+ (let ((name (string-downcase module)))
+ (some (lambda (dir) (some #'probe-file (module-canditates name dir)))
+ *load-path*)))
+
+
+;;;; Macroexpansion
+
+(defvar *macroexpand-printer-bindings*
+ '((*print-circle* . nil)
+ (*print-pretty* . t)
+ (*print-escape* . t)
+ (*print-lines* . nil)
+ (*print-level* . nil)
+ (*print-length* . nil)))
+
+(defun apply-macro-expander (expander string)
+ (with-buffer-syntax ()
+ (with-bindings *macroexpand-printer-bindings*
+ (prin1-to-string (funcall expander (from-string string))))))
+
+(defslimefun swank-macroexpand-1 (string)
+ (apply-macro-expander #'macroexpand-1 string))
+
+(defslimefun swank-macroexpand (string)
+ (apply-macro-expander #'macroexpand string))
+
+(defslimefun swank-macroexpand-all (string)
+ (apply-macro-expander #'macroexpand-all string))
+
+(defslimefun swank-compiler-macroexpand-1 (string)
+ (apply-macro-expander #'compiler-macroexpand-1 string))
+
+(defslimefun swank-compiler-macroexpand (string)
+ (apply-macro-expander #'compiler-macroexpand string))
+
+(defslimefun disassemble-symbol (name)
+ (with-buffer-syntax ()
+ (with-output-to-string (*standard-output*)
+ (let ((*print-readably* nil))
+ (disassemble (fdefinition (from-string name)))))))
+
+
+;;;; Simple completion
+
+(defslimefun simple-completions (string package)
+ "Return a list of completions for the string STRING."
+ (let ((strings (all-completions string package #'prefix-match-p)))
+ (list strings (longest-common-prefix strings))))
+
+(defun all-completions (string package test)
+ (multiple-value-bind (name pname intern) (tokenize-symbol string)
+ (let* ((extern (and pname (not intern)))
+ (pack (cond ((equal pname "") keyword-package)
+ ((not pname) (guess-buffer-package package))
+ (t (guess-package pname))))
+ (test (lambda (sym) (funcall test name (unparse-symbol sym))))
+ (syms (and pack (matching-symbols pack extern test))))
+ (format-completion-set (mapcar #'unparse-symbol syms) intern pname))))
+
+(defun matching-symbols (package external test)
+ (let ((test (if external
+ (lambda (s)
+ (and (symbol-external-p s package)
+ (funcall test s)))
+ test))
+ (result '()))
+ (do-symbols (s package)
+ (when (funcall test s)
+ (push s result)))
+ (remove-duplicates result)))
+
+(defun unparse-symbol (symbol)
+ (let ((*print-case* (case (readtable-case *readtable*)
+ (:downcase :upcase)
+ (t :downcase))))
+ (unparse-name (symbol-name symbol))))
+
+(defun prefix-match-p (prefix string)
+ "Return true if PREFIX is a prefix of STRING."
+ (not (mismatch prefix string :end2 (min (length string) (length prefix)))))
+
+(defun longest-common-prefix (strings)
+ "Return the longest string that is a common prefix of STRINGS."
+ (if (null strings)
+ ""
+ (flet ((common-prefix (s1 s2)
+ (let ((diff-pos (mismatch s1 s2)))
+ (if diff-pos (subseq s1 0 diff-pos) s1))))
+ (reduce #'common-prefix strings))))
+
+(defun format-completion-set (strings internal-p package-name)
+ "Format a set of completion strings.
+Returns a list of completions with package qualifiers if needed."
+ (mapcar (lambda (string) (untokenize-symbol package-name internal-p string))
+ (sort strings #'string<)))
+
+
+;;;; Simple arglist display
+
+(defslimefun operator-arglist (name package)
+ (ignore-errors
+ (let ((args (arglist (parse-symbol name (guess-buffer-package package))))
+ (*print-escape* nil))
+ (cond ((eq args :not-available) nil)
+ (t (format nil "(~a ~/pprint-fill/)" name args))))))
+
+
+;;;; Documentation
+
+(defslimefun apropos-list-for-emacs (name &optional external-only
+ case-sensitive package)
+ "Make an apropos search for Emacs.
+The result is a list of property lists."
+ (let ((package (if package
+ (or (parse-package package)
+ (error "No such package: ~S" package)))))
+ ;; The MAPCAN will filter all uninteresting symbols, i.e. those
+ ;; who cannot be meaningfully described.
+ (mapcan (listify #'briefly-describe-symbol-for-emacs)
+ (sort (remove-duplicates
+ (apropos-symbols name external-only case-sensitive package))
+ #'present-symbol-before-p))))
+
+(defun briefly-describe-symbol-for-emacs (symbol)
+ "Return a property list describing SYMBOL.
+Like `describe-symbol-for-emacs' but with at most one line per item."
+ (flet ((first-line (string)
+ (let ((pos (position #\newline string)))
+ (if (null pos) string (subseq string 0 pos)))))
+ (let ((desc (map-if #'stringp #'first-line
+ (describe-symbol-for-emacs symbol))))
+ (if desc
+ (list* :designator (to-string symbol) desc)))))
+
+(defun map-if (test fn &rest lists)
+ "Like (mapcar FN . LISTS) but only call FN on objects satisfying TEST.
+Example:
+\(map-if #'oddp #'- '(1 2 3 4 5)) => (-1 2 -3 4 -5)"
+ (apply #'mapcar
+ (lambda (x) (if (funcall test x) (funcall fn x) x))
+ lists))
+
+(defun listify (f)
+ "Return a function like F, but which returns any non-null value
+wrapped in a list."
+ (lambda (x)
+ (let ((y (funcall f x)))
+ (and y (list y)))))
+
+(defun present-symbol-before-p (x y)
+ "Return true if X belongs before Y in a printed summary of symbols.
+Sorted alphabetically by package name and then symbol name, except
+that symbols accessible in the current package go first."
+ (declare (type symbol x y))
+ (flet ((accessible (s)
+ ;; Test breaks on NIL for package that does not inherit it
+ (eq (find-symbol (symbol-name s) *buffer-package*) s)))
+ (let ((ax (accessible x)) (ay (accessible y)))
+ (cond ((and ax ay) (string< (symbol-name x) (symbol-name y)))
+ (ax t)
+ (ay nil)
+ (t (let ((px (symbol-package x)) (py (symbol-package y)))
+ (if (eq px py)
+ (string< (symbol-name x) (symbol-name y))
+ (string< (package-name px) (package-name py)))))))))
+
+(defun make-apropos-matcher (pattern case-sensitive)
+ (let ((chr= (if case-sensitive #'char= #'char-equal)))
+ (lambda (symbol)
+ (search pattern (string symbol) :test chr=))))
+
+(defun apropos-symbols (string external-only case-sensitive package)
+ (let ((packages (or package (remove (find-package :keyword)
+ (list-all-packages))))
+ (matcher (make-apropos-matcher string case-sensitive))
+ (result))
+ (with-package-iterator (next packages :external :internal)
+ (loop (multiple-value-bind (morep symbol) (next)
+ (cond ((not morep) (return))
+ ((and (if external-only (symbol-external-p symbol) t)
+ (funcall matcher symbol))
+ (push symbol result))))))
+ result))
+
+(defun call-with-describe-settings (fn)
+ (let ((*print-readably* nil))
+ (funcall fn)))
+
+(defmacro with-describe-settings ((&rest _) &body body)
+ (declare (ignore _))
+ `(call-with-describe-settings (lambda () , at body)))
+
+(defun describe-to-string (object)
+ (with-describe-settings ()
+ (with-output-to-string (*standard-output*)
+ (describe object))))
+
+(defslimefun describe-symbol (symbol-name)
+ (with-buffer-syntax ()
+ (describe-to-string (parse-symbol-or-lose symbol-name))))
+
+(defslimefun describe-function (name)
+ (with-buffer-syntax ()
+ (let ((symbol (parse-symbol-or-lose name)))
+ (describe-to-string (or (macro-function symbol)
+ (symbol-function symbol))))))
+
+(defslimefun describe-definition-for-emacs (name kind)
+ (with-buffer-syntax ()
+ (with-describe-settings ()
+ (with-output-to-string (*standard-output*)
+ (describe-definition (parse-symbol-or-lose name) kind)))))
+
+(defslimefun documentation-symbol (symbol-name &optional default)
+ (with-buffer-syntax ()
+ (multiple-value-bind (sym foundp) (parse-symbol symbol-name)
+ (if foundp
+ (let ((vdoc (documentation sym 'variable))
+ (fdoc (documentation sym 'function)))
+ (or (and (or vdoc fdoc)
+ (concatenate 'string
+ fdoc
+ (and vdoc fdoc '(#\Newline #\Newline))
+ vdoc))
+ default))
+ default))))
+
+
+;;;; Package Commands
+
+(defslimefun list-all-package-names (&optional nicknames)
+ "Return a list of all package names.
+Include the nicknames if NICKNAMES is true."
+ (mapcar #'unparse-name
+ (if nicknames
+ (mapcan #'package-names (list-all-packages))
+ (mapcar #'package-name (list-all-packages)))))
+
+
+;;;; Tracing
+
+;; Use eval for the sake of portability...
+(defun tracedp (fspec)
+ (member fspec (eval '(trace))))
+
+(defslimefun swank-toggle-trace (spec-string)
+ (let ((spec (from-string spec-string)))
+ (cond ((consp spec) ; handle complicated cases in the backend
+ (toggle-trace spec))
+ ((tracedp spec)
+ (eval `(untrace ,spec))
+ (format nil "~S is now untraced." spec))
+ (t
+ (eval `(trace ,spec))
+ (format nil "~S is now traced." spec)))))
+
+(defslimefun untrace-all ()
+ (untrace))
+
+(defslimefun redirect-trace-output (target)
+ (setf (connection.trace-output *emacs-connection*)
+ (make-output-stream-for-target *emacs-connection* target))
+ nil)
+
+
+;;;; Undefing
+
+(defslimefun undefine-function (fname-string)
+ (let ((fname (from-string fname-string)))
+ (format nil "~S" (fmakunbound fname))))
+
+
+;;;; Profiling
+
+(defun profiledp (fspec)
+ (member fspec (profiled-functions)))
+
+(defslimefun toggle-profile-fdefinition (fname-string)
+ (let ((fname (from-string fname-string)))
+ (cond ((profiledp fname)
+ (unprofile fname)
+ (format nil "~S is now unprofiled." fname))
+ (t
+ (profile fname)
+ (format nil "~S is now profiled." fname)))))
+
+
+;;;; Source Locations
+
+(defslimefun find-definitions-for-emacs (name)
+ "Return a list ((DSPEC LOCATION) ...) of definitions for NAME.
+DSPEC is a string and LOCATION a source location. NAME is a string."
+ (multiple-value-bind (sexp error)
+ (ignore-errors (values (from-string name)))
+ (unless error
+ (loop for (dspec loc) in (find-definitions sexp)
+ collect (list (to-string dspec) loc)))))
+
+(defun alistify (list key test)
+ "Partition the elements of LIST into an alist. KEY extracts the key
+from an element and TEST is used to compare keys."
+ (declare (type function key))
+ (let ((alist '()))
+ (dolist (e list)
+ (let* ((k (funcall key e))
+ (probe (assoc k alist :test test)))
+ (if probe
+ (push e (cdr probe))
+ (push (cons k (list e)) alist))))
+ alist))
+
+(defun location-position< (pos1 pos2)
+ (cond ((and (position-p pos1) (position-p pos2))
+ (< (position-pos pos1)
+ (position-pos pos2)))
+ (t nil)))
+
+(defun partition (list test key)
+ (declare (type function test key))
+ (loop for e in list
+ if (funcall test (funcall key e)) collect e into yes
+ else collect e into no
+ finally (return (values yes no))))
+
+(defstruct (xref (:conc-name xref.)
+ (:type list))
+ dspec location)
+
+(defun location-valid-p (location)
+ (eq (car location) :location))
+
+(defun xref-buffer (xref)
+ (location-buffer (xref.location xref)))
+
+(defun xref-position (xref)
+ (location-buffer (xref.location xref)))
+
+(defun group-xrefs (xrefs)
+ "Group XREFS, a list of the form ((DSPEC LOCATION) ...) by location.
+The result is a list of the form ((LOCATION . ((DSPEC . LOCATION) ...)) ...)."
+ (multiple-value-bind (resolved errors)
+ (partition xrefs #'location-valid-p #'xref.location)
+ (let ((alist (alistify resolved #'xref-buffer #'equal)))
+ (append
+ (loop for (buffer . list) in alist
+ collect (cons (second buffer)
+ (mapcar (lambda (xref)
+ (cons (to-string (xref.dspec xref))
+ (xref.location xref)))
+ (sort list #'location-position<
+ :key #'xref-position))))
+ (if errors
+ (list (cons "Unresolved"
+ (mapcar (lambda (xref)
+ (cons (to-string (xref.dspec xref))
+ (xref.location xref)))
+ errors))))))))
+
+(defslimefun xref (type symbol-name)
+ (let ((symbol (parse-symbol-or-lose symbol-name *buffer-package*)))
+ (group-xrefs
+ (ecase type
+ (:calls (who-calls symbol))
+ (:calls-who (calls-who symbol))
+ (:references (who-references symbol))
+ (:binds (who-binds symbol))
+ (:sets (who-sets symbol))
+ (:macroexpands (who-macroexpands symbol))
+ (:specializes (who-specializes symbol))
+ (:callers (list-callers symbol))
+ (:callees (list-callees symbol))))))
+
+
+;;;; Inspecting
+
+(defun common-seperated-spec (list &optional (callback (lambda (v)
+ `(:value ,v))))
+ (butlast
+ (loop
+ for i in list
+ collect (funcall callback i)
+ collect ", ")))
+
+(defun inspector-princ (list)
+ "Like princ-to-string, but don't rewrite (function foo) as #'foo.
+Do NOT pass circular lists to this function."
+ (let ((*print-pprint-dispatch* (copy-pprint-dispatch)))
+ (set-pprint-dispatch '(cons (member function)) nil)
+ (princ-to-string list)))
+
+(defmethod inspect-for-emacs ((object cons) inspector)
+ (declare (ignore inspector))
+ (if (consp (cdr object))
+ (inspect-for-emacs-list object)
+ (inspect-for-emacs-simple-cons object)))
+
+(defun inspect-for-emacs-simple-cons (cons)
+ (values "A cons cell."
+ (label-value-line*
+ ('car (car cons))
+ ('cdr (cdr cons)))))
+
+(defun inspect-for-emacs-list (list)
+ (let ((maxlen 40))
+ (multiple-value-bind (length tail) (safe-length list)
+ (flet ((frob (title list)
+ (let (lines)
+ (loop for i from 0 for rest on list do
+ (if (consp (cdr rest)) ; e.g. (A . (B . ...))
+ (push (label-value-line i (car rest)) lines)
+ (progn ; e.g. (A . NIL) or (A . B)
+ (push (label-value-line i (car rest) :newline nil) lines)
+ (when (cdr rest)
+ (push '((:newline)) lines)
+ (push (label-value-line ':tail () :newline nil) lines))
+ (loop-finish)))
+ finally
+ (setf lines (reduce #'append (nreverse lines) :from-end t)))
+ (values title (append '("Elements:" (:newline)) lines)))))
+
+ (cond ((not length) ; circular
+ (frob "A circular list."
+ (cons (car list)
+ (ldiff (cdr list) list))))
+ ((and (<= length maxlen) (not tail))
+ (frob "A proper list." list))
+ (tail
+ (frob "An improper list." list))
+ (t
+ (frob "A proper list." list)))))))
+
+;; (inspect-for-emacs-list '#1=(a #1# . #1# ))
+
+(defun safe-length (list)
+ "Similar to `list-length', but avoid errors on improper lists.
+Return two values: the length of the list and the last cdr.
+NIL is returned if the list is circular."
+ (do ((n 0 (+ n 2)) ;Counter.
+ (fast list (cddr fast)) ;Fast pointer: leaps by 2.
+ (slow list (cdr slow))) ;Slow pointer: leaps by 1.
+ (nil)
+ (cond ((null fast) (return (values n nil)))
+ ((not (consp fast)) (return (values n fast)))
+ ((null (cdr fast)) (return (values (1+ n) (cdr fast))))
+ ((and (eq fast slow) (> n 0)) (return nil))
+ ((not (consp (cdr fast))) (return (values (1+ n) (cdr fast)))))))
+
+(defvar *slime-inspect-contents-limit* nil "How many elements of
+ a hash table or array to show by default. If table has more than
+ this then offer actions to view more. Set to nil for no limit." )
+
+(defmethod inspect-for-emacs ((ht hash-table) inspector)
+ (declare (ignore inspector))
+ (values (prin1-to-string ht)
+ (append
+ (label-value-line*
+ ("Count" (hash-table-count ht))
+ ("Size" (hash-table-size ht))
+ ("Test" (hash-table-test ht))
+ ("Rehash size" (hash-table-rehash-size ht))
+ ("Rehash threshold" (hash-table-rehash-threshold ht)))
+ (let ((weakness (hash-table-weakness ht)))
+ (when weakness
+ `("Weakness: " (:value ,weakness) (:newline))))
+ (unless (zerop (hash-table-count ht))
+ `((:action "[clear hashtable]" ,(lambda () (clrhash ht))) (:newline)
+ "Contents: " (:newline)))
+ (if (and *slime-inspect-contents-limit*
+ (>= (hash-table-count ht) *slime-inspect-contents-limit*))
+ (inspect-bigger-piece-actions ht (hash-table-count ht))
+ nil)
+ (loop for key being the hash-keys of ht
+ for value being the hash-values of ht
+ repeat (or *slime-inspect-contents-limit* most-positive-fixnum)
+ append `((:value ,key) " = " (:value ,value)
+ " " (:action "[remove entry]"
+ ,(let ((key key))
+ (lambda () (remhash key ht))))
+ (:newline))))))
+
+(defun inspect-bigger-piece-actions (thing size)
+ (append
+ (if (> size *slime-inspect-contents-limit*)
+ (list (inspect-show-more-action thing)
+ '(:newline))
+ nil)
+ (list (inspect-whole-thing-action thing size)
+ '(:newline))))
+
+(defun inspect-whole-thing-action (thing size)
+ `(:action ,(format nil "Inspect all ~a elements."
+ size)
+ ,(lambda()
+ (let ((*slime-inspect-contents-limit* nil))
+ (swank::inspect-object thing)))))
+
+(defun inspect-show-more-action (thing)
+ `(:action ,(format nil "~a elements shown. Prompt for how many to inspect..."
+ *slime-inspect-contents-limit* )
+ ,(lambda()
+ (let ((*slime-inspect-contents-limit*
+ (progn (format t "How many elements should be shown? ") (read))))
+ (swank::inspect-object thing)))))
+
+(defmethod inspect-for-emacs ((array array) inspector)
+ (declare (ignore inspector))
+ (values "An array."
+ (append
+ (label-value-line*
+ ("Dimensions" (array-dimensions array))
+ ("Its element type is" (array-element-type array))
+ ("Total size" (array-total-size array))
+ ("Adjustable" (adjustable-array-p array)))
+ (when (array-has-fill-pointer-p array)
+ (label-value-line "Fill pointer" (fill-pointer array)))
+ '("Contents:" (:newline))
+ (if (and *slime-inspect-contents-limit*
+ (>= (array-total-size array) *slime-inspect-contents-limit*))
+ (inspect-bigger-piece-actions array (length array))
+ nil)
+ (loop for i below (or *slime-inspect-contents-limit* (array-total-size array))
+ append (label-value-line i (row-major-aref array i))))))
+
+(defmethod inspect-for-emacs ((char character) inspector)
+ (declare (ignore inspector))
+ (values "A character."
+ (append
+ (label-value-line*
+ ("Char code" (char-code char))
+ ("Lower cased" (char-downcase char))
+ ("Upper cased" (char-upcase char)))
+ (if (get-macro-character char)
+ `("In the current readtable ("
+ (:value ,*readtable*) ") it is a macro character: "
+ (:value ,(get-macro-character char)))))))
+
+(defvar *inspectee*)
+(defvar *inspectee-parts*)
+(defvar *inspectee-actions*)
+(defvar *inspector-stack* '())
+(defvar *inspector-history* (make-array 10 :adjustable t :fill-pointer 0))
+(declaim (type vector *inspector-history*))
+(defvar *inspect-length* 30)
+(defvar *default-inspector* (make-default-inspector))
+
+(defun reset-inspector ()
+ (setq *inspectee* nil
+ *inspector-stack* nil
+ *inspectee-parts* (make-array 10 :adjustable t :fill-pointer 0)
+ *inspectee-actions* (make-array 10 :adjustable t :fill-pointer 0)
+ *inspector-history* (make-array 10 :adjustable t :fill-pointer 0)))
+
+(defun valid-function-name-p (form)
+ (or (symbolp form)
+ (and (consp form)
+ (second form)
+ (not (third form))
+ (eq (first form) 'setf)
+ (symbolp (second form)))))
+
+(defslimefun init-inspector (string)
+ (with-buffer-syntax ()
+ (reset-inspector)
+ (inspect-object (eval (read-from-string string)))))
+
+(defun print-part-to-string (value)
+ (let ((string (to-string value))
+ (pos (position value *inspector-history*)))
+ (if pos
+ (format nil "#~D=~A" pos string)
+ string)))
+
+(defun inspector-content-for-emacs (specs)
+ (loop for part in specs collect
+ (etypecase part
+ (null ; XXX encourages sloppy programming
+ nil)
+ (string part)
+ (cons (destructure-case part
+ ((:newline)
+ (string #\newline))
+ ((:value obj &optional str)
+ (value-part-for-emacs obj str))
+ ((:action label lambda &key (refreshp t))
+ (action-part-for-emacs label lambda refreshp)))))))
+
+(defun assign-index (object vector)
+ (let ((index (fill-pointer vector)))
+ (vector-push-extend object vector)
+ index))
+
+(defun value-part-for-emacs (object string)
+ (list :value
+ (or string (print-part-to-string object))
+ (assign-index object *inspectee-parts*)))
+
+(defun action-part-for-emacs (label lambda refreshp)
+ (list :action label (assign-index (list lambda refreshp)
+ *inspectee-actions*)))
+
+(defun inspect-object (object &optional (inspector *default-inspector*))
+ (push (setq *inspectee* object) *inspector-stack*)
+ (unless (find object *inspector-history*)
+ (vector-push-extend object *inspector-history*))
+ (let ((*print-pretty* nil) ; print everything in the same line
+ (*print-circle* t)
+ (*print-readably* nil))
+ (multiple-value-bind (_ content) (inspect-for-emacs object inspector)
+ (declare (ignore _))
+ (list :title (with-output-to-string (s)
+ (print-unreadable-object (object s :type t :identity t)))
+ :id (assign-index object *inspectee-parts*)
+ :content (inspector-content-for-emacs content)))))
+
+(defslimefun inspector-nth-part (index)
+ (aref *inspectee-parts* index))
+
+(defslimefun inspect-nth-part (index)
+ (with-buffer-syntax ()
+ (inspect-object (inspector-nth-part index))))
+
+(defslimefun inspector-call-nth-action (index &rest args)
+ (destructuring-bind (action-lambda refreshp)
+ (aref *inspectee-actions* index)
+ (apply action-lambda args)
+ (if refreshp
+ (inspect-object (pop *inspector-stack*))
+ ;; tell emacs that we don't want to refresh the inspector buffer
+ nil)))
+
+(defslimefun inspector-pop ()
+ "Drop the inspector stack and inspect the second element. Return
+nil if there's no second element."
+ (with-buffer-syntax ()
+ (cond ((cdr *inspector-stack*)
+ (pop *inspector-stack*)
+ (inspect-object (pop *inspector-stack*)))
+ (t nil))))
+
+(defslimefun inspector-next ()
+ "Inspect the next element in the *inspector-history*."
+ (with-buffer-syntax ()
+ (let ((position (position *inspectee* *inspector-history*)))
+ (cond ((= (1+ position) (length *inspector-history*))
+ nil)
+ (t (inspect-object (aref *inspector-history* (1+ position))))))))
+
+(defslimefun inspector-reinspect ()
+ (inspect-object *inspectee*))
+
+(defslimefun quit-inspector ()
+ (reset-inspector)
+ nil)
+
+(defslimefun describe-inspectee ()
+ "Describe the currently inspected object."
+ (with-buffer-syntax ()
+ (describe-to-string *inspectee*)))
+
+(defslimefun pprint-inspector-part (index)
+ "Pretty-print the currently inspected object."
+ (with-buffer-syntax ()
+ (swank-pprint (list (inspector-nth-part index)))))
+
+(defslimefun inspect-in-frame (string index)
+ (with-buffer-syntax ()
+ (reset-inspector)
+ (inspect-object (eval-in-frame (from-string string) index))))
+
+(defslimefun inspect-current-condition ()
+ (with-buffer-syntax ()
+ (reset-inspector)
+ (inspect-object *swank-debugger-condition*)))
+
+(defslimefun inspect-frame-var (frame var)
+ (with-buffer-syntax ()
+ (reset-inspector)
+ (inspect-object (frame-var-value frame var))))
+
+
+;;;; Thread listing
+
+(defvar *thread-list* ()
+ "List of threads displayed in Emacs. We don't care a about
+synchronization issues (yet). There can only be one thread listing at
+a time.")
+
+(defslimefun list-threads ()
+ "Return a list ((NAME DESCRIPTION) ...) of all threads."
+ (setq *thread-list* (all-threads))
+ (loop for thread in *thread-list*
+ for name = (thread-name thread)
+ collect (list (if (symbolp name) (symbol-name name) name)
+ (thread-status thread)
+ (thread-id thread))))
+
+(defslimefun quit-thread-browser ()
+ (setq *thread-list* nil))
+
+(defun nth-thread (index)
+ (nth index *thread-list*))
+
+(defslimefun debug-nth-thread (index)
+ (let ((connection *emacs-connection*))
+ (interrupt-thread (nth-thread index)
+ (lambda ()
+ (with-connection (connection)
+ (simple-break))))))
+
+(defslimefun kill-nth-thread (index)
+ (kill-thread (nth-thread index)))
+
+(defslimefun start-swank-server-in-thread (index port-file-name)
+ "Interrupt the INDEXth thread and make it start a swank server.
+The server port is written to PORT-FILE-NAME."
+ (interrupt-thread (nth-thread index)
+ (lambda ()
+ (start-server port-file-name :style nil))))
+
+;;;; Class browser
+
+(defun mop-helper (class-name fn)
+ (let ((class (find-class class-name nil)))
+ (if class
+ (mapcar (lambda (x) (to-string (class-name x)))
+ (funcall fn class)))))
+
+(defslimefun mop (type symbol-name)
+ "Return info about classes using mop.
+
+ When type is:
+ :subclasses - return the list of subclasses of class.
+ :superclasses - return the list of superclasses of class."
+ (let ((symbol (parse-symbol symbol-name *buffer-package*)))
+ (ecase type
+ (:subclasses
+ (mop-helper symbol #'swank-mop:class-direct-subclasses))
+ (:superclasses
+ (mop-helper symbol #'swank-mop:class-direct-superclasses)))))
+
+
+;;;; Automatically synchronized state
+;;;
+;;; Here we add hooks to push updates of relevant information to
+;;; Emacs.
+
+;;;;; *FEATURES*
+
+(defun sync-features-to-emacs ()
+ "Update Emacs if any relevant Lisp state has changed."
+ ;; FIXME: *slime-features* should be connection-local
+ (unless (eq *slime-features* *features*)
+ (setq *slime-features* *features*)
+ (send-to-emacs (list :new-features (features-for-emacs)))))
+
+(defun features-for-emacs ()
+ "Return `*slime-features*' in a format suitable to send it to Emacs."
+ *slime-features*)
+
+(add-hook *pre-reply-hook* 'sync-features-to-emacs)
+
+
+;;;;; Indentation of macros
+;;;
+;;; This code decides how macros should be indented (based on their
+;;; arglists) and tells Emacs. A per-connection cache is used to avoid
+;;; sending redundant information to Emacs -- we just say what's
+;;; changed since last time.
+;;;
+;;; The strategy is to scan all symbols, pick out the macros, and look
+;;; for &body-arguments.
+
+(defvar *configure-emacs-indentation* t
+ "When true, automatically send indentation information to Emacs
+after each command.")
+
+(defslimefun update-indentation-information ()
+ (perform-indentation-update *emacs-connection* t)
+ nil)
+
+;; This function is for *PRE-REPLY-HOOK*.
+(defun sync-indentation-to-emacs ()
+ "Send any indentation updates to Emacs via CONNECTION."
+ (when *configure-emacs-indentation*
+ (let ((fullp (need-full-indentation-update-p *emacs-connection*)))
+ (perform-indentation-update *emacs-connection* fullp))))
+
+(defun need-full-indentation-update-p (connection)
+ "Return true if the whole indentation cache should be updated.
+This is a heuristic to avoid scanning all symbols all the time:
+instead, we only do a full scan if the set of packages has changed."
+ (set-difference (list-all-packages)
+ (connection.indentation-cache-packages connection)))
+
+(defun perform-indentation-update (connection force)
+ "Update the indentation cache in CONNECTION and update Emacs.
+If FORCE is true then start again without considering the old cache."
+ (let ((cache (connection.indentation-cache connection)))
+ (when force (clrhash cache))
+ (let ((delta (update-indentation/delta-for-emacs cache force)))
+ (setf (connection.indentation-cache-packages connection)
+ (list-all-packages))
+ (unless (null delta)
+ (send-to-emacs (list :indentation-update delta))))))
+
+(defun update-indentation/delta-for-emacs (cache &optional force)
+ "Update the cache and return the changes in a (SYMBOL . INDENT) list.
+If FORCE is true then check all symbols, otherwise only check symbols
+belonging to the buffer package."
+ (let ((alist '()))
+ (flet ((consider (symbol)
+ (let ((indent (symbol-indentation symbol)))
+ (when indent
+ (unless (equal (gethash symbol cache) indent)
+ (setf (gethash symbol cache) indent)
+ (push (cons (string-downcase symbol) indent) alist))))))
+ (if force
+ (do-all-symbols (symbol)
+ (consider symbol))
+ (do-symbols (symbol *buffer-package*)
+ ;; We're really just interested in the symbols of *BUFFER-PACKAGE*,
+ ;; and *not* all symbols that are _present_ (cf. SYMBOL-STATUS.)
+ (when (eq (symbol-package symbol) *buffer-package*)
+ (consider symbol)))))
+ alist))
+
+(defun package-names (package)
+ "Return the name and all nicknames of PACKAGE in a fresh list."
+ (cons (package-name package) (copy-list (package-nicknames package))))
+
+(defun cl-symbol-p (symbol)
+ "Is SYMBOL a symbol in the COMMON-LISP package?"
+ (eq (symbol-package symbol) cl-package))
+
+(defun known-to-emacs-p (symbol)
+ "Return true if Emacs has special rules for indenting SYMBOL."
+ (cl-symbol-p symbol))
+
+(defun symbol-indentation (symbol)
+ "Return a form describing the indentation of SYMBOL.
+The form is to be used as the `common-lisp-indent-function' property
+in Emacs."
+ (if (and (macro-function symbol)
+ (not (known-to-emacs-p symbol)))
+ (let ((arglist (arglist symbol)))
+ (etypecase arglist
+ ((member :not-available)
+ nil)
+ (list
+ (macro-indentation arglist))))
+ nil))
+
+(defun macro-indentation (arglist)
+ (if (well-formed-list-p arglist)
+ (position '&body (remove '&optional (clean-arglist arglist)))
+ nil))
+
+(defun clean-arglist (arglist)
+ "Remove &whole, &enviroment, and &aux elements from ARGLIST."
+ (cond ((null arglist) '())
+ ((member (car arglist) '(&whole &environment))
+ (clean-arglist (cddr arglist)))
+ ((eq (car arglist) '&aux)
+ '())
+ (t (cons (car arglist) (clean-arglist (cdr arglist))))))
+
+(defun well-formed-list-p (list)
+ "Is LIST a proper list terminated by NIL?"
+ (typecase list
+ (null t)
+ (cons (well-formed-list-p (cdr list)))
+ (t nil)))
+
+(defun print-indentation-lossage (&optional (stream *standard-output*))
+ "Return the list of symbols whose indentation styles collide incompatibly.
+Collisions are caused because package information is ignored."
+ (let ((table (make-hash-table :test 'equal)))
+ (flet ((name (s) (string-downcase (symbol-name s))))
+ (do-all-symbols (s)
+ (setf (gethash (name s) table)
+ (cons s (symbol-indentation s))))
+ (let ((collisions '()))
+ (do-all-symbols (s)
+ (let* ((entry (gethash (name s) table))
+ (owner (car entry))
+ (indent (cdr entry)))
+ (unless (or (eq s owner)
+ (equal (symbol-indentation s) indent)
+ (and (not (fboundp s))
+ (null (macro-function s))))
+ (pushnew owner collisions)
+ (pushnew s collisions))))
+ (if (null collisions)
+ (format stream "~&No worries!~%")
+ (format stream "~&Symbols with collisions:~%~{ ~S~%~}"
+ collisions))))))
+
+(add-hook *pre-reply-hook* 'sync-indentation-to-emacs)
+
+;;; swank.lisp ends here
Added: branches/bos/thirdparty/emacs/slime/test-all.sh
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/test-all.sh Fri Jan 18 06:05:59 2008
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# This code has been placed in the Public Domain. All warranties
+# are disclaimed.
+
+trap EXIT
+
+for emacs in xemacs ; do # emacs-20.7 emacs-21.3.50 xemacs ; do
+ for lisp in 'cmucl -noinit' sbcl lispworks-personal-4300 'clisp -K full' acl5; do
+ echo testing: $emacs $lisp dribble.$emacs_$lisp result.$emacs_$lisp
+ test.sh $emacs "$lisp" "dribble.${emacs}_${lisp}" "result.${emacs}_${lisp}"
+ done
+done
+
\ No newline at end of file
Added: branches/bos/thirdparty/emacs/slime/test.sh
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/test.sh Fri Jan 18 06:05:59 2008
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# Run the SLIME test suite inside screen, saving the results to a file.
+
+# This script's exit status is the number of tests failed. If no tests
+# fail then no output is printed. If at least one test fails then a
+# one-line summary is printed.
+
+# If something unexpected fails, you might get an exit code like 127
+# or 255 instead. Sorry.
+
+# This code has been placed in the Public Domain. All warranties
+# are disclaimed.
+
+function usage () {
+ echo "Usage: $name [-v] [-r] <emacs> <lisp>"
+ exit 1
+}
+
+name=$0
+
+while getopts vr opt; do
+ case $opt in
+ v) verbose=true;;
+ r) dump_results=true;;
+ *) usage;;
+ esac
+done
+
+shift $((OPTIND - 1))
+[ $# = 2 ] || usage
+
+emacs=$1; lisp=$2;
+
+# Move the code into a directory in /tmp, so that we can compile it
+# for the current lisp.
+
+slimedir=$(dirname $name)
+testdir=/tmp/slime-test.$$
+results=$testdir/results
+dribble=$testdir/dribble
+statusfile=$testdir/status
+
+test -d $testdir && rm -r $testdir
+
+trap "rm -r $testdir" EXIT # remove temporary directory on exit
+
+mkdir $testdir
+cp -r $slimedir/*.{el,lisp} ChangeLog $slimedir/contrib $testdir
+mkfifo $dribble
+
+session=slime-screen.$$
+
+screen -S $session -m -D bash -c "$emacs -nw -q -no-site-file --no-site-file \
+ --eval '(setq debug-on-quit t)' \
+ --eval '(setq max-lisp-eval-depth 1000)' \
+ --eval '(setq load-path (cons \"$testdir\" load-path))' \
+ --eval '(require (quote slime))' \
+ --eval '(setq inferior-lisp-program \"$lisp\")' \
+ --eval '(slime-batch-test \"$results\")' > $dribble;\
+ echo \$? > $statusfile" &
+
+screenpid=$!
+
+if [ "$verbose" = true ]; then
+ cat $dribble &
+else
+ cat $dribble > /dev/null &
+fi;
+
+trap "screen -S $session -X quit" SIGINT
+wait $screenpid
+
+if [ -f "$statusfile" ]; then
+ [ "$dump_results" = true ] && cat $results;
+ echo $(cat $statusfile) "test(s) failed."
+else
+ # Tests crashed
+ echo crashed
+fi
+
+exit $status
Added: branches/bos/thirdparty/emacs/slime/xref.lisp
==============================================================================
--- (empty file)
+++ branches/bos/thirdparty/emacs/slime/xref.lisp Fri Jan 18 06:05:59 2008
@@ -0,0 +1,2891 @@
+;;; -*- Mode: LISP; Package: XREF; Syntax: Common-lisp; -*-
+;;; Mon Jan 21 16:21:20 1991 by Mark Kantrowitz <mkant at GLINDA.OZ.CS.CMU.EDU>
+;;; xref.lisp
+
+;;; ****************************************************************
+;;; List Callers: A Static Analysis Cross Referencing Tool for Lisp
+;;; ****************************************************************
+;;;
+;;; The List Callers system is a portable Common Lisp cross referencing
+;;; utility. It grovels over a set of files and compiles a database of the
+;;; locations of all references for each symbol used in the files.
+;;; List Callers is similar to the Symbolics Who-Calls and the
+;;; Xerox Masterscope facilities.
+;;;
+;;; When you change a function or variable definition, it can be useful
+;;; to know its callers, in order to update each of them to the new
+;;; definition. Similarly, having a graphic display of the structure
+;;; (e.g., call graph) of a program can help make undocumented code more
+;;; understandable. This static code analyzer facilitates both capabilities.
+;;; The database compiled by xref is suitable for viewing by a graphical
+;;; browser. (Note: the reference graph is not necessarily a DAG. Since many
+;;; graphical browsers assume a DAG, this will lead to infinite loops.
+;;; Some code which is useful in working around this problem is included,
+;;; as well as a sample text-indenting outliner and an interface to Bates'
+;;; PSGraph Postscript Graphing facility.)
+;;;
+;;; Written by Mark Kantrowitz, July 1990.
+;;;
+;;; Address: School of Computer Science
+;;; Carnegie Mellon University
+;;; Pittsburgh, PA 15213
+;;;
+;;; Copyright (c) 1990. All rights reserved.
+;;;
+;;; See general license below.
+;;;
+
+;;; ****************************************************************
+;;; General License Agreement and Lack of Warranty *****************
+;;; ****************************************************************
+;;;
+;;; This software is distributed in the hope that it will be useful (both
+;;; in and of itself and as an example of lisp programming), but WITHOUT
+;;; ANY WARRANTY. The author(s) do not accept responsibility to anyone for
+;;; the consequences of using it or for whether it serves any particular
+;;; purpose or works at all. No warranty is made about the software or its
+;;; performance.
+;;;
+;;; Use and copying of this software and the preparation of derivative
+;;; works based on this software are permitted, so long as the following
+;;; conditions are met:
+;;; o The copyright notice and this entire notice are included intact
+;;; and prominently carried on all copies and supporting documentation.
+;;; o No fees or compensation are charged for use, copies, or
+;;; access to this software. You may charge a nominal
+;;; distribution fee for the physical act of transferring a
+;;; copy, but you may not charge for the program itself.
+;;; o If you modify this software, you must cause the modified
+;;; file(s) to carry prominent notices (a Change Log)
+;;; describing the changes, who made the changes, and the date
+;;; of those changes.
+;;; o Any work distributed or published that in whole or in part
+;;; contains or is a derivative of this software or any part
+;;; thereof is subject to the terms of this agreement. The
+;;; aggregation of another unrelated program with this software
+;;; or its derivative on a volume of storage or distribution
+;;; medium does not bring the other program under the scope
+;;; of these terms.
+;;; o Permission is granted to manufacturers and distributors of
+;;; lisp compilers and interpreters to include this software
+;;; with their distribution.
+;;;
+;;; This software is made available AS IS, and is distributed without
+;;; warranty of any kind, either expressed or implied.
+;;;
+;;; In no event will the author(s) or their institutions be liable to you
+;;; for damages, including lost profits, lost monies, or other special,
+;;; incidental or consequential damages arising out of or in connection
+;;; with the use or inability to use (including but not limited to loss of
+;;; data or data being rendered inaccurate or losses sustained by third
+;;; parties or a failure of the program to operate as documented) the
+;;; program, even if you have been advised of the possibility of such
+;;; damanges, or for any claim by any other party, whether in an action of
+;;; contract, negligence, or other tortious action.
+;;;
+;;; The current version of this software and a variety of related utilities
+;;; may be obtained by anonymous ftp from ftp.cs.cmu.edu in the directory
+;;; user/ai/lang/lisp/code/tools/xref/
+;;;
+;;; Please send bug reports, comments, questions and suggestions to
+;;; mkant at cs.cmu.edu. We would also appreciate receiving any changes
+;;; or improvements you may make.
+;;;
+;;; If you wish to be added to the Lisp-Utilities at cs.cmu.edu mailing list,
+;;; send email to Lisp-Utilities-Request at cs.cmu.edu with your name, email
+;;; address, and affiliation. This mailing list is primarily for
+;;; notification about major updates, bug fixes, and additions to the lisp
+;;; utilities collection. The mailing list is intended to have low traffic.
+;;;
+
+;;; ********************************
+;;; Change Log *********************
+;;; ********************************
+;;;
+;;; 27-FEB-91 mk Added insert arg to psgraph-xref to allow the postscript
+;;; graphs to be inserted in Scribe documents.
+;;; 21-FEB-91 mk Added warning if not compiled.
+;;; 07-FEB-91 mk Fixed bug in record-callers with regard to forms at
+;;; toplevel.
+;;; 21-JAN-91 mk Added file xref-test.lisp to test xref.
+;;; 16-JAN-91 mk Added definition WHO-CALLS to parallel the Symbolics syntax.
+;;; 16-JAN-91 mk Added macroexpansion capability to record-callers. Also
+;;; added parameter *handle-macro-forms*, defaulting to T.
+;;; 16-JAN-91 mk Modified print-caller-tree and related functions
+;;; to allow the user to specify root nodes. If the user
+;;; doesn't specify them, it will default to all root
+;;; nodes, as before.
+;;; 16-JAN-91 mk Added parameter *default-graphing-mode* to specify
+;;; the direction of the graphing. Either :call-graph,
+;;; where the children of a node are those functions called
+;;; by the node, or :caller-graph where the children of a
+;;; node are the callers of the node. :call-graph is the
+;;; default.
+;;; 16-JAN-91 mk Added parameter *indent-amount* to control the indentation
+;;; in print-indented-tree.
+;;; 16-JUL-90 mk Functions with argument lists of () were being ignored
+;;; because of a (when form) wrapped around the body of
+;;; record-callers. Then intent of (when form) was as an extra
+;;; safeguard against infinite looping. This wasn't really
+;;; necessary, so it has been removed.
+;;; 16-JUL-90 mk PSGraph-XREF now has keyword arguments, instead of
+;;; optionals.
+;;; 16-JUL-90 mk Added PRINT-CLASS-HIERARCHY to use psgraph to graph the
+;;; CLOS class hierarchy. This really doesn't belong here,
+;;; and should be moved to psgraph.lisp as an example of how
+;;; to use psgraph.
+;;; 16-JUL-90 mk Fixed several caller patterns. The pattern for member
+;;; had an error which caused many references to be missed.
+;;; 16-JUL-90 mk Added ability to save/load processed databases.
+;;; 5-JUL-91 mk Fixed warning of needing compilation to occur only when the
+;;; source is loaded.
+;;; 20-SEP-93 mk Added fix from Peter Norvig to allow Xref to xref itself.
+;;; The arg to macro-function must be a symbol.
+
+;;; ********************************
+;;; To Do **************************
+;;; ********************************
+;;;
+;;; Verify that:
+;;; o null forms don't cause it to infinite loop.
+;;; o nil matches against null argument lists.
+;;; o declarations and doc are being ignored.
+;;;
+;;; Would be nice if in addition to showing callers of a function, it
+;;; displayed the context of the calls to the function (e.g., the
+;;; immediately surrounding form). This entails storing entries of
+;;; the form (symbol context*) in the database and augmenting
+;;; record-callers to keep the context around. The only drawbacks is
+;;; that it would cons a fair bit. If we do this, we should store
+;;; additional information as well in the database, such as the caller
+;;; pattern type (e.g., variable vs. function).
+;;;
+;;; Write a translator from BNF (at least as much of BNF as is used
+;;; in CLtL2), to the format used here.
+;;;
+;;; Should automatically add new patterns for new functions and macros
+;;; based on their arglists. Probably requires much more than this
+;;; simple code walker, so there isn't much we can do.
+;;;
+;;; Defmacro is a problem, because it often hides internal function
+;;; calls within backquote and quote, which we normally ignore. If
+;;; we redefine QUOTE's pattern so that it treats the arg like a FORM,
+;;; we'll probably get them (though maybe the syntax will be mangled),
+;;; but most likely a lot of spurious things as well.
+;;;
+;;; Define an operation for Defsystem which will run XREF-FILE on the
+;;; files of the system. Or yet simpler, when XREF sees a LOAD form
+;;; for which the argument is a string, tries to recursively call
+;;; XREF-FILE on the specified file. Then one could just XREF-FILE
+;;; the file which loads the system. (This should be a program
+;;; parameter.)
+;;;
+;;; Have special keywords which the user may place in a file to have
+;;; XREF-FILE ignore a region.
+;;;
+;;; Should we distinguish flet and labels from defun? I.e., note that
+;;; flet's definitions are locally defined, instead of just lumping
+;;; them in with regular definitions.
+;;;
+;;; Add patterns for series, loop macro.
+;;;
+;;; Need to integrate the variable reference database with the other
+;;; databases, yet maintain separation. So we can distinguish all
+;;; the different types of variable and function references, without
+;;; multiplying databases.
+;;;
+;;; Would pay to comment record-callers and record-callers* in more
+;;; depth.
+;;;
+;;; (&OPTIONAL &REST &KEY &AUX &BODY &WHOLE &ALLOW-OTHER-KEYS &ENVIRONMENT)
+
+;;; ********************************
+;;; Notes **************************
+;;; ********************************
+;;;
+;;; XREF has been tested (successfully) in the following lisps:
+;;; CMU Common Lisp (M2.9 15-Aug-90, Compiler M1.8 15-Aug-90)
+;;; Macintosh Allegro Common Lisp (1.3.2)
+;;; ExCL (Franz Allegro CL 3.1.12 [DEC 3100] 3/30/90)
+;;; Lucid CL (Version 2.1 6-DEC-87)
+;;;
+;;; XREF has been tested (unsuccessfully) in the following lisps:
+;;; Ibuki Common Lisp (01/01, October 15, 1987)
+;;; - if interpreted, runs into stack overflow
+;;; - does not compile (tried ibcl on Suns, PMAXes and RTs)
+;;; seems to be due to a limitation in the c compiler.
+;;;
+;;; XREF needs to be tested in the following lisps:
+;;; Symbolics Common Lisp (8.0)
+;;; Lucid Common Lisp (3.0, 4.0)
+;;; KCL (June 3, 1987 or later)
+;;; AKCL (1.86, June 30, 1987 or later)
+;;; TI (Release 4.1 or later)
+;;; Golden Common Lisp (3.1 IBM-PC)
+;;; VAXLisp (2.0, 3.1)
+;;; HP Common Lisp (same as Lucid?)
+;;; Procyon Common Lisp
+
+
+;;; ****************************************************************
+;;; Documentation **************************************************
+;;; ****************************************************************
+;;;
+;;; XREF analyzes a user's program, determining which functions call a
+;;; given function, and the location of where variables are bound/assigned
+;;; and used. The user may retrieve this information for either a single
+;;; symbol, or display the call graph of portions of the program
+;;; (including the entire program). This allows the programmer to debug
+;;; and document the program's structure.
+;;;
+;;; XREF is primarily intended for analyzing large programs, where it is
+;;; difficult, if not impossible, for the programmer to grasp the structure
+;;; of the whole program. Nothing precludes using XREF for smaller programs,
+;;; where it can be useful for inspecting the relationships between pieces
+;;; of the program and for documenting the program.
+;;;
+;;; Two aspects of the Lisp programming language greatly simplify the
+;;; analysis of Lisp programs:
+;;; o Lisp programs are naturally represented as data.
+;;; Successive definitions from a file are easily read in
+;;; as list structure.
+;;; o The basic syntax of Lisp is uniform. A list program
+;;; consists of a set of nested forms, where each form is
+;;; a list whose car is a tag (e.g., function name) that
+;;; specifies the structure of the rest of the form.
+;;; Thus Lisp programs, when represented as data, can be considered to be
+;;; parse trees. Given a grammar of syntax patterns for the language, XREF
+;;; recursively descends the parse tree for a given definition, computing
+;;; a set of relations that hold for the definition at each node in the
+;;; tree. For example, one kind of relation is that the function defined
+;;; by the definition calls the functions in its body. The relations are
+;;; stored in a database for later examination by the user.
+;;;
+;;; While XREF currently only works for programs written in Lisp, it could
+;;; be extended to other programming languages by writing a function to
+;;; generate parse trees for definitions in that language, and a core
+;;; set of patterns for the language's syntax.
+;;;
+;;; Since XREF normally does a static syntactic analysis of the program,
+;;; it does not detect references due to the expansion of a macro definition.
+;;; To do this in full generality XREF would have to have knowledge about the
+;;; semantics of the program (e.g., macros which call other functions to
+;;; do the expansion). This entails either modifying the compiler to
+;;; record the relationships (e.g., Symbolics Who-Calls Database) or doing
+;;; a walk of loaded code and macroexpanding as needed (PCL code walker).
+;;; The former is not portable, while the latter requires that the code
+;;; used by macros be loaded and in working order. On the other hand, then
+;;; we would need no special knowledge about macros (excluding the 24 special
+;;; forms of Lisp).
+;;;
+;;; Parameters may be set to enable macro expansion in XREF. Then XREF
+;;; will expand any macros for which it does not have predefined patterns.
+;;; (For example, most Lisps will implement dolist as a macro. Since XREF
+;;; has a pattern defined for dolist, it will not call macroexpand-1 on
+;;; a form whose car is dolist.) For this to work properly, the code must
+;;; be loaded before being processed by XREF, and XREF's parameters should
+;;; be set so that it processes forms in their proper packages.
+;;;
+;;; If macro expansion is disabled, the default rules for handling macro
+;;; references may not be sufficient for some user-defined macros, because
+;;; macros allow a variety of non-standard syntactic extensions to the
+;;; language. In this case, the user may specify additional templates in
+;;; a manner similar to that in which the core Lisp grammar was specified.
+;;;
+
+
+;;; ********************************
+;;; User Guide *********************
+;;; ********************************
+;;; -----
+;;; The following functions are called to cross reference the source files.
+;;;
+;;; XREF-FILES (&rest files) [FUNCTION]
+;;; Grovels over the lisp code located in source file FILES, using
+;;; xref-file.
+;;;
+;;; XREF-FILE (filename &optional clear-tables verbose) [Function]
+;;; Cross references the function and variable calls in FILENAME by
+;;; walking over the source code located in the file. Defaults type of
+;;; filename to ".lisp". Chomps on the code using record-callers and
+;;; record-callers*. If CLEAR-TABLES is T (the default), it clears the
+;;; callers database before processing the file. Specify CLEAR-TABLES as
+;;; nil to append to the database. If VERBOSE is T (the default), prints
+;;; out the name of the file, one progress dot for each form processed,
+;;; and the total number of forms.
+;;;
+;;; -----
+;;; The following functions display information about the uses of the
+;;; specified symbol as a function, variable, or constant.
+;;;
+;;; LIST-CALLERS (symbol) [FUNCTION]
+;;; Lists all functions which call SYMBOL as a function (function
+;;; invocation).
+;;;
+;;; LIST-READERS (symbol) [FUNCTION]
+;;; Lists all functions which refer to SYMBOL as a variable
+;;; (variable reference).
+;;;
+;;; LIST-SETTERS (symbol) [FUNCTION]
+;;; Lists all functions which bind/set SYMBOL as a variable
+;;; (variable mutation).
+;;;
+;;; LIST-USERS (symbol) [FUNCTION]
+;;; Lists all functions which use SYMBOL as a variable or function.
+;;;
+;;; WHO-CALLS (symbol &optional how) [FUNCTION]
+;;; Lists callers of symbol. HOW may be :function, :reader, :setter,
+;;; or :variable."
+;;;
+;;; WHAT-FILES-CALL (symbol) [FUNCTION]
+;;; Lists names of files that contain uses of SYMBOL
+;;; as a function, variable, or constant.
+;;;
+;;; SOURCE-FILE (symbol) [FUNCTION]
+;;; Lists the names of files in which SYMBOL is defined/used.
+;;;
+;;; LIST-CALLEES (symbol) [FUNCTION]
+;;; Lists names of functions and variables called by SYMBOL.
+;;;
+;;; -----
+;;; The following functions may be useful for viewing the database and
+;;; debugging the calling patterns.
+;;;
+;;; *LAST-FORM* () [VARIABLE]
+;;; The last form read from the file. Useful for figuring out what went
+;;; wrong when xref-file drops into the debugger.
+;;;
+;;; *XREF-VERBOSE* t [VARIABLE]
+;;; When T, xref-file(s) prints out the names of the files it looks at,
+;;; progress dots, and the number of forms read.
+;;;
+;;; *TYPES-TO-IGNORE* (quote (:lisp :lisp2)) [VARIABLE]
+;;; Default set of caller types (as specified in the patterns) to ignore
+;;; in the database handling functions. :lisp is CLtL 1st edition,
+;;; :lisp2 is additional patterns from CLtL 2nd edition.
+;;;
+;;; *HANDLE-PACKAGE-FORMS* () [VARIABLE]
+;;; When non-NIL, and XREF-FILE sees a package-setting form like
+;;; IN-PACKAGE, sets the current package to the specified package by
+;;; evaluating the form. When done with the file, xref-file resets the
+;;; package to its original value. In some of the displaying functions,
+;;; when this variable is non-NIL one may specify that all symbols from a
+;;; particular set of packages be ignored. This is only useful if the
+;;; files use different packages with conflicting names.
+;;;
+;;; *HANDLE-FUNCTION-FORMS* t [VARIABLE]
+;;; When T, XREF-FILE tries to be smart about forms which occur in
+;;; a function position, such as lambdas and arbitrary Lisp forms.
+;;; If so, it recursively calls record-callers with pattern 'FORM.
+;;; If the form is a lambda, makes the caller a caller of
+;;; :unnamed-lambda.
+;;;
+;;; *HANDLE-MACRO-FORMS* t [VARIABLE]
+;;; When T, if the file was loaded before being processed by XREF, and
+;;; the car of a form is a macro, it notes that the parent calls the
+;;; macro, and then calls macroexpand-1 on the form.
+;;;
+;;; *DEFAULT-GRAPHING-MODE* :call-graph [VARIABLE]
+;;; Specifies whether we graph up or down. If :call-graph, the children
+;;; of a node are the functions it calls. If :caller-graph, the
+;;; children of a node are the functions that call it.
+;;;
+;;; *INDENT-AMOUNT* 3 [VARIABLE]
+;;; Number of spaces to indent successive levels in PRINT-INDENTED-TREE.
+;;;
+;;; DISPLAY-DATABASE (&optional database types-to-ignore) [FUNCTION]
+;;; Prints out the name of each symbol and all its callers. Specify
+;;; database :callers (the default) to get function call references,
+;;; :file to the get files in which the symbol is called, :readers to get
+;;; variable references, and :setters to get variable binding and
+;;; assignments. Ignores functions of types listed in types-to-ignore.
+;;;
+;;; PRINT-CALLER-TREES (&key (mode *default-graphing-mode*) [FUNCTION]
+;;; (types-to-ignore *types-to-ignore*)
+;;; compact root-nodes)
+;;; Prints the calling trees (which may actually be a full graph and not
+;;; necessarily a DAG) as indented text trees using
+;;; PRINT-INDENTED-TREE. MODE is :call-graph for trees where the children
+;;; of a node are the functions called by the node, or :caller-graph for
+;;; trees where the children of a node are the functions the node calls.
+;;; TYPES-TO-IGNORE is a list of funcall types (as specified in the
+;;; patterns) to ignore in printing out the database. For example,
+;;; '(:lisp) would ignore all calls to common lisp functions. COMPACT is
+;;; a flag to tell the program to try to compact the trees a bit by not
+;;; printing trees if they have already been seen. ROOT-NODES is a list
+;;; of root nodes of trees to display. If ROOT-NODES is nil, tries to
+;;; find all root nodes in the database.
+;;;
+;;; MAKE-CALLER-TREE (&optional (mode *default-graphing-mode*) [FUNCTION]
+;;; (types-to-ignore *types-to-ignore*)
+;;; compact)
+;;; Outputs list structure of a tree which roughly represents the
+;;; possibly cyclical structure of the caller database.
+;;; If mode is :call-graph, the children of a node are the functions
+;;; it calls. If mode is :caller-graph, the children of a node are the
+;;; functions that call it.
+;;; If compact is T, tries to eliminate the already-seen nodes, so
+;;; that the graph for a node is printed at most once. Otherwise it will
+;;; duplicate the node's tree (except for cycles). This is usefull
+;;; because the call tree is actually a directed graph, so we can either
+;;; duplicate references or display only the first one.
+;;;
+;;; DETERMINE-FILE-DEPENDENCIES (&optional database) [FUNCTION]
+;;; Makes a hash table of file dependencies for the references listed in
+;;; DATABASE. This function may be useful for automatically resolving
+;;; file references for automatic creation of a system definition
+;;; (defsystem).
+;;;
+;;; PRINT-FILE-DEPENDENCIES (&optional database) [FUNCTION]
+;;; Prints a list of file dependencies for the references listed in
+;;; DATABASE. This function may be useful for automatically computing
+;;; file loading constraints for a system definition tool.
+;;;
+;;; WRITE-CALLERS-DATABASE-TO-FILE (filename) [FUNCTION]
+;;; Saves the contents of the current callers database to a file. This
+;;; file can be loaded to restore the previous contents of the
+;;; database. (For large systems it can take a long time to crunch
+;;; through the code, so this can save some time.)
+;;;
+;;; -----
+;;; The following macros define new function and macro call patterns.
+;;; They may be used to extend the static analysis tool to handle
+;;; new def forms, extensions to Common Lisp, and program defs.
+;;;
+;;; DEFINE-PATTERN-SUBSTITUTION (name pattern) [MACRO]
+;;; Defines NAME to be equivalent to the specified pattern. Useful for
+;;; making patterns more readable. For example, the LAMBDA-LIST is
+;;; defined as a pattern substitution, making the definition of the
+;;; DEFUN caller-pattern simpler.
+;;;
+;;; DEFINE-CALLER-PATTERN (name pattern &optional caller-type) [MACRO]
+;;; Defines NAME as a function/macro call with argument structure
+;;; described by PATTERN. CALLER-TYPE, if specified, assigns a type to
+;;; the pattern, which may be used to exclude references to NAME while
+;;; viewing the database. For example, all the Common Lisp definitions
+;;; have a caller-type of :lisp or :lisp2, so that you can exclude
+;;; references to common lisp functions from the calling tree.
+;;;
+;;; DEFINE-VARIABLE-PATTERN (name &optional caller-type) [MACRO]
+;;; Defines NAME as a variable reference of type CALLER-TYPE. This is
+;;; mainly used to establish the caller-type of the variable.
+;;;
+;;; DEFINE-CALLER-PATTERN-SYNONYMS (source destinations) [MACRO]
+;;; For defining function caller pattern syntax synonyms. For each name
+;;; in DESTINATIONS, defines its pattern as a copy of the definition
+;;; of SOURCE. Allows a large number of identical patterns to be defined
+;;; simultaneously. Must occur after the SOURCE has been defined.
+;;;
+;;; -----
+;;; This system includes pattern definitions for the latest
+;;; common lisp specification, as published in Guy Steele,
+;;; Common Lisp: The Language, 2nd Edition.
+;;;
+;;; Patterns may be either structures to match, or a predicate
+;;; like symbolp/numberp/stringp. The pattern specification language
+;;; is similar to the notation used in CLtL2, but in a more lisp-like
+;;; form:
+;;; (:eq name) The form element must be eq to the symbol NAME.
+;;; (:test test) TEST must be true when applied to the form element.
+;;; (:typep type) The form element must be of type TYPE.
+;;; (:or pat1 pat2 ...) Tries each of the patterns in left-to-right order,
+;;; until one succeeds.
+;;; Equivalent to { pat1 | pat2 | ... }
+;;; (:rest pattern) The remaining form elements are grouped into a
+;;; list which is matched against PATTERN.
+;;; (:optional pat1 ...) The patterns may optionally match against the
+;;; form element.
+;;; Equivalent to [ pat1 ... ].
+;;; (:star pat1 ...) The patterns may match against the patterns
+;;; any number of times, including 0.
+;;; Equivalent to { pat1 ... }*.
+;;; (:plus pat1 ...) The patterns may match against the patterns
+;;; any number of times, but at least once.
+;;; Equivalent to { pat1 ... }+.
+;;; &optional, &key, Similar in behavior to the corresponding
+;;; &rest lambda-list keywords.
+;;; FORM A random lisp form. If a cons, assumes the
+;;; car is a function or macro and tries to
+;;; match the args against that symbol's pattern.
+;;; If a symbol, assumes it's a variable reference.
+;;; :ignore Ignores the corresponding form element.
+;;; NAME The corresponding form element should be
+;;; the name of a new definition (e.g., the
+;;; first arg in a defun pattern is NAME.
+;;; FUNCTION, MACRO The corresponding form element should be
+;;; a function reference not handled by FORM.
+;;; Used in the definition of apply and funcall.
+;;; VAR The corresponding form element should be
+;;; a variable definition or mutation. Used
+;;; in the definition of let, let*, etc.
+;;; VARIABLE The corresponding form element should be
+;;; a variable reference.
+;;;
+;;; In all other pattern symbols, it looks up the symbols pattern substitution
+;;; and recursively matches against the pattern. Automatically destructures
+;;; list structure that does not include consing dots.
+;;;
+;;; Among the pattern substitution names defined are:
+;;; STRING, SYMBOL, NUMBER Appropriate :test patterns.
+;;; LAMBDA-LIST Matches against a lambda list.
+;;; BODY Matches against a function body definition.
+;;; FN Matches against #'function, 'function,
+;;; and lambdas. This is used in the definition
+;;; of apply, funcall, and the mapping patterns.
+;;; and others...
+;;;
+;;; Here's some sample pattern definitions:
+;;; (define-caller-pattern defun
+;;; (name lambda-list
+;;; (:star (:or documentation-string declaration))
+;;; (:star form))
+;;; :lisp)
+;;; (define-caller-pattern funcall (fn (:star form)) :lisp)
+;;;
+;;; In general, the system is intelligent enough to handle any sort of
+;;; simple funcall. One only need specify the syntax for functions and
+;;; macros which use optional arguments, keyword arguments, or some
+;;; argument positions are special, such as in apply and funcall, or
+;;; to indicate that the function is of the specified caller type.
+;;;
+;;;
+;;; NOTES:
+;;;
+;;; XRef assumes syntactically correct lisp code.
+;;;
+;;; This is by no means perfect. For example, let and let* are treated
+;;; identically, instead of differentiating between serial and parallel
+;;; binding. But it's still a useful tool. It can be helpful in
+;;; maintaining code, debugging problems with patch files, determining
+;;; whether functions are multiply defined, and help you remember where
+;;; a function is defined or called.
+;;;
+;;; XREF runs best when compiled.
+
+;;; ********************************
+;;; References *********************
+;;; ********************************
+;;;
+;;; Xerox Interlisp Masterscope Program:
+;;; Larry M Masinter, Global program analysis in an interactive environment
+;;; PhD Thesis, Stanford University, 1980.
+;;;
+;;; Symbolics Who-Calls Database:
+;;; User's Guide to Symbolics Computers, Volume 1, Cambridge, MA, July 1986
+;;; Genera 7.0, pp 183-185.
+;;;
+
+;;; ********************************
+;;; Example ************************
+;;; ********************************
+;;;
+;;; Here is an example of running XREF on a short program.
+;;; [In Scribe documentation, give a simple short program and resulting
+;;; XREF output, including postscript call graphs.]
+#|
+<cl> (xref:xref-file "/afs/cs/user/mkant/Lisp/Graph-Dag/graph-dag.lisp")
+Cross-referencing file /afs/cs/user/mkant/Lisp/Graph-Dag/graph-dag.lisp.
+................................................
+48 forms processed.
+<cl> (xref:display-database :readers)
+
+*DISPLAY-CUTOFF-DEPTH* is referenced by CALCULATE-LEVEL-POSITION CALCULATE-LEVEL-POSITION-BEFORE CALCULATE-POSITION-IN-LEVEL.
+*OFFSET-FROM-EDGE-OF-PANE* is referenced by CALCULATE-LEVEL-POSITION CALCULATE-LEVEL-POSITION-BEFORE.
+*WITHIN-LEVEL-SPACING* is referenced by BREADTH CALCULATE-POSITION-INFO.
+*DIRECTION* is referenced by CREATE-POSITION-INFO.
+*LINK-OFFSET* is referenced by OFFSET-OF-LINK-FROM-ATTACHMENT-POINT.
+*ROOT-IS-SEQUENCE* is referenced by GRAPH.
+*LEVEL-SPACING* is referenced by CALCULATE-LEVEL-POSITION CALCULATE-LEVEL-POSITION-BEFORE.
+*ORIENTATION* is referenced by BREADTH CALCULATE-LEVEL-POSITION CALCULATE-LEVEL-POSITION-BEFORE CALCULATE-POSITION-IN-LEVEL.
+*DEFAULT-GRAPH-POSITION* is referenced by CREATE-POSITION-INFO.
+*GRAPHING-CUTOFF-DEPTH* is referenced by CREATE-NODE-STRUCTURE.
+*LIST-OF-NODES* is referenced by CALCULATE-LEVEL-POSITION CALCULATE-LEVEL-POSITION-BEFORE CREATE-NODE FIND-NODE.
+*GRAPH-TYPE* is referenced by CREATE-NODE-STRUCTURE.
+<cl> (xref:print-caller-trees :root-nodes '(display-graph))
+
+Rooted calling trees:
+ DISPLAY-GRAPH
+ CREATE-POSITION-INFO
+ CALCULATE-POSITION-INFO
+ CALCULATE-POSITION
+ NODE-POSITION-ALREADY-SET-FLAG
+ NODE-LEVEL-ALREADY-SET-FLAG
+ CALCULATE-POSITION-IN-LEVEL
+ NODE-CHILDREN
+ NODE-LEVEL
+ CALCULATE-POSITION
+ NEW-CALCULATE-BREADTH
+ NODE-CHILDREN
+ BREADTH
+ OPPOSITE-DIMENSION
+ NODE-HEIGHT
+ NODE-WIDTH
+ NEW-CALCULATE-BREADTH
+ NODE-PARENTS
+ OPPOSITE-DIMENSION
+ NODE-HEIGHT
+ NODE-WIDTH
+ OPPOSITE-POSITION
+ NODE-Y
+ NODE-X
+ NODE-LEVEL
+ CALCULATE-LEVEL-POSITION
+ NODE-LEVEL
+ NODE-POSITION
+ NODE-X
+ NODE-Y
+ DIMENSION
+ NODE-WIDTH
+ NODE-HEIGHT
+ CALCULATE-LEVEL-POSITION-BEFORE
+ NODE-LEVEL
+ NODE-POSITION
+ NODE-X
+ NODE-Y
+ NODE-WIDTH
+ NODE-HEIGHT
+ DIMENSION
+ NODE-WIDTH
+ NODE-HEIGHT
+|#
+
+;;; ****************************************************************
+;;; List Callers ***************************************************
+;;; ****************************************************************
+
+(defpackage :pxref
+ (:use :common-lisp)
+ (:export #:list-callers
+ #:list-users
+ #:list-readers
+ #:list-setters
+ #:what-files-call
+ #:who-calls
+ #:list-callees
+ #:source-file
+ #:clear-tables
+ #:define-pattern-substitution
+ #:define-caller-pattern
+ #:define-variable-pattern
+ #:define-caller-pattern-synonyms
+ #:clear-patterns
+ #:*last-form*
+ #:*xref-verbose*
+ #:*handle-package-forms*
+ #:*handle-function-forms*
+ #:*handle-macro-forms*
+ #:*types-to-ignore*
+ #:*last-caller-tree*
+ #:*default-graphing-mode*
+ #:*indent-amount*
+ #:xref-file
+ #:xref-files
+ #:write-callers-database-to-file
+ #:display-database
+ #:print-caller-trees
+ #:make-caller-tree
+ #:print-indented-tree
+ #:determine-file-dependencies
+ #:print-file-dependencies
+ #:psgraph-xref
+ ))
+
+(in-package "PXREF")
+
+;;; Warn user if they're loading the source instead of compiling it first.
+;(eval-when (compile load eval)
+; (defvar compiled-p nil))
+;(eval-when (compile load)
+; (setq compiled-p t))
+;(eval-when (load eval)
+; (unless compiled-p
+; (warn "This file should be compiled before loading for best results.")))
+(eval-when (eval)
+ (warn "This file should be compiled before loading for best results."))
+
+
+;;; ********************************
+;;; Primitives *********************
+;;; ********************************
+(defun lookup (symbol environment)
+ (dolist (frame environment)
+ (when (member symbol frame)
+ (return symbol))))
+
+(defun car-eq (list item)
+ (and (consp list)
+ (eq (car list) item)))
+
+;;; ********************************
+;;; Callers Database ***************
+;;; ********************************
+(defvar *file-callers-database* (make-hash-table :test #'equal)
+ "Contains name and list of file callers (files which call) for that name.")
+(defvar *callers-database* (make-hash-table :test #'equal)
+ "Contains name and list of callers (function invocation) for that name.")
+(defvar *readers-database* (make-hash-table :test #'equal)
+ "Contains name and list of readers (variable use) for that name.")
+(defvar *setters-database* (make-hash-table :test #'equal)
+ "Contains name and list of setters (variable mutation) for that name.")
+(defvar *callees-database* (make-hash-table :test #'equal)
+ "Contains name and list of functions and variables it calls.")
+(defun callers-list (name &optional (database :callers))
+ (case database
+ (:file (gethash name *file-callers-database*))
+ (:callees (gethash name *callees-database*))
+ (:callers (gethash name *callers-database*))
+ (:readers (gethash name *readers-database*))
+ (:setters (gethash name *setters-database*))))
+(defsetf callers-list (name &optional (database :callers)) (caller)
+ `(setf (gethash ,name (case ,database
+ (:file *file-callers-database*)
+ (:callees *callees-database*)
+ (:callers *callers-database*)
+ (:readers *readers-database*)
+ (:setters *setters-database*)))
+ ,caller))
+
+(defun list-callers (symbol)
+ "Lists all functions which call SYMBOL as a function (function invocation)."
+ (callers-list symbol :callers))
+(defun list-readers (symbol)
+ "Lists all functions which refer to SYMBOL as a variable
+ (variable reference)."
+ (callers-list symbol :readers))
+(defun list-setters (symbol)
+ "Lists all functions which bind/set SYMBOL as a variable
+ (variable mutation)."
+ (callers-list symbol :setters))
+(defun list-users (symbol)
+ "Lists all functions which use SYMBOL as a variable or function."
+ (values (list-callers symbol)
+ (list-readers symbol)
+ (list-setters symbol)))
+(defun who-calls (symbol &optional how)
+ "Lists callers of symbol. HOW may be :function, :reader, :setter,
+ or :variable."
+ ;; would be nice to have :macro and distinguish variable
+ ;; binding from assignment. (i.e., variable binding, assignment, and use)
+ (case how
+ (:function (list-callers symbol))
+ (:reader (list-readers symbol))
+ (:setter (list-setters symbol))
+ (:variable (append (list-readers symbol)
+ (list-setters symbol)))
+ (otherwise (append (list-callers symbol)
+ (list-readers symbol)
+ (list-setters symbol)))))
+(defun what-files-call (symbol)
+ "Lists names of files that contain uses of SYMBOL
+ as a function, variable, or constant."
+ (callers-list symbol :file))
+(defun list-callees (symbol)
+ "Lists names of functions and variables called by SYMBOL."
+ (callers-list symbol :callees))
+
+(defvar *source-file* (make-hash-table :test #'equal)
+ "Contains function name and source file for that name.")
+(defun source-file (symbol)
+ "Lists the names of files in which SYMBOL is defined/used."
+ (gethash symbol *source-file*))
+(defsetf source-file (name) (value)
+ `(setf (gethash ,name *source-file*) ,value))
+
+(defun clear-tables ()
+ (clrhash *file-callers-database*)
+ (clrhash *callers-database*)
+ (clrhash *callees-database*)
+ (clrhash *readers-database*)
+ (clrhash *setters-database*)
+ (clrhash *source-file*))
+
+
+;;; ********************************
+;;; Pattern Database ***************
+;;; ********************************
+;;; Pattern Types
+(defvar *pattern-caller-type* (make-hash-table :test #'equal))
+(defun pattern-caller-type (name)
+ (gethash name *pattern-caller-type*))
+(defsetf pattern-caller-type (name) (value)
+ `(setf (gethash ,name *pattern-caller-type*) ,value))
+
+;;; Pattern Substitutions
+(defvar *pattern-substitution-table* (make-hash-table :test #'equal)
+ "Stores general patterns for function destructuring.")
+(defun lookup-pattern-substitution (name)
+ (gethash name *pattern-substitution-table*))
+(defmacro define-pattern-substitution (name pattern)
+ "Defines NAME to be equivalent to the specified pattern. Useful for
+ making patterns more readable. For example, the LAMBDA-LIST is
+ defined as a pattern substitution, making the definition of the
+ DEFUN caller-pattern simpler."
+ `(setf (gethash ',name *pattern-substitution-table*)
+ ',pattern))
+
+;;; Function/Macro caller patterns:
+;;; The car of the form is skipped, so we don't need to specify
+;;; (:eq function-name) like we would for a substitution.
+;;;
+;;; Patterns must be defined in the XREF package because the pattern
+;;; language is tested by comparing symbols (using #'equal) and not
+;;; their printreps. This is fine for the lisp grammer, because the XREF
+;;; package depends on the LISP package, so a symbol like 'xref::cons is
+;;; translated automatically into 'lisp::cons. However, since
+;;; (equal 'foo::bar 'baz::bar) returns nil unless both 'foo::bar and
+;;; 'baz::bar are inherited from the same package (e.g., LISP),
+;;; if package handling is turned on the user must specify package
+;;; names in the caller pattern definitions for functions that occur
+;;; in packages other than LISP, otherwise the symbols will not match.
+;;;
+;;; Perhaps we should enforce the definition of caller patterns in the
+;;; XREF package by wrapping the body of define-caller-pattern in
+;;; the XREF package:
+;;; (defmacro define-caller-pattern (name value &optional caller-type)
+;;; (let ((old-package *package*))
+;;; (setf *package* (find-package "XREF"))
+;;; (prog1
+;;; `(progn
+;;; (when ',caller-type
+;;; (setf (pattern-caller-type ',name) ',caller-type))
+;;; (when ',value
+;;; (setf (gethash ',name *caller-pattern-table*)
+;;; ',value)))
+;;; (setf *package* old-package))))
+;;; Either that, or for the purpose of pattern testing we should compare
+;;; printreps. [The latter makes the primitive patterns like VAR
+;;; reserved words.]
+(defvar *caller-pattern-table* (make-hash-table :test #'equal)
+ "Stores patterns for function destructuring.")
+(defun lookup-caller-pattern (name)
+ (gethash name *caller-pattern-table*))
+(defmacro define-caller-pattern (name pattern &optional caller-type)
+ "Defines NAME as a function/macro call with argument structure
+ described by PATTERN. CALLER-TYPE, if specified, assigns a type to
+ the pattern, which may be used to exclude references to NAME while
+ viewing the database. For example, all the Common Lisp definitions
+ have a caller-type of :lisp or :lisp2, so that you can exclude
+ references to common lisp functions from the calling tree."
+ `(progn
+ (when ',caller-type
+ (setf (pattern-caller-type ',name) ',caller-type))
+ (when ',pattern
+ (setf (gethash ',name *caller-pattern-table*)
+ ',pattern))))
+
+;;; For defining variables
+(defmacro define-variable-pattern (name &optional caller-type)
+ "Defines NAME as a variable reference of type CALLER-TYPE. This is
+ mainly used to establish the caller-type of the variable."
+ `(progn
+ (when ',caller-type
+ (setf (pattern-caller-type ',name) ',caller-type))))
+
+;;; For defining synonyms. Means much less space taken up by the patterns.
+(defmacro define-caller-pattern-synonyms (source destinations)
+ "For defining function caller pattern syntax synonyms. For each name
+ in DESTINATIONS, defines its pattern as a copy of the definition of SOURCE.
+ Allows a large number of identical patterns to be defined simultaneously.
+ Must occur after the SOURCE has been defined."
+ `(let ((source-type (pattern-caller-type ',source))
+ (source-pattern (gethash ',source *caller-pattern-table*)))
+ (when source-type
+ (dolist (dest ',destinations)
+ (setf (pattern-caller-type dest) source-type)))
+ (when source-pattern
+ (dolist (dest ',destinations)
+ (setf (gethash dest *caller-pattern-table*)
+ source-pattern)))))
+
+(defun clear-patterns ()
+ (clrhash *pattern-substitution-table*)
+ (clrhash *caller-pattern-table*)
+ (clrhash *pattern-caller-type*))
+
+;;; ********************************
+;;; Cross Reference Files **********
+;;; ********************************
+(defvar *last-form* ()
+ "The last form read from the file. Useful for figuring out what went wrong
+ when xref-file drops into the debugger.")
+
+(defvar *xref-verbose* t
+ "When T, xref-file(s) prints out the names of the files it looks at,
+ progress dots, and the number of forms read.")
+
+;;; This needs to first clear the tables?
+(defun xref-files (&rest files)
+ "Grovels over the lisp code located in source file FILES, using xref-file."
+ ;; If the arg is a list, use it.
+ (when (listp (car files)) (setq files (car files)))
+ (dolist (file files)
+ (xref-file file nil))
+ (values))
+
+(defvar *handle-package-forms* nil ;'(lisp::in-package)
+ "When non-NIL, and XREF-FILE sees a package-setting form like IN-PACKAGE,
+ sets the current package to the specified package by evaluating the
+ form. When done with the file, xref-file resets the package to its
+ original value. In some of the displaying functions, when this variable
+ is non-NIL one may specify that all symbols from a particular set of
+ packages be ignored. This is only useful if the files use different
+ packages with conflicting names.")
+
+(defvar *normal-readtable* (copy-readtable nil)
+ "Normal, unadulterated CL readtable.")
+
+(defun xref-file (filename &optional (clear-tables t) (verbose *xref-verbose*))
+ "Cross references the function and variable calls in FILENAME by
+ walking over the source code located in the file. Defaults type of
+ filename to \".lisp\". Chomps on the code using record-callers and
+ record-callers*. If CLEAR-TABLES is T (the default), it clears the callers
+ database before processing the file. Specify CLEAR-TABLES as nil to
+ append to the database. If VERBOSE is T (the default), prints out the
+ name of the file, one progress dot for each form processed, and the
+ total number of forms."
+ ;; Default type to "lisp"
+ (when (and (null (pathname-type filename))
+ (not (probe-file filename)))
+ (cond ((stringp filename)
+ (setf filename (concatenate 'string filename ".lisp")))
+ ((pathnamep filename)
+ (setf filename (merge-pathnames filename
+ (make-pathname :type "lisp"))))))
+ (when clear-tables (clear-tables))
+ (let ((count 0)
+ (old-package *package*)
+ (*readtable* *normal-readtable*))
+ (when verbose
+ (format t "~&Cross-referencing file ~A.~&" filename))
+ (with-open-file (stream filename :direction :input)
+ (do ((form (read stream nil :eof) (read stream nil :eof)))
+ ((eq form :eof))
+ (incf count)
+ (when verbose
+ (format *standard-output* ".")
+ (force-output *standard-output*))
+ (setq *last-form* form)
+ (record-callers filename form)
+ ;; Package Magic.
+ (when (and *handle-package-forms*
+ (consp form)
+ (member (car form) *handle-package-forms*))
+ (eval form))))
+ (when verbose
+ (format t "~&~D forms processed." count))
+ (setq *package* old-package)
+ (values)))
+
+(defvar *handle-function-forms* t
+ "When T, XREF-FILE tries to be smart about forms which occur in
+ a function position, such as lambdas and arbitrary Lisp forms.
+ If so, it recursively calls record-callers with pattern 'FORM.
+ If the form is a lambda, makes the caller a caller of :unnamed-lambda.")
+
+(defvar *handle-macro-forms* t
+ "When T, if the file was loaded before being processed by XREF, and the
+ car of a form is a macro, it notes that the parent calls the macro,
+ and then calls macroexpand-1 on the form.")
+
+(defvar *callees-database-includes-variables* nil)
+
+(defun record-callers (filename form
+ &optional pattern parent (environment nil)
+ funcall)
+ "RECORD-CALLERS is the main routine used to walk down the code. It matches
+ the PATTERN against the FORM, possibly adding statements to the database.
+ PARENT is the name defined by the current outermost definition; it is
+ the caller of the forms in the body (e.g., FORM). ENVIRONMENT is used
+ to keep track of the scoping of variables. FUNCALL deals with the type
+ of variable assignment and hence how the environment should be modified.
+ RECORD-CALLERS handles atomic patterns and simple list-structure patterns.
+ For complex list-structure pattern destructuring, it calls RECORD-CALLERS*."
+; (when form)
+ (unless pattern (setq pattern 'FORM))
+ (cond ((symbolp pattern)
+ (case pattern
+ (:IGNORE
+ ;; Ignores the rest of the form.
+ (values t parent environment))
+ (NAME
+ ;; This is the name of a new definition.
+ (push filename (source-file form))
+ (values t form environment))
+ ((FUNCTION MACRO)
+ ;; This is the name of a call.
+ (cond ((and *handle-function-forms* (consp form))
+ ;; If we're a cons and special handling is on,
+ (when (eq (car form) 'lambda)
+ (pushnew filename (callers-list :unnamed-lambda :file))
+ (when parent
+ (pushnew parent (callers-list :unnamed-lambda
+ :callers))
+ (pushnew :unnamed-lambda (callers-list parent
+ :callees))))
+ (record-callers filename form 'form parent environment))
+ (t
+ ;; If we're just a regular function name call.
+ (pushnew filename (callers-list form :file))
+ (when parent
+ (pushnew parent (callers-list form :callers))
+ (pushnew form (callers-list parent :callees)))
+ (values t parent environment))))
+ (VAR
+ ;; This is the name of a new variable definition.
+ ;; Includes arglist parameters.
+ (when (and (symbolp form) (not (keywordp form))
+ (not (member form lambda-list-keywords)))
+ (pushnew form (car environment))
+ (pushnew filename (callers-list form :file))
+ (when parent
+; (pushnew form (callers-list parent :callees))
+ (pushnew parent (callers-list form :setters)))
+ (values t parent environment)))
+ (VARIABLE
+ ;; VAR reference
+ (pushnew filename (callers-list form :file))
+ (when (and parent (not (lookup form environment)))
+ (pushnew parent (callers-list form :readers))
+ (when *callees-database-includes-variables*
+ (pushnew form (callers-list parent :callees))))
+ (values t parent environment))
+ (FORM
+ ;; A random form (var or funcall).
+ (cond ((consp form)
+ ;; Get new pattern from TAG.
+ (let ((new-pattern (lookup-caller-pattern (car form))))
+ (pushnew filename (callers-list (car form) :file))
+ (when parent
+ (pushnew parent (callers-list (car form) :callers))
+ (pushnew (car form) (callers-list parent :callees)))
+ (cond ((and new-pattern (cdr form))
+ ;; Special Pattern and there's stuff left
+ ;; to be processed. Note that we check if
+ ;; a pattern is defined for the form before
+ ;; we check to see if we can macroexpand it.
+ (record-callers filename (cdr form) new-pattern
+ parent environment :funcall))
+ ((and *handle-macro-forms*
+ (symbolp (car form)) ; pnorvig 9/9/93
+ (macro-function (car form)))
+ ;; The car of the form is a macro and
+ ;; macro processing is turned on. Macroexpand-1
+ ;; the form and try again.
+ (record-callers filename
+ (macroexpand-1 form)
+ 'form parent environment
+ :funcall))
+ ((null (cdr form))
+ ;; No more left to be processed. Note that
+ ;; this must occur after the macros clause,
+ ;; since macros can expand into more code.
+ (values t parent environment))
+ (t
+ ;; Random Form. We assume it is a function call.
+ (record-callers filename (cdr form)
+ '((:star FORM))
+ parent environment :funcall)))))
+ (t
+ (when (and (not (lookup form environment))
+ (not (numberp form))
+ ;; the following line should probably be
+ ;; commented out?
+ (not (keywordp form))
+ (not (stringp form))
+ (not (eq form t))
+ (not (eq form nil)))
+ (pushnew filename (callers-list form :file))
+ ;; ??? :callers
+ (when parent
+ (pushnew parent (callers-list form :readers))
+ (when *callees-database-includes-variables*
+ (pushnew form (callers-list parent :callees)))))
+ (values t parent environment))))
+ (otherwise
+ ;; Pattern Substitution
+ (let ((new-pattern (lookup-pattern-substitution pattern)))
+ (if new-pattern
+ (record-callers filename form new-pattern
+ parent environment)
+ (when (eq pattern form)
+ (values t parent environment)))))))
+ ((consp pattern)
+ (case (car pattern)
+ (:eq (when (eq (second pattern) form)
+ (values t parent environment)))
+ (:test (when (funcall (eval (second pattern)) form)
+ (values t parent environment)))
+ (:typep (when (typep form (second pattern))
+ (values t parent environment)))
+ (:or (dolist (subpat (rest pattern))
+ (multiple-value-bind (processed parent environment)
+ (record-callers filename form subpat
+ parent environment)
+ (when processed
+ (return (values processed parent environment))))))
+ (:rest ; (:star :plus :optional :rest)
+ (record-callers filename form (second pattern)
+ parent environment))
+ (otherwise
+ (multiple-value-bind (d p env)
+ (record-callers* filename form pattern
+ parent (cons nil environment))
+ (values d p (if funcall environment env))))))))
+
+(defun record-callers* (filename form pattern parent environment
+ &optional continuation
+ in-optionals in-keywords)
+ "RECORD-CALLERS* handles complex list-structure patterns, such as
+ ordered lists of subpatterns, patterns involving :star, :plus,
+ &optional, &key, &rest, and so on. CONTINUATION is a stack of
+ unprocessed patterns, IN-OPTIONALS and IN-KEYWORDS are corresponding
+ stacks which determine whether &rest or &key has been seen yet in
+ the current pattern."
+ ;; form must be a cons or nil.
+; (when form)
+ (if (null pattern)
+ (if (null continuation)
+ (values t parent environment)
+ (record-callers* filename form (car continuation) parent environment
+ (cdr continuation)
+ (cdr in-optionals)
+ (cdr in-keywords)))
+ (let ((pattern-elt (car pattern)))
+ (cond ((car-eq pattern-elt :optional)
+ (if (null form)
+ (values t parent environment)
+ (multiple-value-bind (processed par env)
+ (record-callers* filename form (cdr pattern-elt)
+ parent environment
+ (cons (cdr pattern) continuation)
+ (cons (car in-optionals) in-optionals)
+ (cons (car in-keywords) in-keywords))
+ (if processed
+ (values processed par env)
+ (record-callers* filename form (cdr pattern)
+ parent environment continuation
+ in-optionals in-keywords)))))
+ ((car-eq pattern-elt :star)
+ (if (null form)
+ (values t parent environment)
+ (multiple-value-bind (processed par env)
+ (record-callers* filename form (cdr pattern-elt)
+ parent environment
+ (cons pattern continuation)
+ (cons (car in-optionals) in-optionals)
+ (cons (car in-keywords) in-keywords))
+ (if processed
+ (values processed par env)
+ (record-callers* filename form (cdr pattern)
+ parent environment continuation
+ in-optionals in-keywords)))))
+ ((car-eq pattern-elt :plus)
+ (record-callers* filename form (cdr pattern-elt)
+ parent environment
+ (cons (cons (cons :star (cdr pattern-elt))
+ (cdr pattern))
+ continuation)
+ (cons (car in-optionals) in-optionals)
+ (cons (car in-keywords) in-keywords)))
+ ((car-eq pattern-elt :rest)
+ (record-callers filename form pattern-elt parent environment))
+ ((eq pattern-elt '&optional)
+ (record-callers* filename form (cdr pattern)
+ parent environment continuation
+ (cons t in-optionals)
+ (cons (car in-keywords) in-keywords)))
+ ((eq pattern-elt '&rest)
+ (record-callers filename form (second pattern)
+ parent environment))
+ ((eq pattern-elt '&key)
+ (record-callers* filename form (cdr pattern)
+ parent environment continuation
+ (cons (car in-optionals) in-optionals)
+ (cons t in-keywords)))
+ ((null form)
+ (when (or (car in-keywords) (car in-optionals))
+ (values t parent environment)))
+ ((consp form)
+ (multiple-value-bind (processed parent environment)
+ (record-callers filename (if (car in-keywords)
+ (cadr form)
+ (car form))
+ pattern-elt
+ parent environment)
+ (cond (processed
+ (record-callers* filename (if (car in-keywords)
+ (cddr form)
+ (cdr form))
+ (cdr pattern)
+ parent environment
+ continuation
+ in-optionals in-keywords))
+ ((or (car in-keywords)
+ (car in-optionals))
+ (values t parent environment)))))))))
+
+
+;;; ********************************
+;;; Misc Utilities *****************
+;;; ********************************
+(defvar *types-to-ignore*
+ '(:lisp ; CLtL 1st Edition
+ :lisp2 ; CLtL 2nd Edition additional patterns
+ )
+ "Default set of caller types (as specified in the patterns) to ignore
+ in the database handling functions. :lisp is CLtL 1st edition,
+ :lisp2 is additional patterns from CLtL 2nd edition.")
+
+(defun display-database (&optional (database :callers)
+ (types-to-ignore *types-to-ignore*))
+ "Prints out the name of each symbol and all its callers. Specify database
+ :callers (the default) to get function call references, :fill to the get
+ files in which the symbol is called, :readers to get variable references,
+ and :setters to get variable binding and assignments. Ignores functions
+ of types listed in types-to-ignore."
+ (maphash #'(lambda (name callers)
+ (unless (or (member (pattern-caller-type name)
+ types-to-ignore)
+ ;; When we're doing fancy package crap,
+ ;; allow us to ignore symbols based on their
+ ;; packages.
+ (when *handle-package-forms*
+ (member (symbol-package name)
+ types-to-ignore
+ :key #'find-package)))
+ (format t "~&~S is referenced by~{ ~S~}."
+ name callers)))
+ (ecase database
+ (:file *file-callers-database*)
+ (:callers *callers-database*)
+ (:readers *readers-database*)
+ (:setters *setters-database*))))
+
+(defun write-callers-database-to-file (filename)
+ "Saves the contents of the current callers database to a file. This
+ file can be loaded to restore the previous contents of the
+ database. (For large systems it can take a long time to crunch
+ through the code, so this can save some time.)"
+ (with-open-file (stream filename :direction :output)
+ (format stream "~&(clear-tables)")
+ (maphash #'(lambda (x y)
+ (format stream "~&(setf (source-file '~S) '~S)"
+ x y))
+ *source-file*)
+ (maphash #'(lambda (x y)
+ (format stream "~&(setf (callers-list '~S :file) '~S)"
+ x y))
+ *file-callers-database*)
+ (maphash #'(lambda (x y)
+ (format stream "~&(setf (callers-list '~S :callers) '~S)"
+ x y))
+ *callers-database*)
+ (maphash #'(lambda (x y)
+ (format stream "~&(setf (callers-list '~S :callees) '~S)"
+ x y))
+ *callees-database*)
+ (maphash #'(lambda (x y)
+ (format stream "~&(setf (callers-list '~S :readers) '~S)"
+ x y))
+ *readers-database*)
+ (maphash #'(lambda (x y)
+ (format stream "~&(setf (callers-list '~S :setters) '~S)"
+ x y))
+ *setters-database*)))
+
+
+;;; ********************************
+;;; Print Caller Trees *************
+;;; ********************************
+;;; The following function is useful for reversing a caller table into
+;;; a callee table. Possibly later we'll extend xref to create two
+;;; such database hash tables. Needs to include vars as well.
+(defun invert-hash-table (table &optional (types-to-ignore *types-to-ignore*))
+ "Makes a copy of the hash table in which (name value*) pairs
+ are inverted to (value name*) pairs."
+ (let ((target (make-hash-table :test #'equal)))
+ (maphash #'(lambda (key values)
+ (dolist (value values)
+ (unless (member (pattern-caller-type key)
+ types-to-ignore)
+ (pushnew key (gethash value target)))))
+ table)
+ target))
+
+;;; Resolve file references for automatic creation of a defsystem file.
+(defun determine-file-dependencies (&optional (database *callers-database*))
+ "Makes a hash table of file dependencies for the references listed in
+ DATABASE. This function may be useful for automatically resolving
+ file references for automatic creation of a system definition (defsystem)."
+ (let ((file-ref-ht (make-hash-table :test #'equal)))
+ (maphash #'(lambda (key values)
+ (let ((key-file (source-file key)))
+ (when key
+ (dolist (value values)
+ (let ((value-file (source-file value)))
+ (when value-file
+ (dolist (s key-file)
+ (dolist (d value-file)
+ (pushnew d (gethash s file-ref-ht))))))))))
+ database)
+ file-ref-ht))
+
+(defun print-file-dependencies (&optional (database *callers-database*))
+ "Prints a list of file dependencies for the references listed in DATABASE.
+ This function may be useful for automatically computing file loading
+ constraints for a system definition tool."
+ (maphash #'(lambda (key value) (format t "~&~S --> ~S" key value))
+ (determine-file-dependencies database)))
+
+;;; The following functions demonstrate a possible way to interface
+;;; xref to a graphical browser such as psgraph to mimic the capabilities
+;;; of Masterscope's graphical browser.
+
+(defvar *last-caller-tree* nil)
+
+(defvar *default-graphing-mode* :call-graph
+ "Specifies whether we graph up or down. If :call-graph, the children
+ of a node are the functions it calls. If :caller-graph, the children
+ of a node are the functions that call it.")
+
+(defun gather-tree (parents &optional already-seen
+ (mode *default-graphing-mode*)
+ (types-to-ignore *types-to-ignore*) compact)
+ "Extends the tree, copying it into list structure, until it repeats
+ a reference (hits a cycle)."
+ (let ((*already-seen* nil)
+ (database (case mode
+ (:call-graph *callees-database*)
+ (:caller-graph *callers-database*))))
+ (declare (special *already-seen*))
+ (labels
+ ((amass-tree
+ (parents &optional already-seen)
+ (let (result this-item)
+ (dolist (parent parents)
+ (unless (member (pattern-caller-type parent)
+ types-to-ignore)
+ (pushnew parent *already-seen*)
+ (if (member parent already-seen)
+ (setq this-item nil) ; :ignore
+ (if compact
+ (multiple-value-setq (this-item already-seen)
+ (amass-tree (gethash parent database)
+ (cons parent already-seen)))
+ (setq this-item
+ (amass-tree (gethash parent database)
+ (cons parent already-seen)))))
+ (setq parent (format nil "~S" parent))
+ (when (consp parent) (setq parent (cons :xref-list parent)))
+ (unless (eq this-item :ignore)
+ (push (if this-item
+ (list parent this-item)
+ parent)
+ result))))
+ (values result ;(reverse result)
+ already-seen))))
+ (values (amass-tree parents already-seen)
+ *already-seen*))))
+
+(defun find-roots-and-cycles (&optional (mode *default-graphing-mode*)
+ (types-to-ignore *types-to-ignore*))
+ "Returns a list of uncalled callers (roots) and called callers (potential
+ cycles)."
+ (let ((uncalled-callers nil)
+ (called-callers nil)
+ (database (ecase mode
+ (:call-graph *callers-database*)
+ (:caller-graph *callees-database*)))
+ (other-database (ecase mode
+ (:call-graph *callees-database*)
+ (:caller-graph *callers-database*))))
+ (maphash #'(lambda (name value)
+ (declare (ignore value))
+ (unless (member (pattern-caller-type name)
+ types-to-ignore)
+ (if (gethash name database)
+ (push name called-callers)
+ (push name uncalled-callers))))
+ other-database)
+ (values uncalled-callers called-callers)))
+
+(defun make-caller-tree (&optional (mode *default-graphing-mode*)
+ (types-to-ignore *types-to-ignore*) compact)
+ "Outputs list structure of a tree which roughly represents the possibly
+ cyclical structure of the caller database.
+ If mode is :call-graph, the children of a node are the functions it calls.
+ If mode is :caller-graph, the children of a node are the functions that
+ call it.
+ If compact is T, tries to eliminate the already-seen nodes, so that
+ the graph for a node is printed at most once. Otherwise it will duplicate
+ the node's tree (except for cycles). This is usefull because the call tree
+ is actually a directed graph, so we can either duplicate references or
+ display only the first one."
+ ;; Would be nice to print out line numbers and whenever we skip a duplicated
+ ;; reference, print the line number of the full reference after the node.
+ (multiple-value-bind (uncalled-callers called-callers)
+ (find-roots-and-cycles mode types-to-ignore)
+ (multiple-value-bind (trees already-seen)
+ (gather-tree uncalled-callers nil mode types-to-ignore compact)
+ (setq *last-caller-tree* trees)
+ (let ((more-trees (gather-tree (set-difference called-callers
+ already-seen)
+ already-seen
+ mode types-to-ignore compact)))
+ (values trees more-trees)))))
+
+(defvar *indent-amount* 3
+ "Number of spaces to indent successive levels in PRINT-INDENTED-TREE.")
+
+(defun print-indented-tree (trees &optional (indent 0))
+ "Simple code to print out a list-structure tree (such as those created
+ by make-caller-tree) as indented text."
+ (when trees
+ (dolist (tree trees)
+ (cond ((and (listp tree) (eq (car tree) :xref-list))
+ (format t "~&~VT~A" indent (cdr tree)))
+ ((listp tree)
+ (format t "~&~VT~A" indent (car tree))
+ (print-indented-tree (cadr tree) (+ indent *indent-amount*)))
+ (t
+ (format t "~&~VT~A" indent tree))))))
+
+(defun print-caller-trees (&key (mode *default-graphing-mode*)
+ (types-to-ignore *types-to-ignore*)
+ compact
+ root-nodes)
+ "Prints the calling trees (which may actually be a full graph and not
+ necessarily a DAG) as indented text trees using PRINT-INDENTED-TREE.
+ MODE is :call-graph for trees where the children of a node are the
+ functions called by the node, or :caller-graph for trees where the
+ children of a node are the functions the node calls. TYPES-TO-IGNORE
+ is a list of funcall types (as specified in the patterns) to ignore
+ in printing out the database. For example, '(:lisp) would ignore all
+ calls to common lisp functions. COMPACT is a flag to tell the program
+ to try to compact the trees a bit by not printing trees if they have
+ already been seen. ROOT-NODES is a list of root nodes of trees to
+ display. If ROOT-NODES is nil, tries to find all root nodes in the
+ database."
+ (multiple-value-bind (rooted cycles)
+ (if root-nodes
+ (values (gather-tree root-nodes nil mode types-to-ignore compact))
+ (make-caller-tree mode types-to-ignore compact))
+ (when rooted
+ (format t "~&Rooted calling trees:")
+ (print-indented-tree rooted 2))
+ (when cycles
+ (when rooted
+ (format t "~2%"))
+ (format t "~&Cyclic calling trees:")
+ (print-indented-tree cycles 2))))
+
+
+;;; ********************************
+;;; Interface to PSGraph ***********
+;;; ********************************
+#|
+;;; Interface to Bates' PostScript Graphing Utility
+(load "/afs/cs/user/mkant/Lisp/PSGraph/psgraph")
+
+(defparameter *postscript-output-directory* "")
+(defun psgraph-xref (&key (mode *default-graphing-mode*)
+ (output-directory *postscript-output-directory*)
+ (types-to-ignore *types-to-ignore*)
+ (compact t)
+ (shrink t)
+ root-nodes
+ insert)
+ ;; If root-nodes is a non-nil list, uses that list as the starting
+ ;; position. Otherwise tries to find all roots in the database.
+ (multiple-value-bind (rooted cycles)
+ (if root-nodes
+ (values (gather-tree root-nodes nil mode types-to-ignore compact))
+ (make-caller-tree mode types-to-ignore compact))
+ (psgraph-output (append rooted cycles) output-directory shrink insert)))
+
+(defun psgraph-output (list-of-trees directory shrink &optional insert)
+ (let ((psgraph:*fontsize* 9)
+ (psgraph:*second-fontsize* 7)
+; (psgraph:*boxkind* "fill")
+ (psgraph:*boxgray* "0") ; .8
+ (psgraph:*edgewidth* "1")
+ (psgraph:*edgegray* "0"))
+ (labels ((stringify (thing)
+ (cond ((stringp thing) (string-downcase thing))
+ ((symbolp thing) (string-downcase (symbol-name thing)))
+ ((and (listp thing) (eq (car thing) :xref-list))
+ (stringify (cdr thing)))
+ ((listp thing) (stringify (car thing)))
+ (t (string thing)))))
+ (dolist (item list-of-trees)
+ (let* ((fname (stringify item))
+ (filename (concatenate 'string directory
+ (string-trim '(#\: #\|) fname)
+ ".ps")))
+ (format t "~&Creating PostScript file ~S." filename)
+ (with-open-file (*standard-output* filename
+ :direction :output
+ :if-does-not-exist :create
+ :if-exists :supersede)
+ ;; Note that the #'eq prints the DAG as a tree. If
+ ;; you replace it with #'equal, it will print it as
+ ;; a DAG, which I think is slightly ugly.
+ (psgraph:psgraph item
+ #'caller-tree-children #'caller-info shrink
+ insert #'eq)))))))
+
+(defun caller-tree-children (tree)
+ (when (and tree (listp tree) (not (eq (car tree) :xref-list)))
+ (cadr tree)))
+
+(defun caller-tree-node (tree)
+ (when tree
+ (cond ((and (listp tree) (eq (car tree) :xref-list))
+ (cdr tree))
+ ((listp tree)
+ (car tree))
+ (t
+ tree))))
+
+(defun caller-info (tree)
+ (let ((node (caller-tree-node tree)))
+ (list node)))
+|#
+#|
+;;; Code to print out graphical trees of CLOS class hierarchies.
+(defun print-class-hierarchy (&optional (start-class 'anything)
+ (file "classes.ps"))
+ (let ((start (find-class start-class)))
+ (when start
+ (with-open-file (*standard-output* file :direction :output)
+ (psgraph:psgraph start
+ #'clos::class-direct-subclasses
+ #'(lambda (x)
+ (list (format nil "~A" (clos::class-name x))))
+ t nil #'eq)))))
+
+|#
+
+
+;;; ****************************************************************
+;;; Cross Referencing Patterns for Common Lisp *********************
+;;; ****************************************************************
+(clear-patterns)
+
+;;; ********************************
+;;; Pattern Substitutions **********
+;;; ********************************
+(define-pattern-substitution integer (:test #'integerp))
+(define-pattern-substitution rational (:test #'rationalp))
+(define-pattern-substitution symbol (:test #'symbolp))
+(define-pattern-substitution string (:test #'stringp))
+(define-pattern-substitution number (:test #'numberp))
+(define-pattern-substitution lambda-list
+ ((:star var)
+ (:optional (:eq &optional)
+ (:star (:or var
+ (var (:optional form (:optional var))))))
+ (:optional (:eq &rest) var)
+ (:optional (:eq &key) (:star (:or var
+ ((:or var
+ (keyword var))
+ (:optional form (:optional var)))))
+ (:optional &allow-other-keys))
+ (:optional (:eq &aux)
+ (:star (:or var
+ (var (:optional form)))))))
+(define-pattern-substitution test form)
+(define-pattern-substitution body
+ ((:star (:or declaration documentation-string))
+ (:star form)))
+(define-pattern-substitution documentation-string string)
+(define-pattern-substitution initial-value form)
+(define-pattern-substitution tag symbol)
+(define-pattern-substitution declaration ((:eq declare)(:rest :ignore)))
+(define-pattern-substitution destination form)
+(define-pattern-substitution control-string string)
+(define-pattern-substitution format-arguments
+ ((:star form)))
+(define-pattern-substitution fn
+ (:or ((:eq quote) function)
+ ((:eq function) function)
+ function))
+
+;;; ********************************
+;;; Caller Patterns ****************
+;;; ********************************
+
+;;; Types Related
+(define-caller-pattern coerce (form :ignore) :lisp)
+(define-caller-pattern type-of (form) :lisp)
+(define-caller-pattern upgraded-array-element-type (:ignore) :lisp2)
+(define-caller-pattern upgraded-complex-part-type (:ignore) :lisp2)
+
+;;; Lambdas and Definitions
+(define-variable-pattern lambda-list-keywords :lisp)
+(define-variable-pattern lambda-parameters-limit :lisp)
+(define-caller-pattern lambda (lambda-list (:rest body)) :lisp)
+
+(define-caller-pattern defun
+ (name lambda-list
+ (:star (:or documentation-string declaration))
+ (:star form))
+ :lisp)
+
+;;; perhaps this should use VAR, instead of NAME
+(define-caller-pattern defvar
+ (var (:optional initial-value (:optional documentation-string)))
+ :lisp)
+(define-caller-pattern defparameter
+ (var initial-value (:optional documentation-string))
+ :lisp)
+(define-caller-pattern defconstant
+ (var initial-value (:optional documentation-string))
+ :lisp)
+
+(define-caller-pattern eval-when
+ (:ignore ; the situations
+ (:star form))
+ :lisp)
+
+;;; Logical Values
+(define-variable-pattern nil :lisp)
+(define-variable-pattern t :lisp)
+
+;;; Predicates
+(define-caller-pattern typep (form form) :lisp)
+(define-caller-pattern subtypep (form form) :lisp)
+
+(define-caller-pattern null (form) :lisp)
+(define-caller-pattern symbolp (form) :lisp)
+(define-caller-pattern atom (form) :lisp)
+(define-caller-pattern consp (form) :lisp)
+(define-caller-pattern listp (form) :lisp)
+(define-caller-pattern numberp (form) :lisp)
+(define-caller-pattern integerp (form) :lisp)
+(define-caller-pattern rationalp (form) :lisp)
+(define-caller-pattern floatp (form) :lisp)
+(define-caller-pattern realp (form) :lisp2)
+(define-caller-pattern complexp (form) :lisp)
+(define-caller-pattern characterp (form) :lisp)
+(define-caller-pattern stringp (form) :lisp)
+(define-caller-pattern bit-vector-p (form) :lisp)
+(define-caller-pattern vectorp (form) :lisp)
+(define-caller-pattern simple-vector-p (form) :lisp)
+(define-caller-pattern simple-string-p (form) :lisp)
+(define-caller-pattern simple-bit-vector-p (form) :lisp)
+(define-caller-pattern arrayp (form) :lisp)
+(define-caller-pattern packagep (form) :lisp)
+(define-caller-pattern functionp (form) :lisp)
+(define-caller-pattern compiled-function-p (form) :lisp)
+(define-caller-pattern commonp (form) :lisp)
+
+;;; Equality Predicates
+(define-caller-pattern eq (form form) :lisp)
+(define-caller-pattern eql (form form) :lisp)
+(define-caller-pattern equal (form form) :lisp)
+(define-caller-pattern equalp (form form) :lisp)
+
+;;; Logical Operators
+(define-caller-pattern not (form) :lisp)
+(define-caller-pattern or ((:star form)) :lisp)
+(define-caller-pattern and ((:star form)) :lisp)
+
+;;; Reference
+
+;;; Quote is a problem. In Defmacro & friends, we'd like to actually
+;;; look at the argument, 'cause it hides internal function calls
+;;; of the defmacro.
+(define-caller-pattern quote (:ignore) :lisp)
+
+(define-caller-pattern function ((:or fn form)) :lisp)
+(define-caller-pattern symbol-value (form) :lisp)
+(define-caller-pattern symbol-function (form) :lisp)
+(define-caller-pattern fdefinition (form) :lisp2)
+(define-caller-pattern boundp (form) :lisp)
+(define-caller-pattern fboundp (form) :lisp)
+(define-caller-pattern special-form-p (form) :lisp)
+
+;;; Assignment
+(define-caller-pattern setq ((:star var form)) :lisp)
+(define-caller-pattern psetq ((:star var form)) :lisp)
+(define-caller-pattern set (form form) :lisp)
+(define-caller-pattern makunbound (form) :lisp)
+(define-caller-pattern fmakunbound (form) :lisp)
+
+;;; Generalized Variables
+(define-caller-pattern setf ((:star form form)) :lisp)
+(define-caller-pattern psetf ((:star form form)) :lisp)
+(define-caller-pattern shiftf ((:plus form) form) :lisp)
+(define-caller-pattern rotatef ((:star form)) :lisp)
+(define-caller-pattern define-modify-macro
+ (name
+ lambda-list
+ fn
+ (:optional documentation-string))
+ :lisp)
+(define-caller-pattern defsetf
+ (:or (name name (:optional documentation-string))
+ (name lambda-list (var)
+ (:star (:or declaration documentation-string))
+ (:star form)))
+ :lisp)
+(define-caller-pattern define-setf-method
+ (name lambda-list
+ (:star (:or declaration documentation-string))
+ (:star form))
+ :lisp)
+(define-caller-pattern get-setf-method (form) :lisp)
+(define-caller-pattern get-setf-method-multiple-value (form) :lisp)
+
+
+;;; Function invocation
+(define-caller-pattern apply (fn form (:star form)) :lisp)
+(define-caller-pattern funcall (fn (:star form)) :lisp)
+
+
+;;; Simple sequencing
+(define-caller-pattern progn ((:star form)) :lisp)
+(define-caller-pattern prog1 (form (:star form)) :lisp)
+(define-caller-pattern prog2 (form form (:star form)) :lisp)
+
+;;; Variable bindings
+(define-caller-pattern let
+ (((:star (:or var (var &optional form))))
+ (:star declaration)
+ (:star form))
+ :lisp)
+(define-caller-pattern let*
+ (((:star (:or var (var &optional form))))
+ (:star declaration)
+ (:star form))
+ :lisp)
+(define-caller-pattern compiler-let
+ (((:star (:or var (var form))))
+ (:star form))
+ :lisp)
+(define-caller-pattern progv
+ (form form (:star form)) :lisp)
+(define-caller-pattern flet
+ (((:star (name lambda-list
+ (:star (:or declaration
+ documentation-string))
+ (:star form))))
+ (:star form))
+ :lisp)
+(define-caller-pattern labels
+ (((:star (name lambda-list
+ (:star (:or declaration
+ documentation-string))
+ (:star form))))
+ (:star form))
+ :lisp)
+(define-caller-pattern macrolet
+ (((:star (name lambda-list
+ (:star (:or declaration
+ documentation-string))
+ (:star form))))
+ (:star form))
+ :lisp)
+(define-caller-pattern symbol-macrolet
+ (((:star (var form))) (:star declaration) (:star form))
+ :lisp2)
+
+;;; Conditionals
+(define-caller-pattern if (test form (:optional form)) :lisp)
+(define-caller-pattern when (test (:star form)) :lisp)
+(define-caller-pattern unless (test (:star form)) :lisp)
+(define-caller-pattern cond ((:star (test (:star form)))) :lisp)
+(define-caller-pattern case
+ (form
+ (:star ((:or symbol
+ ((:star symbol)))
+ (:star form))))
+ :lisp)
+(define-caller-pattern typecase (form (:star (symbol (:star form))))
+ :lisp)
+
+;;; Blocks and Exits
+(define-caller-pattern block (name (:star form)) :lisp)
+(define-caller-pattern return-from (function (:optional form)) :lisp)
+(define-caller-pattern return ((:optional form)) :lisp)
+
+;;; Iteration
+(define-caller-pattern loop ((:star form)) :lisp)
+(define-caller-pattern do
+ (((:star (:or var
+ (var (:optional form (:optional form)))))) ; init step
+ (form (:star form)) ; end-test result
+ (:star declaration)
+ (:star (:or tag form))) ; statement
+ :lisp)
+(define-caller-pattern do*
+ (((:star (:or var
+ (var (:optional form (:optional form))))))
+ (form (:star form))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern dolist
+ ((var form (:optional form))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern dotimes
+ ((var form (:optional form))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+
+;;; Mapping
+(define-caller-pattern mapcar (fn form (:star form)) :lisp)
+(define-caller-pattern maplist (fn form (:star form)) :lisp)
+(define-caller-pattern mapc (fn form (:star form)) :lisp)
+(define-caller-pattern mapl (fn form (:star form)) :lisp)
+(define-caller-pattern mapcan (fn form (:star form)) :lisp)
+(define-caller-pattern mapcon (fn form (:star form)) :lisp)
+
+;;; The "Program Feature"
+(define-caller-pattern tagbody ((:star (:or tag form))) :lisp)
+(define-caller-pattern prog
+ (((:star (:or var (var (:optional form)))))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern prog*
+ (((:star (:or var (var (:optional form)))))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern go (tag) :lisp)
+
+;;; Multiple Values
+(define-caller-pattern values ((:star form)) :lisp)
+(define-variable-pattern multiple-values-limit :lisp)
+(define-caller-pattern values-list (form) :lisp)
+(define-caller-pattern multiple-value-list (form) :lisp)
+(define-caller-pattern multiple-value-call (fn (:star form)) :lisp)
+(define-caller-pattern multiple-value-prog1 (form (:star form)) :lisp)
+(define-caller-pattern multiple-value-bind
+ (((:star var)) form
+ (:star declaration)
+ (:star form))
+ :lisp)
+(define-caller-pattern multiple-value-setq (((:star var)) form) :lisp)
+(define-caller-pattern nth-value (form form) :lisp2)
+
+;;; Dynamic Non-Local Exits
+(define-caller-pattern catch (tag (:star form)) :lisp)
+(define-caller-pattern throw (tag form) :lisp)
+(define-caller-pattern unwind-protect (form (:star form)) :lisp)
+
+;;; Macros
+(define-caller-pattern macro-function (form) :lisp)
+(define-caller-pattern defmacro
+ (name
+ lambda-list
+ (:star (:or declaration documentation-string))
+ (:star form))
+ :lisp)
+(define-caller-pattern macroexpand (form (:optional :ignore)) :lisp)
+(define-caller-pattern macroexpand-1 (form (:optional :ignore)) :lisp)
+(define-variable-pattern *macroexpand-hook* :lisp)
+
+;;; Destructuring
+(define-caller-pattern destructuring-bind
+ (lambda-list form
+ (:star declaration)
+ (:star form))
+ :lisp2)
+
+;;; Compiler Macros
+(define-caller-pattern define-compiler-macro
+ (name lambda-list
+ (:star (:or declaration documentation-string))
+ (:star form))
+ :lisp2)
+(define-caller-pattern compiler-macro-function (form) :lisp2)
+(define-caller-pattern compiler-macroexpand (form (:optional :ignore)) :lisp2)
+(define-caller-pattern compiler-macroexpand-1 (form (:optional :ignore)) :lisp2)
+
+;;; Environments
+(define-caller-pattern variable-information (form &optional :ignore)
+ :lisp2)
+(define-caller-pattern function-information (fn &optional :ignore) :lisp2)
+(define-caller-pattern declaration-information (form &optional :ignore) :lisp2)
+(define-caller-pattern augment-environment (form &key (:star :ignore)) :lisp2)
+(define-caller-pattern define-declaration
+ (name
+ lambda-list
+ (:star form))
+ :lisp2)
+(define-caller-pattern parse-macro (name lambda-list form) :lisp2)
+(define-caller-pattern enclose (form &optional :ignore) :lisp2)
+
+
+;;; Declarations
+(define-caller-pattern declare ((:rest :ignore)) :lisp)
+(define-caller-pattern proclaim ((:rest :ignore)) :lisp)
+(define-caller-pattern locally ((:star declaration) (:star form)) :lisp)
+(define-caller-pattern declaim ((:rest :ignore)) :lisp2)
+(define-caller-pattern the (form form) :lisp)
+
+;;; Symbols
+(define-caller-pattern get (form form (:optional form)) :lisp)
+(define-caller-pattern remprop (form form) :lisp)
+(define-caller-pattern symbol-plist (form) :lisp)
+(define-caller-pattern getf (form form (:optional form)) :lisp)
+(define-caller-pattern remf (form form) :lisp)
+(define-caller-pattern get-properties (form form) :lisp)
+
+(define-caller-pattern symbol-name (form) :lisp)
+(define-caller-pattern make-symbol (form) :lisp)
+(define-caller-pattern copy-symbol (form (:optional :ignore)) :lisp)
+(define-caller-pattern gensym ((:optional :ignore)) :lisp)
+(define-variable-pattern *gensym-counter* :lisp2)
+(define-caller-pattern gentemp ((:optional :ignore :ignore)) :lisp)
+(define-caller-pattern symbol-package (form) :lisp)
+(define-caller-pattern keywordp (form) :lisp)
+
+;;; Packages
+(define-variable-pattern *package* :lisp)
+(define-caller-pattern make-package ((:rest :ignore)) :lisp)
+(define-caller-pattern in-package ((:rest :ignore)) :lisp)
+(define-caller-pattern find-package ((:rest :ignore)) :lisp)
+(define-caller-pattern package-name ((:rest :ignore)) :lisp)
+(define-caller-pattern package-nicknames ((:rest :ignore)) :lisp)
+(define-caller-pattern rename-package ((:rest :ignore)) :lisp)
+(define-caller-pattern package-use-list ((:rest :ignore)) :lisp)
+(define-caller-pattern package-used-by-list ((:rest :ignore)) :lisp)
+(define-caller-pattern package-shadowing-symbols ((:rest :ignore)) :lisp)
+(define-caller-pattern list-all-packages () :lisp)
+(define-caller-pattern delete-package ((:rest :ignore)) :lisp2)
+(define-caller-pattern intern (form &optional :ignore) :lisp)
+(define-caller-pattern find-symbol (form &optional :ignore) :lisp)
+(define-caller-pattern unintern (form &optional :ignore) :lisp)
+
+(define-caller-pattern export ((:or symbol ((:star symbol)))
+ &optional :ignore) :lisp)
+(define-caller-pattern unexport ((:or symbol ((:star symbol)))
+ &optional :ignore) :lisp)
+(define-caller-pattern import ((:or symbol ((:star symbol)))
+ &optional :ignore) :lisp)
+(define-caller-pattern shadowing-import ((:or symbol ((:star symbol)))
+ &optional :ignore) :lisp)
+(define-caller-pattern shadow ((:or symbol ((:star symbol)))
+ &optional :ignore) :lisp)
+
+(define-caller-pattern use-package ((:rest :ignore)) :lisp)
+(define-caller-pattern unuse-package ((:rest :ignore)) :lisp)
+(define-caller-pattern defpackage (name (:rest :ignore)) :lisp2)
+(define-caller-pattern find-all-symbols (form) :lisp)
+(define-caller-pattern do-symbols
+ ((var (:optional form (:optional form)))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern do-external-symbols
+ ((var (:optional form (:optional form)))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern do-all-symbols
+ ((var (:optional form))
+ (:star declaration)
+ (:star (:or tag form)))
+ :lisp)
+(define-caller-pattern with-package-iterator
+ ((name form (:plus :ignore))
+ (:star form))
+ :lisp2)
+
+;;; Modules
+(define-variable-pattern *modules* :lisp)
+(define-caller-pattern provide (form) :lisp)
+(define-caller-pattern require (form &optional :ignore) :lisp)
+
+
+;;; Numbers
+(define-caller-pattern zerop (form) :lisp)
+(define-caller-pattern plusp (form) :lisp)
+(define-caller-pattern minusp (form) :lisp)
+(define-caller-pattern oddp (form) :lisp)
+(define-caller-pattern evenp (form) :lisp)
+
+(define-caller-pattern = (form (:star form)) :lisp)
+(define-caller-pattern /= (form (:star form)) :lisp)
+(define-caller-pattern > (form (:star form)) :lisp)
+(define-caller-pattern < (form (:star form)) :lisp)
+(define-caller-pattern <= (form (:star form)) :lisp)
+(define-caller-pattern >= (form (:star form)) :lisp)
+
+(define-caller-pattern max (form (:star form)) :lisp)
+(define-caller-pattern min (form (:star form)) :lisp)
+
+(define-caller-pattern - (form (:star form)) :lisp)
+(define-caller-pattern + (form (:star form)) :lisp)
+(define-caller-pattern * (form (:star form)) :lisp)
+(define-caller-pattern / (form (:star form)) :lisp)
+(define-caller-pattern 1+ (form) :lisp)
+(define-caller-pattern 1- (form) :lisp)
+
+(define-caller-pattern incf (form form) :lisp)
+(define-caller-pattern decf (form form) :lisp)
+
+(define-caller-pattern conjugate (form) :lisp)
+
+(define-caller-pattern gcd ((:star form)) :lisp)
+(define-caller-pattern lcm ((:star form)) :lisp)
+
+(define-caller-pattern exp (form) :lisp)
+(define-caller-pattern expt (form form) :lisp)
+(define-caller-pattern log (form (:optional form)) :lisp)
+(define-caller-pattern sqrt (form) :lisp)
+(define-caller-pattern isqrt (form) :lisp)
+
+(define-caller-pattern abs (form) :lisp)
+(define-caller-pattern phase (form) :lisp)
+(define-caller-pattern signum (form) :lisp)
+(define-caller-pattern sin (form) :lisp)
+(define-caller-pattern cos (form) :lisp)
+(define-caller-pattern tan (form) :lisp)
+(define-caller-pattern cis (form) :lisp)
+(define-caller-pattern asin (form) :lisp)
+(define-caller-pattern acos (form) :lisp)
+(define-caller-pattern atan (form &optional form) :lisp)
+(define-variable-pattern pi :lisp)
+
+(define-caller-pattern sinh (form) :lisp)
+(define-caller-pattern cosh (form) :lisp)
+(define-caller-pattern tanh (form) :lisp)
+(define-caller-pattern asinh (form) :lisp)
+(define-caller-pattern acosh (form) :lisp)
+(define-caller-pattern atanh (form) :lisp)
+
+;;; Type Conversions and Extractions
+(define-caller-pattern float (form (:optional form)) :lisp)
+(define-caller-pattern rational (form) :lisp)
+(define-caller-pattern rationalize (form) :lisp)
+(define-caller-pattern numerator (form) :lisp)
+(define-caller-pattern denominator (form) :lisp)
+
+(define-caller-pattern floor (form (:optional form)) :lisp)
+(define-caller-pattern ceiling (form (:optional form)) :lisp)
+(define-caller-pattern truncate (form (:optional form)) :lisp)
+(define-caller-pattern round (form (:optional form)) :lisp)
+
+(define-caller-pattern mod (form form) :lisp)
+(define-caller-pattern rem (form form) :lisp)
+
+(define-caller-pattern ffloor (form (:optional form)) :lisp)
+(define-caller-pattern fceiling (form (:optional form)) :lisp)
+(define-caller-pattern ftruncate (form (:optional form)) :lisp)
+(define-caller-pattern fround (form (:optional form)) :lisp)
+
+(define-caller-pattern decode-float (form) :lisp)
+(define-caller-pattern scale-float (form form) :lisp)
+(define-caller-pattern float-radix (form) :lisp)
+(define-caller-pattern float-sign (form (:optional form)) :lisp)
+(define-caller-pattern float-digits (form) :lisp)
+(define-caller-pattern float-precision (form) :lisp)
+(define-caller-pattern integer-decode-float (form) :lisp)
+
+(define-caller-pattern complex (form (:optional form)) :lisp)
+(define-caller-pattern realpart (form) :lisp)
+(define-caller-pattern imagpart (form) :lisp)
+
+(define-caller-pattern logior ((:star form)) :lisp)
+(define-caller-pattern logxor ((:star form)) :lisp)
+(define-caller-pattern logand ((:star form)) :lisp)
+(define-caller-pattern logeqv ((:star form)) :lisp)
+
+(define-caller-pattern lognand (form form) :lisp)
+(define-caller-pattern lognor (form form) :lisp)
+(define-caller-pattern logandc1 (form form) :lisp)
+(define-caller-pattern logandc2 (form form) :lisp)
+(define-caller-pattern logorc1 (form form) :lisp)
+(define-caller-pattern logorc2 (form form) :lisp)
+
+(define-caller-pattern boole (form form form) :lisp)
+(define-variable-pattern boole-clr :lisp)
+(define-variable-pattern boole-set :lisp)
+(define-variable-pattern boole-1 :lisp)
+(define-variable-pattern boole-2 :lisp)
+(define-variable-pattern boole-c1 :lisp)
+(define-variable-pattern boole-c2 :lisp)
+(define-variable-pattern boole-and :lisp)
+(define-variable-pattern boole-ior :lisp)
+(define-variable-pattern boole-xor :lisp)
+(define-variable-pattern boole-eqv :lisp)
+(define-variable-pattern boole-nand :lisp)
+(define-variable-pattern boole-nor :lisp)
+(define-variable-pattern boole-andc1 :lisp)
+(define-variable-pattern boole-andc2 :lisp)
+(define-variable-pattern boole-orc1 :lisp)
+(define-variable-pattern boole-orc2 :lisp)
+
+(define-caller-pattern lognot (form) :lisp)
+(define-caller-pattern logtest (form form) :lisp)
+(define-caller-pattern logbitp (form form) :lisp)
+(define-caller-pattern ash (form form) :lisp)
+(define-caller-pattern logcount (form) :lisp)
+(define-caller-pattern integer-length (form) :lisp)
+
+(define-caller-pattern byte (form form) :lisp)
+(define-caller-pattern byte-size (form) :lisp)
+(define-caller-pattern byte-position (form) :lisp)
+(define-caller-pattern ldb (form form) :lisp)
+(define-caller-pattern ldb-test (form form) :lisp)
+(define-caller-pattern mask-field (form form) :lisp)
+(define-caller-pattern dpb (form form form) :lisp)
+(define-caller-pattern deposit-field (form form form) :lisp)
+
+;;; Random Numbers
+(define-caller-pattern random (form (:optional form)) :lisp)
+(define-variable-pattern *random-state* :lisp)
+(define-caller-pattern make-random-state ((:optional form)) :lisp)
+(define-caller-pattern random-state-p (form) :lisp)
+
+;;; Implementation Parameters
+(define-variable-pattern most-positive-fixnum :lisp)
+(define-variable-pattern most-negative-fixnum :lisp)
+(define-variable-pattern most-positive-short-float :lisp)
+(define-variable-pattern least-positive-short-float :lisp)
+(define-variable-pattern least-negative-short-float :lisp)
+(define-variable-pattern most-negative-short-float :lisp)
+(define-variable-pattern most-positive-single-float :lisp)
+(define-variable-pattern least-positive-single-float :lisp)
+(define-variable-pattern least-negative-single-float :lisp)
+(define-variable-pattern most-negative-single-float :lisp)
+(define-variable-pattern most-positive-double-float :lisp)
+(define-variable-pattern least-positive-double-float :lisp)
+(define-variable-pattern least-negative-double-float :lisp)
+(define-variable-pattern most-negative-double-float :lisp)
+(define-variable-pattern most-positive-long-float :lisp)
+(define-variable-pattern least-positive-long-float :lisp)
+(define-variable-pattern least-negative-long-float :lisp)
+(define-variable-pattern most-negative-long-float :lisp)
+(define-variable-pattern least-positive-normalized-short-float :lisp2)
+(define-variable-pattern least-negative-normalized-short-float :lisp2)
+(define-variable-pattern least-positive-normalized-single-float :lisp2)
+(define-variable-pattern least-negative-normalized-single-float :lisp2)
+(define-variable-pattern least-positive-normalized-double-float :lisp2)
+(define-variable-pattern least-negative-normalized-double-float :lisp2)
+(define-variable-pattern least-positive-normalized-long-float :lisp2)
+(define-variable-pattern least-negative-normalized-long-float :lisp2)
+(define-variable-pattern short-float-epsilon :lisp)
+(define-variable-pattern single-float-epsilon :lisp)
+(define-variable-pattern double-float-epsilon :lisp)
+(define-variable-pattern long-float-epsilon :lisp)
+(define-variable-pattern short-float-negative-epsilon :lisp)
+(define-variable-pattern single-float-negative-epsilon :lisp)
+(define-variable-pattern double-float-negative-epsilon :lisp)
+(define-variable-pattern long-float-negative-epsilon :lisp)
+
+;;; Characters
+(define-variable-pattern char-code-limit :lisp)
+(define-variable-pattern char-font-limit :lisp)
+(define-variable-pattern char-bits-limit :lisp)
+(define-caller-pattern standard-char-p (form) :lisp)
+(define-caller-pattern graphic-char-p (form) :lisp)
+(define-caller-pattern string-char-p (form) :lisp)
+(define-caller-pattern alpha-char-p (form) :lisp)
+(define-caller-pattern upper-case-p (form) :lisp)
+(define-caller-pattern lower-case-p (form) :lisp)
+(define-caller-pattern both-case-p (form) :lisp)
+(define-caller-pattern digit-char-p (form (:optional form)) :lisp)
+(define-caller-pattern alphanumericp (form) :lisp)
+
+(define-caller-pattern char= ((:star form)) :lisp)
+(define-caller-pattern char/= ((:star form)) :lisp)
+(define-caller-pattern char< ((:star form)) :lisp)
+(define-caller-pattern char> ((:star form)) :lisp)
+(define-caller-pattern char<= ((:star form)) :lisp)
+(define-caller-pattern char>= ((:star form)) :lisp)
+
+(define-caller-pattern char-equal ((:star form)) :lisp)
+(define-caller-pattern char-not-equal ((:star form)) :lisp)
+(define-caller-pattern char-lessp ((:star form)) :lisp)
+(define-caller-pattern char-greaterp ((:star form)) :lisp)
+(define-caller-pattern char-not-greaterp ((:star form)) :lisp)
+(define-caller-pattern char-not-lessp ((:star form)) :lisp)
+
+(define-caller-pattern char-code (form) :lisp)
+(define-caller-pattern char-bits (form) :lisp)
+(define-caller-pattern char-font (form) :lisp)
+(define-caller-pattern code-char (form (:optional form form)) :lisp)
+(define-caller-pattern make-char (form (:optional form form)) :lisp)
+(define-caller-pattern characterp (form) :lisp)
+(define-caller-pattern char-upcase (form) :lisp)
+(define-caller-pattern char-downcase (form) :lisp)
+(define-caller-pattern digit-char (form (:optional form form)) :lisp)
+(define-caller-pattern char-int (form) :lisp)
+(define-caller-pattern int-char (form) :lisp)
+(define-caller-pattern char-name (form) :lisp)
+(define-caller-pattern name-char (form) :lisp)
+(define-variable-pattern char-control-bit :lisp)
+(define-variable-pattern char-meta-bit :lisp)
+(define-variable-pattern char-super-bit :lisp)
+(define-variable-pattern char-hyper-bit :lisp)
+(define-caller-pattern char-bit (form form) :lisp)
+(define-caller-pattern set-char-bit (form form form) :lisp)
+
+;;; Sequences
+(define-caller-pattern complement (fn) :lisp2)
+(define-caller-pattern elt (form form) :lisp)
+(define-caller-pattern subseq (form form &optional form) :lisp)
+(define-caller-pattern copy-seq (form) :lisp)
+(define-caller-pattern length (form) :lisp)
+(define-caller-pattern reverse (form) :lisp)
+(define-caller-pattern nreverse (form) :lisp)
+(define-caller-pattern make-sequence (form form &key form) :lisp)
+
+(define-caller-pattern concatenate (form (:star form)) :lisp)
+(define-caller-pattern map (form fn form (:star form)) :lisp)
+(define-caller-pattern map-into (form fn (:star form)) :lisp2)
+
+(define-caller-pattern some (fn form (:star form)) :lisp)
+(define-caller-pattern every (fn form (:star form)) :lisp)
+(define-caller-pattern notany (fn form (:star form)) :lisp)
+(define-caller-pattern notevery (fn form (:star form)) :lisp)
+
+(define-caller-pattern reduce (fn form &key (:star form)) :lisp)
+(define-caller-pattern fill (form form &key (:star form)) :lisp)
+(define-caller-pattern replace (form form &key (:star form)) :lisp)
+(define-caller-pattern remove (form form &key (:star form)) :lisp)
+(define-caller-pattern remove-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern remove-if-not (fn form &key (:star form)) :lisp)
+(define-caller-pattern delete (form form &key (:star form)) :lisp)
+(define-caller-pattern delete-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern delete-if-not (fn form &key (:star form)) :lisp)
+(define-caller-pattern remove-duplicates (form &key (:star form)) :lisp)
+(define-caller-pattern delete-duplicates (form &key (:star form)) :lisp)
+(define-caller-pattern substitute (form form form &key (:star form)) :lisp)
+(define-caller-pattern substitute-if (form fn form &key (:star form)) :lisp)
+(define-caller-pattern substitute-if-not (form fn form &key (:star form)) :lisp)
+(define-caller-pattern nsubstitute (form form form &key (:star form)) :lisp)
+(define-caller-pattern nsubstitute-if (form fn form &key (:star form)) :lisp)
+(define-caller-pattern nsubstitute-if-not (form fn form &key (:star form)) :lisp)
+(define-caller-pattern find (form form &key (:star form)) :lisp)
+(define-caller-pattern find-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern find-if-not (fn form &key (:star form)) :lisp)
+(define-caller-pattern position (form form &key (:star form)) :lisp)
+(define-caller-pattern position-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern position-if-not (fn form &key (:star form)) :lisp)
+(define-caller-pattern count (form form &key (:star form)) :lisp)
+(define-caller-pattern count-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern count-if-not (fn form &key (:star form)) :lisp)
+(define-caller-pattern mismatch (form form &key (:star form)) :lisp)
+(define-caller-pattern search (form form &key (:star form)) :lisp)
+(define-caller-pattern sort (form fn &key (:star form)) :lisp)
+(define-caller-pattern stable-sort (form fn &key (:star form)) :lisp)
+(define-caller-pattern merge (form form form fn &key (:star form)) :lisp)
+
+;;; Lists
+(define-caller-pattern car (form) :lisp)
+(define-caller-pattern cdr (form) :lisp)
+(define-caller-pattern caar (form) :lisp)
+(define-caller-pattern cadr (form) :lisp)
+(define-caller-pattern cdar (form) :lisp)
+(define-caller-pattern cddr (form) :lisp)
+(define-caller-pattern caaar (form) :lisp)
+(define-caller-pattern caadr (form) :lisp)
+(define-caller-pattern cadar (form) :lisp)
+(define-caller-pattern caddr (form) :lisp)
+(define-caller-pattern cdaar (form) :lisp)
+(define-caller-pattern cdadr (form) :lisp)
+(define-caller-pattern cddar (form) :lisp)
+(define-caller-pattern cdddr (form) :lisp)
+(define-caller-pattern caaaar (form) :lisp)
+(define-caller-pattern caaadr (form) :lisp)
+(define-caller-pattern caadar (form) :lisp)
+(define-caller-pattern caaddr (form) :lisp)
+(define-caller-pattern cadaar (form) :lisp)
+(define-caller-pattern cadadr (form) :lisp)
+(define-caller-pattern caddar (form) :lisp)
+(define-caller-pattern cadddr (form) :lisp)
+(define-caller-pattern cdaaar (form) :lisp)
+(define-caller-pattern cdaadr (form) :lisp)
+(define-caller-pattern cdadar (form) :lisp)
+(define-caller-pattern cdaddr (form) :lisp)
+(define-caller-pattern cddaar (form) :lisp)
+(define-caller-pattern cddadr (form) :lisp)
+(define-caller-pattern cdddar (form) :lisp)
+(define-caller-pattern cddddr (form) :lisp)
+
+(define-caller-pattern cons (form form) :lisp)
+(define-caller-pattern tree-equal (form form &key (:star fn)) :lisp)
+(define-caller-pattern endp (form) :lisp)
+(define-caller-pattern list-length (form) :lisp)
+(define-caller-pattern nth (form form) :lisp)
+
+(define-caller-pattern first (form) :lisp)
+(define-caller-pattern second (form) :lisp)
+(define-caller-pattern third (form) :lisp)
+(define-caller-pattern fourth (form) :lisp)
+(define-caller-pattern fifth (form) :lisp)
+(define-caller-pattern sixth (form) :lisp)
+(define-caller-pattern seventh (form) :lisp)
+(define-caller-pattern eighth (form) :lisp)
+(define-caller-pattern ninth (form) :lisp)
+(define-caller-pattern tenth (form) :lisp)
+
+(define-caller-pattern rest (form) :lisp)
+(define-caller-pattern nthcdr (form form) :lisp)
+(define-caller-pattern last (form (:optional form)) :lisp)
+(define-caller-pattern list ((:star form)) :lisp)
+(define-caller-pattern list* ((:star form)) :lisp)
+(define-caller-pattern make-list (form &key (:star form)) :lisp)
+(define-caller-pattern append ((:star form)) :lisp)
+(define-caller-pattern copy-list (form) :lisp)
+(define-caller-pattern copy-alist (form) :lisp)
+(define-caller-pattern copy-tree (form) :lisp)
+(define-caller-pattern revappend (form form) :lisp)
+(define-caller-pattern nconc ((:star form)) :lisp)
+(define-caller-pattern nreconc (form form) :lisp)
+(define-caller-pattern push (form form) :lisp)
+(define-caller-pattern pushnew (form form &key (:star form)) :lisp)
+(define-caller-pattern pop (form) :lisp)
+(define-caller-pattern butlast (form (:optional form)) :lisp)
+(define-caller-pattern nbutlast (form (:optional form)) :lisp)
+(define-caller-pattern ldiff (form form) :lisp)
+(define-caller-pattern rplaca (form form) :lisp)
+(define-caller-pattern rplacd (form form) :lisp)
+
+(define-caller-pattern subst (form form form &key (:star form)) :lisp)
+(define-caller-pattern subst-if (form fn form &key (:star form)) :lisp)
+(define-caller-pattern subst-if-not (form fn form &key (:star form)) :lisp)
+(define-caller-pattern nsubst (form form form &key (:star form)) :lisp)
+(define-caller-pattern nsubst-if (form fn form &key (:star form)) :lisp)
+(define-caller-pattern nsubst-if-not (form fn form &key (:star form)) :lisp)
+(define-caller-pattern sublis (form form &key (:star form)) :lisp)
+(define-caller-pattern nsublis (form form &key (:star form)) :lisp)
+(define-caller-pattern member (form form &key (:star form)) :lisp)
+(define-caller-pattern member-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern member-if-not (fn form &key (:star form)) :lisp)
+
+(define-caller-pattern tailp (form form) :lisp)
+(define-caller-pattern adjoin (form form &key (:star form)) :lisp)
+(define-caller-pattern union (form form &key (:star form)) :lisp)
+(define-caller-pattern nunion (form form &key (:star form)) :lisp)
+(define-caller-pattern intersection (form form &key (:star form)) :lisp)
+(define-caller-pattern nintersection (form form &key (:star form)) :lisp)
+(define-caller-pattern set-difference (form form &key (:star form)) :lisp)
+(define-caller-pattern nset-difference (form form &key (:star form)) :lisp)
+(define-caller-pattern set-exclusive-or (form form &key (:star form)) :lisp)
+(define-caller-pattern nset-exclusive-or (form form &key (:star form)) :lisp)
+(define-caller-pattern subsetp (form form &key (:star form)) :lisp)
+
+(define-caller-pattern acons (form form form) :lisp)
+(define-caller-pattern pairlis (form form (:optional form)) :lisp)
+(define-caller-pattern assoc (form form &key (:star form)) :lisp)
+(define-caller-pattern assoc-if (fn form) :lisp)
+(define-caller-pattern assoc-if-not (fn form) :lisp)
+(define-caller-pattern rassoc (form form &key (:star form)) :lisp)
+(define-caller-pattern rassoc-if (fn form &key (:star form)) :lisp)
+(define-caller-pattern rassoc-if-not (fn form &key (:star form)) :lisp)
+
+;;; Hash Tables
+(define-caller-pattern make-hash-table (&key (:star form)) :lisp)
+(define-caller-pattern hash-table-p (form) :lisp)
+(define-caller-pattern gethash (form form (:optional form)) :lisp)
+(define-caller-pattern remhash (form form) :lisp)
+(define-caller-pattern maphash (fn form) :lisp)
+(define-caller-pattern clrhash (form) :lisp)
+(define-caller-pattern hash-table-count (form) :lisp)
+(define-caller-pattern with-hash-table-iterator
+ ((name form) (:star form)) :lisp2)
+(define-caller-pattern hash-table-rehash-size (form) :lisp2)
+(define-caller-pattern hash-table-rehash-threshold (form) :lisp2)
+(define-caller-pattern hash-table-size (form) :lisp2)
+(define-caller-pattern hash-table-test (form) :lisp2)
+(define-caller-pattern sxhash (form) :lisp)
+
+;;; Arrays
+(define-caller-pattern make-array (form &key (:star form)) :lisp)
+(define-variable-pattern array-rank-limit :lisp)
+(define-variable-pattern array-dimension-limit :lisp)
+(define-variable-pattern array-total-size-limit :lisp)
+(define-caller-pattern vector ((:star form)) :lisp)
+(define-caller-pattern aref (form (:star form)) :lisp)
+(define-caller-pattern svref (form form) :lisp)
+(define-caller-pattern array-element-type (form) :lisp)
+(define-caller-pattern array-rank (form) :lisp)
+(define-caller-pattern array-dimension (form form) :lisp)
+(define-caller-pattern array-dimensions (form) :lisp)
+(define-caller-pattern array-total-size (form) :lisp)
+(define-caller-pattern array-in-bounds-p (form (:star form)) :lisp)
+(define-caller-pattern array-row-major-index (form (:star form)) :lisp)
+(define-caller-pattern row-major-aref (form form) :lisp2)
+(define-caller-pattern adjustable-array-p (form) :lisp)
+
+(define-caller-pattern bit (form (:star form)) :lisp)
+(define-caller-pattern sbit (form (:star form)) :lisp)
+
+(define-caller-pattern bit-and (form form (:optional form)) :lisp)
+(define-caller-pattern bit-ior (form form (:optional form)) :lisp)
+(define-caller-pattern bit-xor (form form (:optional form)) :lisp)
+(define-caller-pattern bit-eqv (form form (:optional form)) :lisp)
+(define-caller-pattern bit-nand (form form (:optional form)) :lisp)
+(define-caller-pattern bit-nor (form form (:optional form)) :lisp)
+(define-caller-pattern bit-andc1 (form form (:optional form)) :lisp)
+(define-caller-pattern bit-andc2 (form form (:optional form)) :lisp)
+(define-caller-pattern bit-orc1 (form form (:optional form)) :lisp)
+(define-caller-pattern bit-orc2 (form form (:optional form)) :lisp)
+(define-caller-pattern bit-not (form (:optional form)) :lisp)
+
+(define-caller-pattern array-has-fill-pointer-p (form) :lisp)
+(define-caller-pattern fill-pointer (form) :lisp)
+(define-caller-pattern vector-push (form form) :lisp)
+(define-caller-pattern vector-push-extend (form form (:optional form)) :lisp)
+(define-caller-pattern vector-pop (form) :lisp)
+(define-caller-pattern adjust-array (form form &key (:star form)) :lisp)
+
+;;; Strings
+(define-caller-pattern char (form form) :lisp)
+(define-caller-pattern schar (form form) :lisp)
+(define-caller-pattern string= (form form &key (:star form)) :lisp)
+(define-caller-pattern string-equal (form form &key (:star form)) :lisp)
+(define-caller-pattern string< (form form &key (:star form)) :lisp)
+(define-caller-pattern string> (form form &key (:star form)) :lisp)
+(define-caller-pattern string<= (form form &key (:star form)) :lisp)
+(define-caller-pattern string>= (form form &key (:star form)) :lisp)
+(define-caller-pattern string/= (form form &key (:star form)) :lisp)
+(define-caller-pattern string-lessp (form form &key (:star form)) :lisp)
+(define-caller-pattern string-greaterp (form form &key (:star form)) :lisp)
+(define-caller-pattern string-not-greaterp (form form &key (:star form)) :lisp)
+(define-caller-pattern string-not-lessp (form form &key (:star form)) :lisp)
+(define-caller-pattern string-not-equal (form form &key (:star form)) :lisp)
+
+(define-caller-pattern make-string (form &key (:star form)) :lisp)
+(define-caller-pattern string-trim (form form) :lisp)
+(define-caller-pattern string-left-trim (form form) :lisp)
+(define-caller-pattern string-right-trim (form form) :lisp)
+(define-caller-pattern string-upcase (form &key (:star form)) :lisp)
+(define-caller-pattern string-downcase (form &key (:star form)) :lisp)
+(define-caller-pattern string-capitalize (form &key (:star form)) :lisp)
+(define-caller-pattern nstring-upcase (form &key (:star form)) :lisp)
+(define-caller-pattern nstring-downcase (form &key (:star form)) :lisp)
+(define-caller-pattern nstring-capitalize (form &key (:star form)) :lisp)
+(define-caller-pattern string (form) :lisp)
+
+;;; Structures
+(define-caller-pattern defstruct
+ ((:or name (name (:rest :ignore)))
+ (:optional documentation-string)
+ (:plus :ignore))
+ :lisp)
+
+;;; The Evaluator
+(define-caller-pattern eval (form) :lisp)
+(define-variable-pattern *evalhook* :lisp)
+(define-variable-pattern *applyhook* :lisp)
+(define-caller-pattern evalhook (form fn fn &optional :ignore) :lisp)
+(define-caller-pattern applyhook (fn form fn fn &optional :ignore) :lisp)
+(define-caller-pattern constantp (form) :lisp)
+
+;;; Streams
+(define-variable-pattern *standard-input* :lisp)
+(define-variable-pattern *standard-output* :lisp)
+(define-variable-pattern *error-output* :lisp)
+(define-variable-pattern *query-io* :lisp)
+(define-variable-pattern *debug-io* :lisp)
+(define-variable-pattern *terminal-io* :lisp)
+(define-variable-pattern *trace-output* :lisp)
+(define-caller-pattern make-synonym-stream (symbol) :lisp)
+(define-caller-pattern make-broadcast-stream ((:star form)) :lisp)
+(define-caller-pattern make-concatenated-stream ((:star form)) :lisp)
+(define-caller-pattern make-two-way-stream (form form) :lisp)
+(define-caller-pattern make-echo-stream (form form) :lisp)
+(define-caller-pattern make-string-input-stream (form &optional form form) :lisp)
+(define-caller-pattern make-string-output-stream (&key (:star form)) :lisp)
+(define-caller-pattern get-output-stream-string (form) :lisp)
+
+(define-caller-pattern with-open-stream
+ ((var form)
+ (:star declaration)
+ (:star form))
+ :lisp)
+
+(define-caller-pattern with-input-from-string
+ ((var form &key (:star form))
+ (:star declaration)
+ (:star form))
+ :lisp)
+
+(define-caller-pattern with-output-to-string
+ ((var (:optional form))
+ (:star declaration)
+ (:star form))
+ :lisp)
+(define-caller-pattern streamp (form) :lisp)
+(define-caller-pattern open-stream-p (form) :lisp2)
+(define-caller-pattern input-stream-p (form) :lisp)
+(define-caller-pattern output-stream-p (form) :lisp)
+(define-caller-pattern stream-element-type (form) :lisp)
+(define-caller-pattern close (form (:rest :ignore)) :lisp)
+(define-caller-pattern broadcast-stream-streams (form) :lisp2)
+(define-caller-pattern concatenated-stream-streams (form) :lisp2)
+(define-caller-pattern echo-stream-input-stream (form) :lisp2)
+(define-caller-pattern echo-stream-output-stream (form) :lisp2)
+(define-caller-pattern synonym-stream-symbol (form) :lisp2)
+(define-caller-pattern two-way-stream-input-stream (form) :lisp2)
+(define-caller-pattern two-way-stream-output-stream (form) :lisp2)
+(define-caller-pattern interactive-stream-p (form) :lisp2)
+(define-caller-pattern stream-external-format (form) :lisp2)
+
+;;; Reader
+(define-variable-pattern *read-base* :lisp)
+(define-variable-pattern *read-suppress* :lisp)
+(define-variable-pattern *read-eval* :lisp2)
+(define-variable-pattern *readtable* :lisp)
+(define-caller-pattern copy-readtable (&optional form form) :lisp)
+(define-caller-pattern readtablep (form) :lisp)
+(define-caller-pattern set-syntax-from-char (form form &optional form form) :lisp)
+(define-caller-pattern set-macro-character (form fn &optional form) :lisp)
+(define-caller-pattern get-macro-character (form (:optional form)) :lisp)
+(define-caller-pattern make-dispatch-macro-character (form &optional form form)
+ :lisp)
+(define-caller-pattern set-dispatch-macro-character
+ (form form fn (:optional form)) :lisp)
+(define-caller-pattern get-dispatch-macro-character
+ (form form (:optional form)) :lisp)
+(define-caller-pattern readtable-case (form) :lisp2)
+(define-variable-pattern *print-readably* :lisp2)
+(define-variable-pattern *print-escape* :lisp)
+(define-variable-pattern *print-pretty* :lisp)
+(define-variable-pattern *print-circle* :lisp)
+(define-variable-pattern *print-base* :lisp)
+(define-variable-pattern *print-radix* :lisp)
+(define-variable-pattern *print-case* :lisp)
+(define-variable-pattern *print-gensym* :lisp)
+(define-variable-pattern *print-level* :lisp)
+(define-variable-pattern *print-length* :lisp)
+(define-variable-pattern *print-array* :lisp)
+(define-caller-pattern with-standard-io-syntax
+ ((:star declaration)
+ (:star form))
+ :lisp2)
+
+(define-caller-pattern read (&optional form form form form) :lisp)
+(define-variable-pattern *read-default-float-format* :lisp)
+(define-caller-pattern read-preserving-whitespace
+ (&optional form form form form) :lisp)
+(define-caller-pattern read-delimited-list (form &optional form form) :lisp)
+(define-caller-pattern read-line (&optional form form form form) :lisp)
+(define-caller-pattern read-char (&optional form form form form) :lisp)
+(define-caller-pattern unread-char (form (:optional form)) :lisp)
+(define-caller-pattern peek-char (&optional form form form form) :lisp)
+(define-caller-pattern listen ((:optional form)) :lisp)
+(define-caller-pattern read-char-no-hang ((:star form)) :lisp)
+(define-caller-pattern clear-input ((:optional form)) :lisp)
+(define-caller-pattern read-from-string (form (:star form)) :lisp)
+(define-caller-pattern parse-integer (form &rest :ignore) :lisp)
+(define-caller-pattern read-byte ((:star form)) :lisp)
+
+(define-caller-pattern write (form &key (:star form)) :lisp)
+(define-caller-pattern prin1 (form (:optional form)) :lisp)
+(define-caller-pattern print (form (:optional form)) :lisp)
+(define-caller-pattern pprint (form (:optional form)) :lisp)
+(define-caller-pattern princ (form (:optional form)) :lisp)
+(define-caller-pattern write-to-string (form &key (:star form)) :lisp)
+(define-caller-pattern prin1-to-string (form) :lisp)
+(define-caller-pattern princ-to-string (form) :lisp)
+(define-caller-pattern write-char (form (:optional form)) :lisp)
+(define-caller-pattern write-string (form &optional form &key (:star form)) :lisp)
+(define-caller-pattern write-line (form &optional form &key (:star form)) :lisp)
+(define-caller-pattern terpri ((:optional form)) :lisp)
+(define-caller-pattern fresh-line ((:optional form)) :lisp)
+(define-caller-pattern finish-output ((:optional form)) :lisp)
+(define-caller-pattern force-output ((:optional form)) :lisp)
+(define-caller-pattern clear-output ((:optional form)) :lisp)
+(define-caller-pattern print-unreadable-object
+ ((form form &key (:star form))
+ (:star declaration)
+ (:star form))
+ :lisp2)
+(define-caller-pattern write-byte (form form) :lisp)
+(define-caller-pattern format
+ (destination
+ control-string
+ (:rest format-arguments))
+ :lisp)
+
+(define-caller-pattern y-or-n-p (control-string (:star form)) :lisp)
+(define-caller-pattern yes-or-no-p (control-string (:star form)) :lisp)
+
+;;; Pathnames
+(define-caller-pattern wild-pathname-p (form &optional form) :lisp2)
+(define-caller-pattern pathname-match-p (form form) :lisp2)
+(define-caller-pattern translate-pathname (form form form &key (:star form))
+ :lisp2)
+
+(define-caller-pattern logical-pathname (form) :lisp2)
+(define-caller-pattern translate-logical-pathname (form &key (:star form)) :lisp2)
+(define-caller-pattern logical-pathname-translations (form) :lisp2)
+(define-caller-pattern load-logical-pathname-translations (form) :lisp2)
+(define-caller-pattern compile-file-pathname (form &key form) :lisp2)
+
+(define-caller-pattern pathname (form) :lisp)
+(define-caller-pattern truename (form) :lisp)
+(define-caller-pattern parse-namestring ((:star form)) :lisp)
+(define-caller-pattern merge-pathnames ((:star form)) :lisp)
+(define-variable-pattern *default-pathname-defaults* :lisp)
+(define-caller-pattern make-pathname ((:star form)) :lisp)
+(define-caller-pattern pathnamep (form) :lisp)
+(define-caller-pattern pathname-host (form) :lisp)
+(define-caller-pattern pathname-device (form) :lisp)
+(define-caller-pattern pathname-directory (form) :lisp)
+(define-caller-pattern pathname-name (form) :lisp)
+(define-caller-pattern pathname-type (form) :lisp)
+(define-caller-pattern pathname-version (form) :lisp)
+(define-caller-pattern namestring (form) :lisp)
+(define-caller-pattern file-namestring (form) :lisp)
+(define-caller-pattern directory-namestring (form) :lisp)
+(define-caller-pattern host-namestring (form) :lisp)
+(define-caller-pattern enough-namestring (form (:optional form)) :lisp)
+(define-caller-pattern user-homedir-pathname (&optional form) :lisp)
+(define-caller-pattern open (form &key (:star form)) :lisp)
+(define-caller-pattern with-open-file
+ ((var form (:rest :ignore))
+ (:star declaration)
+ (:star form))
+ :lisp)
+
+(define-caller-pattern rename-file (form form) :lisp)
+(define-caller-pattern delete-file (form) :lisp)
+(define-caller-pattern probe-file (form) :lisp)
+(define-caller-pattern file-write-date (form) :lisp)
+(define-caller-pattern file-author (form) :lisp)
+(define-caller-pattern file-position (form (:optional form)) :lisp)
+(define-caller-pattern file-length (form) :lisp)
+(define-caller-pattern file-string-length (form form) :lisp2)
+(define-caller-pattern load (form &key (:star form)) :lisp)
+(define-variable-pattern *load-verbose* :lisp)
+(define-variable-pattern *load-print* :lisp2)
+(define-variable-pattern *load-pathname* :lisp2)
+(define-variable-pattern *load-truename* :lisp2)
+(define-caller-pattern make-load-form (form) :lisp2)
+(define-caller-pattern make-load-form-saving-slots (form &optional form)
+ :lisp2)
+(define-caller-pattern directory (form &key (:star form)) :lisp)
+
+;;; Errors
+(define-caller-pattern error (form (:star form)) :lisp)
+(define-caller-pattern cerror (form form (:star form)) :lisp)
+(define-caller-pattern warn (form (:star form)) :lisp)
+(define-variable-pattern *break-on-warnings* :lisp)
+(define-caller-pattern break (&optional form (:star form)) :lisp)
+(define-caller-pattern check-type (form form (:optional form)) :lisp)
+(define-caller-pattern assert
+ (form
+ (:optional ((:star var))
+ (:optional form (:star form))))
+ :lisp)
+(define-caller-pattern etypecase (form (:star (symbol (:star form)))) :lisp)
+(define-caller-pattern ctypecase (form (:star (symbol (:star form)))) :lisp)
+(define-caller-pattern ecase
+ (form
+ (:star ((:or symbol ((:star symbol)))
+ (:star form))))
+ :lisp)
+(define-caller-pattern ccase
+ (form
+ (:star ((:or symbol ((:star symbol)))
+ (:star form))))
+ :lisp)
+
+;;; The Compiler
+(define-caller-pattern compile (form (:optional form)) :lisp)
+(define-caller-pattern compile-file (form &key (:star form)) :lisp)
+(define-variable-pattern *compile-verbose* :lisp2)
+(define-variable-pattern *compile-print* :lisp2)
+(define-variable-pattern *compile-file-pathname* :lisp2)
+(define-variable-pattern *compile-file-truename* :lisp2)
+(define-caller-pattern load-time-value (form (:optional form)) :lisp2)
+(define-caller-pattern disassemble (form) :lisp)
+(define-caller-pattern function-lambda-expression (fn) :lisp2)
+(define-caller-pattern with-compilation-unit (((:star :ignore)) (:star form))
+ :lisp2)
+
+;;; Documentation
+(define-caller-pattern documentation (form form) :lisp)
+(define-caller-pattern trace ((:star form)) :lisp)
+(define-caller-pattern untrace ((:star form)) :lisp)
+(define-caller-pattern step (form) :lisp)
+(define-caller-pattern time (form) :lisp)
+(define-caller-pattern describe (form &optional form) :lisp)
+(define-caller-pattern describe-object (form &optional form) :lisp2)
+(define-caller-pattern inspect (form) :lisp)
+(define-caller-pattern room ((:optional form)) :lisp)
+(define-caller-pattern ed ((:optional form)) :lisp)
+(define-caller-pattern dribble ((:optional form)) :lisp)
+(define-caller-pattern apropos (form (:optional form)) :lisp)
+(define-caller-pattern apropos-list (form (:optional form)) :lisp)
+(define-caller-pattern get-decoded-time () :lisp)
+(define-caller-pattern get-universal-time () :lisp)
+(define-caller-pattern decode-universal-time (form &optional form) :lisp)
+(define-caller-pattern encode-universal-time
+ (form form form form form form &optional form) :lisp)
+(define-caller-pattern get-internal-run-time () :lisp)
+(define-caller-pattern get-internal-real-time () :lisp)
+(define-caller-pattern sleep (form) :lisp)
+
+(define-caller-pattern lisp-implementation-type () :lisp)
+(define-caller-pattern lisp-implementation-version () :lisp)
+(define-caller-pattern machine-type () :lisp)
+(define-caller-pattern machine-version () :lisp)
+(define-caller-pattern machine-instance () :lisp)
+(define-caller-pattern software-type () :lisp)
+(define-caller-pattern software-version () :lisp)
+(define-caller-pattern short-site-name () :lisp)
+(define-caller-pattern long-site-name () :lisp)
+(define-variable-pattern *features* :lisp)
+
+(define-caller-pattern identity (form) :lisp)
+
+;;; Pretty Printing
+(define-variable-pattern *print-pprint-dispatch* :lisp2)
+(define-variable-pattern *print-right-margin* :lisp2)
+(define-variable-pattern *print-miser-width* :lisp2)
+(define-variable-pattern *print-lines* :lisp2)
+(define-caller-pattern pprint-newline (form &optional form) :lisp2)
+(define-caller-pattern pprint-logical-block
+ ((var form &key (:star form))
+ (:star form))
+ :lisp2)
+(define-caller-pattern pprint-exit-if-list-exhausted () :lisp2)
+(define-caller-pattern pprint-pop () :lisp2)
+(define-caller-pattern pprint-indent (form form &optional form) :lisp2)
+(define-caller-pattern pprint-tab (form form form &optional form) :lisp2)
+(define-caller-pattern pprint-fill (form form &optional form form) :lisp2)
+(define-caller-pattern pprint-linear (form form &optional form form) :lisp2)
+(define-caller-pattern pprint-tabular (form form &optional form form form) :lisp2)
+(define-caller-pattern formatter (control-string) :lisp2)
+(define-caller-pattern copy-pprint-dispatch (&optional form) :lisp2)
+(define-caller-pattern pprint-dispatch (form &optional form) :lisp2)
+(define-caller-pattern set-pprint-dispatch (form form &optional form form)
+ :lisp2)
+
+;;; CLOS
+(define-caller-pattern add-method (fn form) :lisp2)
+(define-caller-pattern call-method (form form) :lisp2)
+(define-caller-pattern call-next-method ((:star form)) :lisp2)
+(define-caller-pattern change-class (form form) :lisp2)
+(define-caller-pattern class-name (form) :lisp2)
+(define-caller-pattern class-of (form) :lisp2)
+(define-caller-pattern compute-applicable-methods (fn (:star form)) :lisp2)
+(define-caller-pattern defclass (name &rest :ignore) :lisp2)
+(define-caller-pattern defgeneric (name lambda-list &rest :ignore) :lisp2)
+(define-caller-pattern define-method-combination
+ (name lambda-list ((:star :ignore))
+ (:optional ((:eq :arguments) :ignore))
+ (:optional ((:eq :generic-function) :ignore))
+ (:star (:or declaration documentation-string))
+ (:star form))
+ :lisp2)
+(define-caller-pattern defmethod
+ (name (:star symbol) lambda-list
+ (:star (:or declaration documentation-string))
+ (:star form))
+ :lisp2)
+(define-caller-pattern ensure-generic-function (name &key (:star form)) :lisp2)
+(define-caller-pattern find-class (form &optional form form) :lisp2)
+(define-caller-pattern find-method (fn &rest :ignore) :lisp2)
+(define-caller-pattern function-keywords (&rest :ignore) :lisp2)
+(define-caller-pattern generic-flet (((:star (name lambda-list))) (:star form))
+ :lisp2)
+(define-caller-pattern generic-labels
+ (((:star (name lambda-list))) (:star form))
+ :lisp2)
+(define-caller-pattern generic-function (lambda-list) :lisp2)
+(define-caller-pattern initialize-instance (form &key (:star form)) :lisp2)
+(define-caller-pattern invalid-method-error (fn form (:star form)) :lisp2)
+(define-caller-pattern make-instance (fn (:star form)) :lisp2)
+(define-caller-pattern make-instances-obsolete (fn) :lisp2)
+(define-caller-pattern method-combination-error (form (:star form)) :lisp2)
+(define-caller-pattern method-qualifiers (fn) :lisp2)
+(define-caller-pattern next-method-p () :lisp2)
+(define-caller-pattern no-applicable-method (fn (:star form)) :lisp2)
+(define-caller-pattern no-next-method (fn (:star form)) :lisp2)
+(define-caller-pattern print-object (form form) :lisp2)
+(define-caller-pattern reinitialize-instance (form (:star form)) :lisp2)
+(define-caller-pattern remove-method (fn form) :lisp2)
+(define-caller-pattern shared-initialize (form form (:star form)) :lisp2)
+(define-caller-pattern slot-boundp (form form) :lisp2)
+(define-caller-pattern slot-exists-p (form form) :lisp2)
+(define-caller-pattern slot-makeunbound (form form) :lisp2)
+(define-caller-pattern slot-missing (fn form form form &optional form) :lisp2)
+(define-caller-pattern slot-unbound (fn form form) :lisp2)
+(define-caller-pattern slot-value (form form) :lisp2)
+(define-caller-pattern update-instance-for-different-class
+ (form form (:star form)) :lisp2)
+(define-caller-pattern update-instance-for-redefined-class
+ (form form (:star form)) :lisp2)
+(define-caller-pattern with-accessors
+ (((:star :ignore)) form
+ (:star declaration)
+ (:star form))
+ :lisp2)
+(define-caller-pattern with-added-methods
+ ((name lambda-list) form
+ (:star form))
+ :lisp2)
+(define-caller-pattern with-slots
+ (((:star :ignore)) form
+ (:star declaration)
+ (:star form))
+ :lisp2)
+
+;;; Conditions
+(define-caller-pattern signal (form (:star form)) :lisp2)
+(define-variable-pattern *break-on-signals* :lisp2)
+(define-caller-pattern handler-case (form (:star (form ((:optional var))
+ (:star form))))
+ :lisp2)
+(define-caller-pattern ignore-errors ((:star form)) :lisp2)
+(define-caller-pattern handler-bind (((:star (form form)))
+ (:star form))
+ :lisp2)
+(define-caller-pattern define-condition (name &rest :ignore) :lisp2)
+(define-caller-pattern make-condition (form &rest :ignore) :lisp2)
+(define-caller-pattern with-simple-restart
+ ((name form (:star form)) (:star form)) :lisp2)
+(define-caller-pattern restart-case
+ (form
+ (:star (form form (:star form))))
+ :lisp2)
+(define-caller-pattern restart-bind
+ (((:star (name fn &key (:star form))))
+ (:star form))
+ :lisp2)
+(define-caller-pattern with-condition-restarts
+ (form form
+ (:star declaration)
+ (:star form))
+ :lisp2)
+(define-caller-pattern compute-restarts (&optional form) :lisp2)
+(define-caller-pattern restart-name (form) :lisp2)
+(define-caller-pattern find-restart (form &optional form) :lisp2)
+(define-caller-pattern invoke-restart (form (:star form)) :lisp2)
+(define-caller-pattern invoke-restart-interactively (form) :lisp2)
+(define-caller-pattern abort (&optional form) :lisp2)
+(define-caller-pattern continue (&optional form) :lisp2)
+(define-caller-pattern muffle-warning (&optional form) :lisp2)
+(define-caller-pattern store-value (form &optional form) :lisp2)
+(define-caller-pattern use-value (form &optional form) :lisp2)
+(define-caller-pattern invoke-debugger (form) :lisp2)
+(define-variable-pattern *debugger-hook* :lisp2)
+(define-caller-pattern simple-condition-format-string (form) :lisp2)
+(define-caller-pattern simple-condition-format-arguments (form) :lisp2)
+(define-caller-pattern type-error-datum (form) :lisp2)
+(define-caller-pattern type-error-expected-type (form) :lisp2)
+(define-caller-pattern package-error-package (form) :lisp2)
+(define-caller-pattern stream-error-stream (form) :lisp2)
+(define-caller-pattern file-error-pathname (form) :lisp2)
+(define-caller-pattern cell-error-name (form) :lisp2)
+(define-caller-pattern arithmetic-error-operation (form) :lisp2)
+(define-caller-pattern arithmetic-error-operands (form) :lisp2)
+
+;;; For ZetaLisp Flavors
+(define-caller-pattern send (form fn (:star form)) :flavors)
More information about the Bknr-cvs
mailing list