[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bitten by lexical-binding

From: Drew Adams
Subject: bitten by lexical-binding
Date: Sat, 21 Nov 2015 14:28:11 -0800 (PST)

I should hardly complain without understanding completely
what is going on, but FWIW:

I redefine `mouse-drag-region', so that if you click in
the echo area when *Messages* is already displayed then:
(1) `M-x' is invoked and (2) the *Messages* window is
removed.  Otherwise, it behaves the same as the vanilla

Not a big change, and this code has worked from Emacs 22
on.  And the part of the redefinition that differs from
the vanilla definition is not even in question here.

The vanilla definition of `mouse-drag-region' is this:

 (defun mouse-drag-region (start-event)
   (interactive "e")
   (run-hooks 'mouse-leave-buffer-hook)
   (mouse-drag-track start-event))

Prior to Emacs 24.4 it was the same, except the last line
had (mouse-drag-track start-event t).  My version of it too
had (mouse-drag-track start-event t).

Starting with Emacs 25, `mouse-drag-track' does not accept
the second arg.  But invoking it without that argument meant
that (my version of) `mouse-drag-region' no longer copied
the text to the kill ring, when `mouse-drag-copy-region'=t.
That was the problem.

I spent quite a while debugging this.  Using the debugger
or using calls to `message' to print out state was useless.

What changed in vanilla Emacs was `mouse-drag-track'.  It
now uses `set-transient-map' instead of handling a second
arg.  But finding just what change to make, to fix my code,
was really not easy.

It turned out (though I do not understand completely) that
the only thing I needed to do was to add a `lexical-binding'
declaration to my file.  (Luckily, the code in the file did
not depend on dynamic binding.)

My redefinition of `mouse-drag-region' does not make any
apparent use of visible lexical binding - no free vars,
no use of closures, etc.

`mouse-drag-track' does depend on lexical binding.  But
my code does not change `mouse-drag-track' in any way -
it just calls it, exactly the same way that vanilla Emacs
calls it.

Why is it that with dynamic binding my code did not work
(but it works with lexical binding)?

The same thing was true whether I byte-compiled my code or
not, and regardless of which Emacs version I byte-compiled
it in (even Emacs 20!).  And the same thing was true if I
loaded the vanilla source code (mouse.el) first, instead
of its byte-compiled version (mouse.elc).

An explanation of this would be great.  Meanwhile, this
seems like a gotcha.  Just because some function depends
on lexical binding, why should code that calls it also
need to use lexical binding?


Here is my code, FWIW.  The only part that differs from the
vanilla code is the handling of a click in the echo area.
And that part is not what misbehaved - it can be ignored here.

AFAIU, nothing in this code should change because of lexical
vs dynamic binding.  What am I missing?

(defun mouse-drag-region (start-event)
  (interactive "e")
  (let ((clickwin  (posn-window (event-start start-event))))
    (if (and (window-minibuffer-p clickwin)
             (not (minibuffer-window-active-p clickwin)))
        (let* ((Messages-buf (get-buffer-create "*Messages*"))
               (Messages-win (get-buffer-window Messages-buf
          (if Messages-win
              (let ((M-x-cmd  (or (key-binding "\M-x" t)
                (if (eq Messages-win (selected-window))
                  (delete-window Messages-win))
                  (call-interactively M-x-cmd nil [(meta ?x)])))
              (set-buffer Messages-buf)
              (goto-char (point-max))
              (display-buffer (current-buffer)))))
      (run-hooks 'mouse-leave-buffer-hook)
      (let ((emacs24.4+
              (or (> emacs-major-version 24)
                  (and (= emacs-major-version 24)
                       (not (version< emacs-version "24.3.50"))))))
        (if emacs24.4+
            (mouse-drag-track start-event) ; <=========
          (mouse-drag-track start-event t))))))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]