Subject: Re: bug#49104: [PATCH] 28.0.50; Handle remapped commands for M-TAB in `flyspell-prog-mode'

From: Stefan Monnier <[email-masked]>
Date: Sat, 19 Jun 2021 13:24:35 -0400

>> > Isn't it a bug that global/local-key-binding don't return such
>> > remapped bindings, at least optionally?
>> I don't
> Why not?

Good question.  I think I meant to write "I don't know" instead of just
"I don't".

>> but I wonder why flyspell-prog-mode uses those functions
>> instead of using just `key-binding`
> Because the latter is not described in the ELisp manual where
> global/local-key-binding are, and isn't referenced from there?

In that case, `key-binding` might be a good replacement.
I see that using `key-binding` could find flyspell's own binding, tho, so we
should probably use the (first) patch below instead.

Tho I also wonder why we do the lookup when flyspell is enabled instead
of doing directly in flyspell-auto-correct-word as in the second
patch below.

        Stefan

diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el
index ba48e5de21..11ff0f426f 100644
--- a/lisp/textmodes/flyspell.el
+++ b/lisp/textmodes/flyspell.el
@@ -411,8 +411,8 @@ flyspell-prog-mode
   (setq flyspell-generic-check-word-predicate
         #'flyspell-generic-progmode-verify)
   (setq-local flyspell--prev-meta-tab-binding
-              (or (local-key-binding "\M-\t" t)
-                  (global-key-binding "\M-\t" t)))
+              (let ((flyspell-mode nil))
+                (key-binding "\M-\t")))
   (flyspell-mode 1)
   (run-hooks 'flyspell-prog-mode-hook))

diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el
index ba48e5de21..649057270e 100644
--- a/lisp/textmodes/flyspell.el
+++ b/lisp/textmodes/flyspell.el
@@ -401,18 +401,12 @@ flyspell-generic-progmode-verify
     (let ((f (get-text-property (1- (point)) 'face)))
       (memq f flyspell-prog-text-faces))))
 
-(defvar flyspell--prev-meta-tab-binding nil
-  "Records the binding of M-TAB in effect before flyspell was activated.")
-
 ;;;###autoload
 (defun flyspell-prog-mode ()
   "Turn on `flyspell-mode' for comments and strings."
   (interactive)
   (setq flyspell-generic-check-word-predicate
         #'flyspell-generic-progmode-verify)
-  (setq-local flyspell--prev-meta-tab-binding
-              (or (local-key-binding "\M-\t" t)
-                  (global-key-binding "\M-\t" t)))
   (flyspell-mode 1)
   (run-hooks 'flyspell-prog-mode-hook))
 
@@ -1990,13 +1984,10 @@ flyspell-auto-correct-word
   (interactive)
   ;; If we are not in the construct where flyspell should be active,
   ;; invoke the original binding of M-TAB, if that was recorded.
-  (if (and (local-variable-p 'flyspell--prev-meta-tab-binding)
-           (commandp flyspell--prev-meta-tab-binding t)
-           (functionp flyspell-generic-check-word-predicate)
-           (not (funcall flyspell-generic-check-word-predicate))
-           (equal (where-is-internal 'flyspell-auto-correct-word nil t)
-                  [?\M-\t]))
-      (call-interactively flyspell--prev-meta-tab-binding)
+  (if (and (functionp flyspell-generic-check-word-predicate)
+           (not (funcall flyspell-generic-check-word-predicate)))
+      (let ((flyspell-mode nil))
+        (execut-command (key-binding (this-command-keys))))
     (let ((pos     (point))
           (old-max (point-max)))
       ;; Flush a possibly stale cache from previous invocations of