I have a file which defines a readtable so I can type things like #v(1 2). (Don't ask. :-)
When I hit M-. to find any definition in this file, emacs croaks and asks if I want to enter recursive edit. Saying yes yields a SLDB buffer like this:
Subcharacter #\v not defined for dispatch char ##. [Condition of type CONDITIONS:SIMPLE-READER-ERROR]
Restarts: 0: [ABORT] Abort handling SLIME request. 1: [ABORT] Quit process.
Now, I grovelled a bit in the sources and found: (defvar *readtable-alist* '() "An alist mapping package names to readtables.")
I tried to use this thusly:
Try to add what I think is reasonable to this alist CL-USER> (push (cons "GRAPHICS" *readtable*) swank::*readtable-alist*) (("GRAPHICS" . #<READTABLE 202E1B84>))
Verify that it finds the right package CL-USER> (swank::guess-buffer-readtable "graphics") #<READTABLE 202E1B84>
Make sure the correct table is in place: CL-USER> (get-dispatch-macro-character ## #\v (swank::guess-buffer-readtable "graphics")) #<function GRAPHICS::VECTOR-READER 237CF9D2> (looks good).
However, the next M-. failed in exactly the same way.
Tracing GUESS-BUFFER-READTABLE, I found it was in fact calling it with argument ":graphics", which I thought sub-optimal, but, no matter: CL-USER> (push (cons ":graphics" *readtable*) swank::*readtable-alist*) ((":graphics" . #<READTABLE 202E1B84>) ("GRAPHICS" . #<READTABLE 202E1B84>))
Now, surely it will work, right? Nope. Any clues?
Cheers, --ap
Alain.Picard@memetrics.com writes:
I have a file which defines a readtable so I can type things like #v(1 2). (Don't ask. :-)
When I hit M-. to find any definition in this file, emacs croaks and asks if I want to enter recursive edit. Saying yes yields a SLDB buffer like this:
The `with-standard-io-syntax' in dspec-stream-position looks suspicious to me (swank-lispworks.lisp). How about if you remove it?
-Luke
Luke Gorrie writes:
Alain.Picard@memetrics.com writes:
I have a file which defines a readtable so I can type things like #v(1 2). (Don't ask. :-)
When I hit M-. to find any definition in this file, emacs croaks and asks if I want to enter recursive edit. Saying yes yields a SLDB buffer like this:
The `with-standard-io-syntax' in dspec-stream-position looks suspicious to me (swank-lispworks.lisp). How about if you remove it?
If you remove it, it works. In fact, I think there are TWO bugs in that function; I think that *read-eval* needs to be set to T. I propose:
(defun dspec-stream-position (stream dspec) (let ((*read-eval* t)) (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))))))
in swank-lispworks.lisp.
Thanks!
Alain.Picard@memetrics.com writes:
If you remove it, it works. In fact, I think there are TWO bugs in that function; I think that *read-eval* needs to be set to T. I propose:
Committed, though I don't really understand this dspec mechanism.
I suspect we should also be making a dynamic binding of *package* to avoid side-effecting the global value while looking up a location. Right?
-Luke
On Thu, 17 Jun 2004 18:56:58 +1000, Alain.Picard@memetrics.com said:
ap> Luke Gorrie writes:
Alain.Picard@memetrics.com writes:
I have a file which defines a readtable so I can type things like #v(1 2). (Don't ask. :-)
When I hit M-. to find any definition in this file, emacs croaks and asks if I want to enter recursive edit. Saying yes yields a SLDB buffer like this:
The `with-standard-io-syntax' in dspec-stream-position looks suspicious to me (swank-lispworks.lisp). How about if you remove it?
ap> If you remove it, it works. In fact, I think there are TWO bugs ap> in that function; I think that *read-eval* needs to be set to T.
It was bound it to NIL to prevent unexpected evaluation -- it depends on how dangerous you want M-. to be :-)
#.(call-system "rm -rf /")
ap> I propose:
ap> (defun dspec-stream-position (stream dspec) ap> (let ((*read-eval* t)) ap> (loop (let* ((pos (file-position stream)) ap> (form (read stream nil '#1=#:eof))) ap> (when (eq form '#1#) ap> (return nil)) ap> (labels ((check-dspec (form) ap> (when (consp form) ap> (let ((operator (car form))) ap> (case operator ap> ((progn) ap> (mapcar #'check-dspec ap> (cdr form))) ap> ((eval-when locally macrolet symbol-macrolet) ap> (mapcar #'check-dspec ap> (cddr form))) ap> ((in-package) ap> (let ((package (find-package (second form)))) ap> (when package ap> (setq *package* package)))) ap> (otherwise ap> (let ((form-dspec (dspec:parse-form-dspec form))) ap> (when (dspec:dspec-equal dspec form-dspec) ap> (return pos))))))))) ap> (check-dspec form))))))
ap> in swank-lispworks.lisp.
I made it use WITH-STANDARD-IO-SYNTAX originally to get all the standard bindings, in particular you must also bind *PACKAGE* because the function sets it. There is also *READ-BASE*, *READ-DEFAULT-FLOAT-FORMAT* and *READ-SUPPRESS* to consider.
What binds *READTABLE* when you do M-. anyway? It doesn't seem to be bound for me when DSPEC-STREAM-POSITION is reached via FIND-DEFINITIONS-FOR-EMACS.
__Martin
Martin Simmons martin@xanalys.com writes:
I made it use WITH-STANDARD-IO-SYNTAX originally to get all the standard bindings, in particular you must also bind *PACKAGE* because the function sets it. There is also *READ-BASE*, *READ-DEFAULT-FLOAT-FORMAT* and *READ-SUPPRESS* to consider.
True, plus any other implementation-defined reader setting (I don't know if LispWorks has any). I particularly hadn't realised that with-standard-io-syntax was binding *package*.
I hacked it to use a `with-fairly-standard-io-syntax' macro. This does with-standard-io-syntax but then rebinds *package* and *readtable* as they were before executing the body. Sound reasonable?
What binds *READTABLE* when you do M-. anyway? It doesn't seem to be bound for me when DSPEC-STREAM-POSITION is reached via FIND-DEFINITIONS-FOR-EMACS.
[Just read the *readtable-alist* code for the first time.]
Nobody sets it for definition-finding. That's reasonable in swank.lisp since it doesn't know what package the definition will be in. Perhaps ideal would be for dspec-stream-position to set the right readtable (from *readtable-alist*) when it sees IN-PACKAGE. I'm not sure if the other backends can/should do this too. We'd have to move *readtable-alist* into swank-backend.lisp.
But I suspect the main issue right now is to make sure that a custom-hacked readtable that one installs globally as *READTABLE* will be used by `M-.'. That's how I do my readtable'ery, at least.
P.S., Helmut, I think I was sleeping when *readtable-alist* when in. Could you post a snippet of how it's supposed to be used?
Cheers, Luke
Luke Gorrie luke@bluetail.com writes:
That's reasonable in swank.lisp since it doesn't know what package the definition will be in.
er, yes it does, from the symbol. I wonder if it's worth choosing *readtable* based on the package of the symbol we're looking up.
On Thu, 17 Jun 2004 13:47:25 +0200, Luke Gorrie luke@bluetail.com said:
Luke> Martin Simmons martin@xanalys.com writes:
I made it use WITH-STANDARD-IO-SYNTAX originally to get all the standard bindings, in particular you must also bind *PACKAGE* because the function sets it. There is also *READ-BASE*, *READ-DEFAULT-FLOAT-FORMAT* and *READ-SUPPRESS* to consider.
Luke> True, plus any other implementation-defined reader setting (I don't Luke> know if LispWorks has any). I particularly hadn't realised that Luke> with-standard-io-syntax was binding *package*.
Luke> I hacked it to use a `with-fairly-standard-io-syntax' macro. This does Luke> with-standard-io-syntax but then rebinds *package* and *readtable* as Luke> they were before executing the body. Sound reasonable?
Yes, sound good.
What binds *READTABLE* when you do M-. anyway? It doesn't seem to be bound for me when DSPEC-STREAM-POSITION is reached via FIND-DEFINITIONS-FOR-EMACS.
Luke> [Just read the *readtable-alist* code for the first time.]
Luke> Nobody sets it for definition-finding. That's reasonable in swank.lisp Luke> since it doesn't know what package the definition will be in. Perhaps Luke> ideal would be for dspec-stream-position to set the right readtable Luke> (from *readtable-alist*) when it sees IN-PACKAGE. I'm not sure if the Luke> other backends can/should do this too. We'd have to move Luke> *readtable-alist* into swank-backend.lisp.
Luke> But I suspect the main issue right now is to make sure that a Luke> custom-hacked readtable that one installs globally as *READTABLE* will Luke> be used by `M-.'. That's how I do my readtable'ery, at least.
It looks like using SWANK::WITH-BUFFER-SYNTAX somewhere might be the right thing, since *BUFFER-READTABLE* and *BUFFER-PACKAGE* are already bound.
__Martin
Luke Gorrie luke@bluetail.com writes:
Nobody sets it for definition-finding. That's reasonable in swank.lisp since it doesn't know what package the definition will be in. Perhaps ideal would be for dspec-stream-position to set the right readtable (from *readtable-alist*) when it sees IN-PACKAGE. I'm not sure if the other backends can/should do this too. We'd have to move *readtable-alist* into swank-backend.lisp.
For CMUCL/SBCL, at least, we don't look at the IN-PACKAGE forms. *read-suppress* is T most of the time and we only look at the "shape" of the expression.
But I suspect the main issue right now is to make sure that a custom-hacked readtable that one installs globally as *READTABLE* will be used by `M-.'. That's how I do my readtable'ery, at least.
Yeah, and it's probably what 99% of the users do. People who use multiple readtables deserve to loose :-)
P.S., Helmut, I think I was sleeping when *readtable-alist* when in. Could you post a snippet of how it's supposed to be used?
It went in with the other SBCL reader stuff. Say you have a package foo and readtable *bar* then you could use it like:
(push (cons (package-name :foo) *bar*) swank::*readtable-alist*)
swank::eval-for-emacs uses this to bind *buffer-readtable*; the current readtable will be used if there's no entry in the *readtable-alist*.
`with-buffer-syntax' can then be used to actually bind *readtable* to *buffer-readtable*. I replaced most uses of
(let ((*package* *buffer-package*)) ...)
with the idiom:
(defslimefun <foo> (...) (with-buffer-syntax () ...))
All this is currently only used for SBCL and I don't know if *readtable-alist* is very useful for users. I assumed it is more convenient to associate readtables with packages than to use Emacs-style file variables, ala -*- readtable: ... -*-. OTOH, file variables would be handy when find-definitions opens an arbitrary file; we could just look at the first line.
Helmut.
Helmut Eller writes:
Luke Gorrie luke@bluetail.com writes:
But I suspect the main issue right now is to make sure that a custom-hacked readtable that one installs globally as *READTABLE* will be used by `M-.'. That's how I do my readtable'ery, at least.
Yeah, and it's probably what 99% of the users do. People who use multiple readtables deserve to loose :-)
I'm currently working on Objective-C integration with CLOS, and the code implementing the integration uses a normal readtable, while ObjC-using code needs a different readtable (so far the only change is to use :invert read-case to support camelCase ObjC method names). The specter of having to constantly switch readtables has made me think about adding the ability to associate a readtable with an Emacs buffer.
All this is to say that I think there are reasonable situations in which this might come up.
All this is currently only used for SBCL and I don't know if *readtable-alist* is very useful for users. I assumed it is more convenient to associate readtables with packages than to use Emacs-style file variables, ala -*- readtable: ... -*-. OTOH, file variables would be handy when find-definitions opens an arbitrary file; we could just look at the first line.
I think the file variables method is the way to go, maybe in combination with grovelling for a (setf *readtable* ...) form at the top of the file, so the common case gets handled automatically.