1

In realgud I have a text button that needs access to a dynamically-bound buffer-local variable.

The situation occurs like this. Inside one buffer that has the buffer local variable, there is a command that creates another "Describe" buffer with the value of that complex defstruct variable formatted nicely using org mode.

But inside that "Describe" buffer I would like to have a button that calls describe-variable on the variable, but have that use the value from its original buffer location, not the value in the describe buffer.

Currently I have inside insert-text-button an action property like this:

'action '(lambda(button) (describe-variable 'realgud-cmdbuf-info))

However this gives picks up the wrong buffer-local value. I can't change the above say to:

'action '(lambda(button) (with-current-buffer buffer (describe-variable 'realgud-cmdbuf-info)))

because of the quote in front of the lambda, and because with-current-buffer is a macro. Changing that to start `list('lambda(button) would be cumbersome if I could figure it out.

Probably I need to use some macro here, but that also is beyond my comprehension.

Help?

`

  • `` `(lambda (button) (with-current-buffer ',buffer (describe-variable 'readgud-cmdbuf-info)))``. – Drew Aug 8 '16 at 13:58
  • @Drew Sorry for the delayed reply. When I try that I get "save-current-buffer: Wrong type argument: stringp, (\, buffer)" – rocky Aug 10 '16 at 0:15
  • What I wrote should not be quoted. Remove the outer two backquotes from each end. There needs to be a single backquote in front of this: (lambda (button) (with-current-buffer ',buffer (describe-variable 'realgud-cmdbuf-info))). Of course, this must be done in a context where buffer is defined. – Drew Aug 10 '16 at 1:31
  • I had removed the outer two quotes when I tried this initially as I figured that was a typesetting artefact. So unsurprisingly, I get the same error message: Wrong type argument: stringp, (\, buffer). I am getting this when the lambda is called and the body executed, not when it is defined. – rocky Aug 11 '16 at 6:55
  • 1
    Assuming buffer is bound in this scope, all you have to do is remove the quote before lambda and enable lexical-binding in the .el file. Alternatively use a backquote ` and then splice it in with , as suggested. What ever you do don't single-quote lambdas, unless you want it to be treated as constant data, e.g. by the compiler. – politza Aug 29 '16 at 19:22
3
+50

You can add not only action but any other attributes to a text-button, that can be referred later with button-get function. So saving the (reference to the) current buffer, together with action, seems a good idea here.

(insert-text-button
     "realgud-cmdbuf-info"
     'buffer buffer
     'action (lambda (b)
           (with-current-buffer (button-get b 'buffer)
             (describe-variable 'realgud-cmdbuf-info)))

Another solution is to enable lexical-binding in your script, that simply disables dynamic-binding.

  • 1
    Thanks - this works. However so that others may benefit it would be great to get a more detailed explanation of what's going on and how this addresses the problem. This was explicitly mentioned in the bounty. If you can do that great. If not, I think I understand what's going on and when I get a chance I may try add more of an explanation. Also, at some point I'll revise the question to make the problem clearer. – rocky Aug 29 '16 at 10:56
  • Edited the answer. You can put any attributes to a button and 'buffer is not a special-case. – zk_phi Aug 30 '16 at 5:47
1

Start your file with

;; Copyright (C) 2015-2016 Free Software Foundation, Inc -*- lexical-binding: t -*-

Now you're able to use closures in your Lisp code, e.g.

(let ((x 0))
  (lambda () (setq x (1+ x))))

will create a count function. The same applies to your anonymous function, it will close over it's lexical environment, i.e. it knows about the variable buffer.

(insert-text-button
 "realgud-cmdbuf-info"
 'action (lambda (_button) ;; underscore makes compiler happy
           (describe-variable 'realgud-cmdbuf-info buffer))
 'help-echo "mouse-2: help-on-variable")

In rare circumstances, enabling lexical-binding can break your code, but only if you did something stupid to begin with. For example accessing local variables from a function up the call-stack. And of course this won't work, if you're programming for ancient Emacs (I believe it was introduced in 24.1).

  • lexical binding was introduced in 24.1 (see NEWS.24 - C-2 C-4 <f1> n). The 'buffer buffer should be redundant if you do it this way. – npostavs Sep 1 '16 at 2:14
  • Unless he's using it someplace else, tough it doesn't look that way. – politza Sep 1 '16 at 2:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.