Subject: bug#3938: 23.0.96; regression: minibuffer-message interferes with C-u
From: "Drew Adams" <[email-masked]>
To: "'Chong Yidong'" <[email-masked]>
Cc: <[email-masked]>
Date: Tue, 28 Jul 2009 13:14:19 -0700

> The function `sit-for', which `minibuffer-message' uses, treats C-u
> specially.  It's easy to get your code to work; just put the call to
> `minibuffer-message' after `ensure-overriding-map-is-bound':
> 
> (defun test-univ-arg ()
>   (interactive)
>   (setq prefix-arg                     (list 4)
>         universal-argument-num-events  (length (this-command-keys)))
>   (ensure-overriding-map-is-bound)
>   (minibuffer-message "FOO"))

Actually, I already had the call to `minibuffer-message' last, in my own code.

I pared down my original code again, and discovered that the problem of the
regression is elsewhere. (Note, BTW, that the definition of `sit-for' has not
changed in Emacs 23 wrt Emacs 22, and this bug is a regression from Emacs 22.)

emacs -Q

(define-key minibuffer-local-must-match-map "\C-f" 'test2)
(define-key minibuffer-local-must-match-map
  (vector 'remap 'universal-argument) 'test-univ-arg)

(defun test2 () (interactive) (describe-function '+))

(defun test-univ-arg ()
  (interactive)
  (setq prefix-arg                     (list 4)
        universal-argument-num-events  (length (this-command-keys)))
  (my-ensure-overriding-map-is-bound)
  (minibuffer-message "FOO"))

;; Same as `ensure-overriding-map-is-bound', but with
;; `my-universal-argument-map' instead of `universal-argument-map'.
(defun my-ensure-overriding-map-is-bound ()
  (unless overriding-map-is-bound
    (setq saved-overriding-map           overriding-terminal-local-map
          overriding-terminal-local-map  my-universal-argument-map
          overriding-map-is-bound        t)))

;; Exact copy of `universal-argument-map'.
(defvar my-universal-argument-map
  (let ((map  (make-sparse-keymap)))
    (define-key map [t] 'universal-argument-other-key)
    (define-key map (vector meta-prefix-char t) 'universal-argument-other-key)
    (define-key map [switch-frame] nil)
    (define-key map [?\C-u] 'universal-argument-more)
    (define-key map [?-] 'universal-argument-minus)
    (define-key map [?0] 'digit-argument)
    (define-key map [?1] 'digit-argument)
    (define-key map [?2] 'digit-argument)
    (define-key map [?3] 'digit-argument)
    (define-key map [?4] 'digit-argument)
    (define-key map [?5] 'digit-argument)
    (define-key map [?6] 'digit-argument)
    (define-key map [?7] 'digit-argument)
    (define-key map [?8] 'digit-argument)
    (define-key map [?9] 'digit-argument)
    (define-key map [kp-0] 'digit-argument)
    (define-key map [kp-1] 'digit-argument)
    (define-key map [kp-2] 'digit-argument)
    (define-key map [kp-3] 'digit-argument)
    (define-key map [kp-4] 'digit-argument)
    (define-key map [kp-5] 'digit-argument)
    (define-key map [kp-6] 'digit-argument)
    (define-key map [kp-7] 'digit-argument)
    (define-key map [kp-8] 'digit-argument)
    (define-key map [kp-9] 'digit-argument)
    (define-key map [kp-subtract] 'universal-argument-minus)
    map))

IOW, we use an exact copy of `universal-argument-map' instead of
`universal-argument-map' itself. That's the only change from vanilla Emacs (the
definition of `my-ensure-overriding-map-is-bound' just reflects the vanilla
definition).

Same instructions as before: M-x C-u C-f, hitting C-f right after C-u (no delay)
vs waiting until the 2-sec delay for `minibuffer-message' has elapsed.

Compare the same test using Emacs 22.

With Emacs 23, the delay must elapse entirely - the user input event of hitting
`C-f' does not seem to interrupt it (`sit-for' should be interrupted by an input
event). So the effect, in Emacs 23, is that you need to hit `C-f' twice (or wait
before hitting it). In Emacs 22, hitting `C-f' just once works immediately. In
Emacs 23, the first `C-f' just has the effect of clearing "FOO" from the
minibuffer.

[Also, if instead of using `my-universal-argument-map' you use (copy-keymap
universal-argument-map) the result is the same. Using
`my-universal-argument-map' is a better test, since `copy-keymap' doesn't copy
recursively.]