emacs-devel
[Top][All Lists]
Advanced

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

A possible CUA-mode bug about `cua-prefix-override-inhibit-delay` and it


From: Siyuan Chen
Subject: A possible CUA-mode bug about `cua-prefix-override-inhibit-delay` and its workaround
Date: Wed, 22 May 2024 15:25:20 +0800

Hi Emacs-devel team,

Currently, there seems to be a bug in CUA-mode, i.e. when `(setq cua-prefix-override-inhibit-delay nil)`, cut and copy do not work.

From the `cua-prefix-override-inhibit-delay` docs

> If non-nil, time in seconds to delay before overriding prefix key. If there is additional input within this time, the prefix key is used as a normal prefix key.  So typing a key sequence quickly will inhibit overriding the prefix key. As a special case, if the prefix key is repeated within this time, the first prefix key is discarded, so typing a prefix key twice in quick succession will also inhibit overriding the prefix key.
> If the value is nil, use a shifted prefix key to inhibit the override."

So I assume that

(1) CUA-mode allows user `(setq cua-prefix-override-inhibit-delay nil)`.

(2) When `(setq cua-prefix-override-inhibit-delay nil)`, CUA-mode should disable the timer feature, and expect the user to use Shift instead, i.e. the old prefix key `C-x` -> new prefix key `C-S-x`.

Unfortunately, it is not the case. `(setq cua-prefix-override-inhibit-delay nil)` will cause a totally disabled CUA-mode feature, i.e. selecting a region and pressing `C-x` never cuts the region. This obviously breaks the docs behavior!

Noticed that in cua-base.el, the `cua--prefix-override-replay` pushes back the key `^X` to `unread-command-events` via `(setq unread-command-events (cons (cons 'no-record key) unread-command-events))`, but no one handles it in `cua--xxxx-keymap`. Yeah, when `(setq cua-prefix-override-inhibit-delay 0.2)`, there will be a timeout version keymap to handle

```
(define-key cua--cua-keys-keymap [(control x) timeout] #'kill-region)
(define-key cua--cua-keys-keymap [(control c) timeout] #'copy-region-as-kill)
```

but no 'no-record version when `(setq cua-prefix-override-inhibit-delay nil)`.

The following provides a workaround. 

It does `kill-region` and `copy-region-as-kill ` directly in `cua--prefix-override-keymap` when ` cua-prefix-override-inhibit-delay` is nil (or < 0).

```
(defun --sc-cua--prefix-override-ctl-x ()
  (interactive)
  (if (or (not (numberp cua-prefix-override-inhibit-delay))
          (<= cua-prefix-override-inhibit-delay 0))
      (call-interactively #'kill-region)
    (call-interactively #'cua--prefix-override-handler)))

(defun --sc-cua--prefix-override-ctl-c ()
  (interactive)
  (if (or (not (numberp cua-prefix-override-inhibit-delay))
          (<= cua-prefix-override-inhibit-delay 0))
      (call-interactively #'copy-region-as-kill)
    (call-interactively #'cua--prefix-override-handler)))

(defun --sc-cua--init-keymaps()
  (define-key cua--prefix-override-keymap [(control x)] #'--sc-cua--prefix-override-ctl-x)
  (define-key cua--prefix-override-keymap [(control c)] #'--sc-cua--prefix-override-ctl-c))

(advice-add 'cua--init-keymaps :after #'--sc-cua--init-keymaps)
```

It worked well on my end, so I'm sharing it here in case someone is interested and hoping it can be merged upstream (The `sc` defun prefix is just my naming space, so don't care about it) .

The 2nd question someone might ask: Why do we have to set `(setq cua-prefix-override-inhibit-delay nil)` and use the Shift version as prefix keys? Why not keep the default value `0.2`?

The reason is that `0.2` prevents users from quick copy/cut operations!  Let's do a simple experiment:

1. Enable cua-mode and `(setq cua-prefix-override-inhibit-delay 1)`.

2. You have two buffers, called BufferA and BufferB.

3. Go to BufferA and suppose there are two words in it, `Hello` and `World` in it.

4. Select the `Hello` and press Ctrl+C and wait 1 second.

5. Select the `World` and press Ctrl+X and quickly switch to BufferB (via mouse click tab in tab-line).

6. In BufferB, press Ctrl+V.

The expected behavior is the "World" is pasted but Emacs pastes `Hello`. Reducing the `cua-prefix-override-inhibit-delay` value (e.g. `0.01`) can partially rescue the problem, but not much if someone is operating very very fast and makes the problem hard to detect. That is why we have to set `(setq cua-prefix-override-inhibit-delay nil)`!

A possible related issue from https://lists.gnu.org/archive/html/help-gnu-emacs/2016-06/msg00468.html

The user said that

> The symptoms are that I select some text (using the shifted arrowkeys), copy it with C-c, switch to another application (typically an input form in web browser) and paste. At this point I realise that mycopy operation failed, as I get a stale clipboard value pasted.

I guess the user's issue is related to this one.

Tested in GNU Emacs 28.2 on Windows (I believe the 29.3 has the same problem because `cua-base.el` is not much different except two defalias).

Thanks.

Best regards,
Siyuan Chen

reply via email to

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