Hello,
I sent mail to Luke about this a few days ago, but I guess he's busy partying like it's 2003 :) (if not, then please check your common-lisp.net mailbox and disregard it!). Anyway, I've gotten the swank backend mostly working on CLISP. The file is attached. On the way, I've also discovered that the slime state machine generates an error on :read-string (and gives the "you've encountered an error in SLIME" message). This should probably be fixed (and I'm not man enough to do it), as it means that interactive restarts (and probably anything else that does query-io) doesn't work.
I also have a proposal stemming from potential problems with the current message-length and character encoding schemes. The stream character encoding should be specified by a slime variable (which defaults to something like "iso-8859-1"), whose value gets passed to a swank function on initialization, which then converts it to internal representation and binds it to a special variable, which is used when opening slime sockets. The message length should then be represented by arabic numerals - the first character in a message is 0-9 and indicated how many (1+) subsequent chars to read to get the message length (giving maximum message length of 10 9s). This is a lot less efficient than the current method, but it'll work with any character encoding scheme supporting arabic numerals (which the ANSI spec says are part of standard characters and so must be provided by every conforming implementation). I propose character encoding should be specified by ASCII strings like "UTF-8", with standard names used so you can just run find-symbol or equivalent on them to get at the encoding object in Lisp and Emacs.
Also, here are some patches for things I've changed along the way:
In slime.el (the RE doesn't work for CLISP's output, and I belive this type of formatting should be done in swank):
*************** *** 3689,3697 **** for (number string) = frame do (let (label framestring) ! (setq label (format "%s" number) ! framestring string) ! (slime-insert-propertized `(frame ,frame) " " (in-sldb-face frame-label label) " " (in-sldb-face frame-line framestring) "\n"))) (let ((number (sldb-previous-frame-number))) --- 3689,3699 ---- for (number string) = frame do (let (label framestring) ! (if (string-match "\([0-9]*:\)?\s *\(.*\)" string) ! (setq label (match-string 1 string) ! framestring (match-string 2 string)) ! (setq label "" framestring string)) ! (slime-insert-propertized `(frame ,frame) " " (in-sldb-face frame-label label) " " (in-sldb-face frame-line framestring) "\n"))) (let ((number (sldb-previous-frame-number)))
In swank-backend.lisp:
*************** *** 134,141 **** (defgeneric call-with-compilation-hooks (func) (:documentation "Call FUNC with hooks to trigger SLDB on compiler errors.")) ! (defmacro with-compilation-hooks ((&rest ignore) &body body) ! (declare (ignore ignore)) `(call-with-compilation-hooks (lambda () (progn ,@body))))
(defgeneric compile-string-for-emacs (string &key buffer position) --- 134,140 ---- (defgeneric call-with-compilation-hooks (func) (:documentation "Call FUNC with hooks to trigger SLDB on compiler errors.")) ! (defmacro with-compilation-hooks (() &body body) `(call-with-compilation-hooks (lambda () (progn ,@body))))
(defgeneric compile-string-for-emacs (string &key buffer position)
In swank.lisp (CLISP didn't like the for loop, and neither did I :)
*************** *** 434,455 ****
(defun eval-region (string &optional package-update-p) "Evaluate STRING and return the result. ! If PACKAGE-UPDATE-P is non-nil, and evaluation causes a package ! change, then send Emacs an update." ! (let ((*package* *buffer-package*) ! form ! (pos 0) ! return-values ! (end-symbol (gensym))) (unwind-protect ! (loop (multiple-value-setq (form pos) ! (read-from-string string nil end-symbol :start pos)) ! (if (eq form end-symbol) ! (return return-values) ! (setq return-values ! (multiple-value-list (eval form))))) (when (and package-update-p (not (eq *package* *buffer-package*))) ! (send-to-emacs (list :new-package (shortest-package-nickname *package*)))))))
(defun shortest-package-nickname (package) "Return the shortest nickname (or canonical name) of PACKAGE." --- 434,452 ----
(defun eval-region (string &optional package-update-p) "Evaluate STRING and return the result. ! If PACKAGE-UPDATE-P is non-nil, and evaluation causes a package ! change, then send Emacs an update." ! (let ((*package* *buffer-package*)) (unwind-protect ! (with-input-from-string (stream string) ! (loop for form = (read stream nil stream) ! until (eq form stream) ! for - = form ! for values = (multiple-value-list (eval form)) ! do (force-output) ! finally (return (values values -)))) (when (and package-update-p (not (eq *package* *buffer-package*))) ! (send-to-emacs (list :new-package (shortest-package-nickname *package*)))))))
(defun shortest-package-nickname (package) "Return the shortest nickname (or canonical name) of PACKAGE."
Happy New Years! Vladimir
sedachv sedachv@cpsc.ucalgary.ca writes:
I've gotten the swank backend mostly working on CLISP.
Me too :-) For purposes of comparison:
http://members.inode.at/wjenkner/clisp/swank-clisp.lisp
There is support for frame locals, the portable xref and some proof of concept support for compiler notes. On the other hand, you have given more thought to the socket interface. Perhaps we could combine our efforts.
My set of patches for the other files is at
http://members.inode.at/wjenkner/clisp/slime.diff
By the way, with my version I didn't run into the problem with symbol completion you described (I use the current CVS version of CLISP).
Wolfgang
On Wed, Dec 31, 2003 at 07:43:18AM +0100, Wolfgang Jenkner wrote:
sedachv sedachv@cpsc.ucalgary.ca writes:
I've gotten the swank backend mostly working on CLISP.
Me too :-) For purposes of comparison:
http://members.inode.at/wjenkner/clisp/swank-clisp.lisp
There is support for frame locals, the portable xref and some proof of concept support for compiler notes. On the other hand, you have given more thought to the socket interface. Perhaps we could combine our efforts.
Excellent! It looks like your debugging code is a lot better than mine, and I didn't even know there was a portable xref. I threw a quick cut-and-paste job together that somewhat works. It's attached, and distributed under the GPL (since most of it is your code, and I just realized I should have put my previous version under the GPL too since it is technically an extension to CLISP). One thing to note is that under CLISP 2.32, trying to compile a file from SLIME causes this error: "NO-APPLICABLE-METHOD: When calling #<GENERIC-FUNCTION SWANK::MESSAGE> with arguments (NIL), no method is applicable." The backtrace is a little hairy, and I've decided not to look into it right now.
My set of patches for the other files is at
http://members.inode.at/wjenkner/clisp/slime.diff
By the way, with my version I didn't run into the problem with symbol completion you described (I use the current CVS version of CLISP).
Hmm, it seems that I'm doing something wrong in my code (possibly stemming from stream-handling). Your version seems to work just fine (I did just upgrade to 2.32, but mine still fails with the same error as before; in particular it says: "Illegal START index <1+ (length string)> for <string>" for any completion string it tries to get). Same thing for the attached file.
Wolfgang
Vladimir
sedachv sedachv@cpsc.ucalgary.ca writes:
On Wed, Dec 31, 2003 at 07:43:18AM +0100, Wolfgang Jenkner wrote:
sedachv sedachv@cpsc.ucalgary.ca writes:
I've gotten the swank backend mostly working on CLISP.
Me too :-) For purposes of comparison:
Cool! I committed a merged version.
I tried with CLISP 2.32 and completion seems to work fine here. The debugging support doesn't seem to work with older versions (2.30), because there where changes in CLISP's internals. We should probably ask the CLISP developers if they could make some official debugger interface.
There seem to be problems with stream handling. If I set the :buffered argument for socket-accept to t, CLISP seems to wait forever, even if there is a connection. Also, CLISP's debugger doesn't seem to work well with our redirected streams. OTOH, CLISP's inspector has no problems. Not sure if the problem is in our stream code or in CLISP's debugger. Any ideas?
I added the portable xref to slime, but haven't tried it yet. We could try to implement list-callers and list-callees without the xref package. The callees of a function can be found by disassembling the bytecode (I guess that's not very hard). The callers can then be found by searching the callees of all fbound symbols.
I will ask the common-lisp.net gods to give you CVS commit rights.
Happy New Year!
Helmut.
Helmut Eller e9626484@stud3.tuwien.ac.at writes:
sedachv sedachv@cpsc.ucalgary.ca writes:
On Wed, Dec 31, 2003 at 07:43:18AM +0100, Wolfgang Jenkner wrote:
sedachv sedachv@cpsc.ucalgary.ca writes:
I've gotten the swank backend mostly working on CLISP.
Me too :-) For purposes of comparison:
Cool! I committed a merged version.
Very nice. As far as I am concerned everything works at least as well as before (and the frame locals look much better now, without some useless package markers). Also, thanks for correcting a package related reader blunder of mine (blush).
Also, CLISP's debugger doesn't seem to work well with our redirected streams. OTOH, CLISP's inspector has no problems. Not sure if the problem is in our stream code or in CLISP's debugger. Any ideas?
Also, in CLISP's (original) break loop, commands like :q don't seem to work in *slime-repl*, but things like (throw 'sys::debug 'sys::quit) do, sometimes.
The essential step might be to get SYS::READ-FORM (in src/debug.d) right. Compare the correct behaviour (from an *inferior-lisp* buffer)
(sys::read-form "test> " (list (cons ":hello" #'(lambda () (print "Hello!")))))
test> :hello
"Hello!" T ; T
with what happens in *slime-repl*
(sys::read-form "test> " (list (cons ":hello" #'(lambda () (print "Hello!"))))) :hello
test> :hello :HELLO NIL
(In both cases I typed the lower-case :hello's)
Also, Vladimir noticed:
;;; What doesn't work: ;; - Most debugging conditions use *query-io*, and the slime state-machine gets stuck on :read-string
I don't know if this is the same problem, have to investigate it.
Wolfgang