Hi,
I would like to propose an small improvement to slime-edit-definition so that it correctly identifies setf forms (which it doesn't, at the moment).
The change is limited to the interactive pseudo-call. Instead of
(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: "))) ...)
use
(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-edit-definition-query (slime-extract-context)))) ...)
The function slime-edit-definition-query is just a stripped down version of slime-trace-query:
(defun slime-edit-definition-query (spec) "Ask the user which function to edit; SPEC is the default. The result is a string." (cond ((null spec) (slime-read-from-minibuffer "Name: ")) ((symbolp spec) (symbol-name spec)) (t (destructure-case spec ((setf n) (prin1-to-string spec)) (((:defun :defmacro :defgeneric) n) (prin1-to-string n)) ((:defmethod n &rest _) (prin1-to-string n)) ((:call caller callee) (prin1-to-string callee)) (((:labels :flet) &rest _) (slime-read-from-minibuffer "Name: "))))))
That would be enough, if it were not for the fact that, in some cases, Slime is not correctly identifying the relevant context information. One reason seems to be the slime-in-expression-p function. Here are a few examples (the . is the cursor):
(defun zdzz () (setfabble-p fo.o)) -> (:defun (setf foo))
(defun zdzz () (setfab.ble-p foo)) -> (:defun (setf setfabble-p))
(defmacro-transform bla () (bo.o)) -> (:call (:defmacro bla) boo)
(defmacro-transform b.la () (boo)) -> (:defmacro bla)
(defmacro-tran.sform bla () (boo)) -> (:defmacro defmacro-transform)
(defunia (bsd.o)) -> (:call (:defun (bsdo)) bsdo)
(defun.ia (bsdo)) -> (:defun defunia)
One problem is the (looking-at (symbol-name p)) form in slime-in-expression-p that, obviously, is happy even if the symbol being searched only _partially_ matches the actual text. So either we replace it with something similar to
(looking-at (concat (symbol-name p) "\S_"))
or, in order to deal with end-of-buffer limits, with something similar to
(let ((symbol (buffer-substring-no-properties (point) (save-excursion (forward-sexp 1) (point))))) (string= symbol (symbol-name p)))
With this change, the examples now produce:
(defun zdzz () (setfabble-p fo.o)) -> foo
(defun zdzz () (setfab.ble-p foo)) -> (:call (:defun zdzz) setfabble-p)
(defmacro-transform bla () (bo.o)) -> (:call bla boo)
(defmacro-transform b.la () (boo)) -> bla
(defmacro-tran.sform bla () (boo)) -> (:call bla defmacro-transform)
(defunia (bsd.o)) -> (:call (bsdo) bsdo)
(defun.ia (bsdo)) -> (:call (bsdo) defunia)
It's better but there are still some problems, visible in the last three examples. Fortunately, they don't severely affect what I want to do and, besides, I'm not sure about the inner workings of the slime-in-expression-p function (it seems incomplete, imho), so I'll leave it that way for now.
BTW, this was only superficially tested, but it seems to work.
Best regards,
António Leitão.
* Antonio Menezes Leitao [2006-11-22 20:42+0100] writes:
Hi,
I would like to propose an small improvement to slime-edit-definition so that it correctly identifies setf forms (which it doesn't, at the moment).
Are you saying that, if point is at (setf c.ar), M-. should automatically jump to the definition of #'(setf car) ?
Currently it jumps to #'car. I think it would be more appropriate to show both alternatives and let the user choose (as we do for generic functions).
To implement that, we need to change swank-backend:find-definitions, but we could avoid the brittle parsing of the syntactic context.
Helmut.
Hi,
Helmut Eller heller@common-lisp.net writes:
Are you saying that, if point is at (setf c.ar), M-. should automatically jump to the definition of #'(setf car) ?
Not quite. What I'm saying is that if the point is at
(setf (c.ar x) y)
or
(setf (foo x) y (bar y) x (c.ar z) w)
then we should jump to #'(setf car), no questions asked (because the context seems clear enough to me).
BTW, currently, in a form such as
(defun u () (setf foo (bar.baz)))
The function slime-extract-context incorrectly returns
(:call (:defun u) (setf barbaz))
instead of
(:call (:defun u) barbaz)
António Leitão.
Antonio Menezes Leitao aml@gia.ist.utl.pt writes:
Helmut Eller heller@common-lisp.net writes:
Are you saying that, if point is at (setf c.ar), M-. should automatically jump to the definition of #'(setf car) ?
Not quite. What I'm saying is that if the point is at
(setf (c.ar x) y)
or
(setf (foo x) y (bar y) x (c.ar z) w)
then we should jump to #'(setf car), no questions asked (because the context seems clear enough to me).
I would greatly prefer to be offered both (SETF CAR) and CAR.
Also, consider setf-expansions:
(defun mycar (x) (car x)) (defun setmycar (x y) (setf (car x) y)) (defsetf mycar setmycar)
What should happen in this?
(setf (my.car *x*) 42)
IMO ideally the user would be presented with all three possibilities in the XREF buffer, or just MYCAR and the (DEFSETF MYCAR).
Cheers,
-- Nikodemus Schemer: "Buddha is small, clean, and serious." Lispnik: "Buddha is big, has hairy armpits, and laughs."
Nikodemus Siivola nikodemus@random-state.net writes:
I would greatly prefer to be offered both (SETF CAR) and CAR.
Also, consider setf-expansions:
(defun mycar (x) (car x)) (defun setmycar (x y) (setf (car x) y)) (defsetf mycar setmycar)
What should happen in this?
(setf (my.car *x*) 42)
IMHO, we should jump to the defsetf form.
Then, moving the point to setmycar, we can jump to the setmycar definition. In case we move the point to mycar, we can jump to the mycar definition (if it exists).
This seems consistent behaviour, to me.
IMO ideally the user would be presented with all three possibilities in the XREF buffer, or just MYCAR and the (DEFSETF MYCAR).
If I'm allowed to vote, I vote for presenting just the defsetf because it's the form that allows you to write (setf (mycar ...) ...) in the first place. In your example, mycar is also a defined function but, for defsetf purposes, that's irrelevant. As a result, it shouldn't be presented as relevant. But that's just my opinion and I will not be bothered if you choose to implement it the way as you seem to prefer.
António Leitão.
If I'm allowed to vote, I vote for presenting just the defsetf because it's the form that allows you to write (setf (mycar ...) ...) in the first place. In your example, mycar is also a defined function but, for defsetf purposes, that's irrelevant. As a result, it shouldn't be presented as relevant. But that's just my opinion and I will not be bothered if you choose to implement it the way as you seem to prefer.
OTOH, it's the same question as whether presenting all the methods with the same name, or jumping to the one directly where you pressed M-.
"Attila Lendvai" attila.lendvai@gmail.com writes:
If I'm allowed to vote, I vote for presenting just the defsetf because it's the form that allows you to write (setf (mycar ...) ...) in the first place. In your example, mycar is also a defined function but, for defsetf purposes, that's irrelevant. As a result, it shouldn't be presented as relevant. But that's just my opinion and I will not be bothered if you choose to implement it the way as you seem to prefer.
OTOH, it's the same question as whether presenting all the methods with the same name, or jumping to the one directly where you pressed M-.
Are you talking about jumping from a generic function call to a specific method invocation? I mean, from (foo ...) to a specific (defmethod foo ...)?
How would you know which method is the correct target for the jump?
António Leitão.
OTOH, it's the same question as whether presenting all the methods with the same name, or jumping to the one directly where you pressed M-.
Are you talking about jumping from a generic function call to a specific method invocation? I mean, from (foo ...) to a specific (defmethod foo ...)?
How would you know which method is the correct target for the jump?
my point was: how do you know that the user pressed M-. because he wanted to jump to the setf function? could be he wanted to actually jump to the reader function and the symbol was at hand in a setf expression.
but it would be a good feature that even though the xref buffer is shown, the setf variant could be activated by default.
* Antonio Menezes Leitao [2006-11-23 14:00+0100] writes:
If I'm allowed to vote, I vote for presenting just the defsetf because it's the form that allows you to write (setf (mycar ...) ...) in the first place. In your example, mycar is also a defined function but, for defsetf purposes, that's irrelevant. As a result, it shouldn't be presented as relevant. But that's just my opinion and I will not be bothered if you choose to implement it the way as you seem to prefer.
I committed the change for slime-in-expression-p but left slime-edit-definition as it was, because:
- the current code to extract the context incomplete (and most likely buggy)
- only a few backends return something sensible for (setf NAME)
- different people have different expectations what the proper context is
I think our current strategy is not only simpler to implement but also more predictable. If you don't like that decision, than you can rebind the M-. key to your version with very few lines of code.
Helmut.