unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Stephen Berman via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Arash Esbati <arash@gnu.org>
Cc: 71337@debbugs.gnu.org
Subject: bug#71337: 30.0.50; `electric-pair-mode' and custom keybinding
Date: Mon, 03 Jun 2024 15:50:55 +0200	[thread overview]
Message-ID: <87frtu9lts.fsf@gmx.net> (raw)
In-Reply-To: <m25xuqurlc.fsf@macmutant.fritz.box> (Arash Esbati's message of "Mon, 03 Jun 2024 14:40:47 +0200")

[-- Attachment #1: Type: text/plain, Size: 1655 bytes --]

On Mon, 03 Jun 2024 14:40:47 +0200 Arash Esbati <arash@gnu.org> wrote:

> Hi all,
>
> I have a custom keybinding "s-ß" with my German keyboard, but the issue
> I'm facing is also reproducible like this:
>
> • emacs -Q
> • In scratch, eval:
>
>   (progn
>     (setq debug-on-error t)
>     (electric-pair-mode  1)
>     (keymap-global-set "s-#" (lambda (arg)
>                                "Insert ARG backslash(es)."
>                                (interactive "*p")
>                                (self-insert-command arg ?\\))))
>
> • Now hit "s-#" and the debugger says (linebreaks added manually):
>
> Debugger entered--Lisp error: (wrong-type-argument characterp 8388643)
>   #f(compiled-function () #<bytecode -0x15954a2c5d74b890>)()
>   electric-pair--with-syntax-1(nil #f(compiled-function () #<bytecode -0x15954a2c5d74b890>))
>   electric-pair-syntax-info(8388643)
>   electric-pair-post-self-insert-function()
>   self-insert-command(1 92)
>   #f(lambda (arg) [t] "Insert ARG backslash(es)." (interactive "*p")
>    (self-insert-command arg 92))(1)
>   funcall-interactively(#f(lambda (arg) [t] "Insert ARG backslash(es)."
>    (interactive "*p") (self-insert-command arg 92)) 1)
>   command-execute(#f(lambda (arg) [t] "Insert ARG backslash(es)."
>    (interactive "*p") (self-insert-command arg 92)))
>
> Running the exercise with (electric-pair-mode -1) doesn't throw an
> error.

If the pairing in electric-pair-mode should only be triggered by
self-inserting characters (as the current code seems to require), then
the attached patch appears to avoid the above problem.

Steve Berman


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: electric-pair-post-self-insert-function patch --]
[-- Type: text/x-patch, Size: 7441 bytes --]

diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index 40618e9ef38..1b5b6d401a9 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -528,71 +528,72 @@ electric-pair-post-self-insert-function
   and `electric-pair-skip-whitespace' (which see)."
   (let* ((pos (and electric-pair-mode (electric--after-char-pos)))
          (skip-whitespace-info))
-    (pcase (electric-pair-syntax-info last-command-event)
-      (`(,syntax ,pair ,unconditional ,_)
-       (cond
-        ((null pos) nil)
-        ;; Wrap a pair around the active region.
-        ;;
-        ((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
-         ;; FIXME: To do this right, we'd need a post-self-insert-function
-         ;; so we could add-function around it and insert the closer after
-         ;; all the rest of the hook has run.
-         (if (or (eq syntax ?\")
-                 (and (eq syntax ?\))
-                      (>= (point) (mark)))
-                 (and (not (eq syntax ?\)))
-                      (>= (mark) (point))))
-             (save-excursion
-               (goto-char (mark))
-               (electric-pair--insert pair))
-           (delete-region pos (1- pos))
-           (electric-pair--insert pair)
-           (goto-char (mark))
-           (electric-pair--insert last-command-event)))
-        ;; Backslash-escaped: no pairing, no skipping.
-        ((save-excursion
-           (goto-char (1- pos))
-           (not (zerop (% (skip-syntax-backward "\\") 2))))
-         nil)
-        ;; Skip self.
-        ((and (memq syntax '(?\) ?\" ?\$))
-              (and (or unconditional
-                       (if (functionp electric-pair-skip-self)
-                           (electric-pair--save-literal-point-excursion
-                             (goto-char pos)
-                             (funcall electric-pair-skip-self last-command-event))
-                         electric-pair-skip-self))
-                   (save-excursion
-                     (when (and (not (and unconditional
-                                          (eq syntax ?\")))
-                                (setq skip-whitespace-info
-                                      (if (and (not (eq electric-pair-skip-whitespace 'chomp))
-                                               (functionp electric-pair-skip-whitespace))
-                                          (funcall electric-pair-skip-whitespace)
-                                        electric-pair-skip-whitespace)))
-                       (funcall electric-pair-skip-whitespace-function))
-                     (eq (char-after) last-command-event))))
-         ;; This is too late: rather than insert&delete we'd want to only
-         ;; skip (or insert in overwrite mode).  The difference is in what
-         ;; goes in the undo-log and in the intermediate state which might
-         ;; be visible to other post-self-insert-hook.  We'll just have to
-         ;; live with it for now.
-         (when skip-whitespace-info
-           (funcall electric-pair-skip-whitespace-function))
-         (delete-region (1- pos) (if (eq skip-whitespace-info 'chomp)
-                                     (point)
-                                   pos))
-         (forward-char))
-        ;; Insert matching pair.
-        ((and (memq syntax '(?\( ?\" ?\$))
-              (not overwrite-mode)
-              (or unconditional
-                  (not (electric-pair--save-literal-point-excursion
-                         (goto-char pos)
-                         (funcall electric-pair-inhibit-predicate
-                                  last-command-event)))))
-         (save-excursion (electric-pair--insert pair))))))))
+    (when (characterp last-command-event)
+      (pcase (electric-pair-syntax-info last-command-event)
+        (`(,syntax ,pair ,unconditional ,_)
+         (cond
+          ((null pos) nil)
+          ;; Wrap a pair around the active region.
+          ;;
+          ((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
+           ;; FIXME: To do this right, we'd need a post-self-insert-function
+           ;; so we could add-function around it and insert the closer after
+           ;; all the rest of the hook has run.
+           (if (or (eq syntax ?\")
+                   (and (eq syntax ?\))
+                        (>= (point) (mark)))
+                   (and (not (eq syntax ?\)))
+                        (>= (mark) (point))))
+               (save-excursion
+                 (goto-char (mark))
+                 (electric-pair--insert pair))
+             (delete-region pos (1- pos))
+             (electric-pair--insert pair)
+             (goto-char (mark))
+             (electric-pair--insert last-command-event)))
+          ;; Backslash-escaped: no pairing, no skipping.
+          ((save-excursion
+             (goto-char (1- pos))
+             (not (zerop (% (skip-syntax-backward "\\") 2))))
+           nil)
+          ;; Skip self.
+          ((and (memq syntax '(?\) ?\" ?\$))
+                (and (or unconditional
+                         (if (functionp electric-pair-skip-self)
+                             (electric-pair--save-literal-point-excursion
+                              (goto-char pos)
+                              (funcall electric-pair-skip-self last-command-event))
+                           electric-pair-skip-self))
+                     (save-excursion
+                       (when (and (not (and unconditional
+                                            (eq syntax ?\")))
+                                  (setq skip-whitespace-info
+                                        (if (and (not (eq electric-pair-skip-whitespace 'chomp))
+                                                 (functionp electric-pair-skip-whitespace))
+                                            (funcall electric-pair-skip-whitespace)
+                                          electric-pair-skip-whitespace)))
+                         (funcall electric-pair-skip-whitespace-function))
+                       (eq (char-after) last-command-event))))
+           ;; This is too late: rather than insert&delete we'd want to only
+           ;; skip (or insert in overwrite mode).  The difference is in what
+           ;; goes in the undo-log and in the intermediate state which might
+           ;; be visible to other post-self-insert-hook.  We'll just have to
+           ;; live with it for now.
+           (when skip-whitespace-info
+             (funcall electric-pair-skip-whitespace-function))
+           (delete-region (1- pos) (if (eq skip-whitespace-info 'chomp)
+                                       (point)
+                                     pos))
+           (forward-char))
+          ;; Insert matching pair.
+          ((and (memq syntax '(?\( ?\" ?\$))
+                (not overwrite-mode)
+                (or unconditional
+                    (not (electric-pair--save-literal-point-excursion
+                          (goto-char pos)
+                          (funcall electric-pair-inhibit-predicate
+                                   last-command-event)))))
+           (save-excursion (electric-pair--insert pair)))))))))

 (defun electric-pair-open-newline-between-pairs-psif ()
   "Honor `electric-pair-open-newline-between-pairs'.

  reply	other threads:[~2024-06-03 13:50 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-03 12:40 bug#71337: 30.0.50; `electric-pair-mode' and custom keybinding Arash Esbati
2024-06-03 13:50 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2024-06-04  5:53   ` Arash Esbati
2024-06-04  7:30     ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-04  7:37       ` João Távora
2024-06-04  8:08         ` João Távora
2024-06-04  8:18           ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-04 14:52             ` Eli Zaretskii
2024-06-04  9:24           ` Eli Zaretskii
2024-06-04 10:09             ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-04 10:49               ` João Távora
2024-06-04 11:04               ` Eli Zaretskii
2024-06-04 14:56               ` Eli Zaretskii
2024-06-04 15:43                 ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-04 12:33             ` Arash Esbati
2024-06-04 13:36               ` João Távora
2024-06-04 14:09                 ` Arash Esbati
2024-06-04 14:21             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-06-15  8:10               ` Eli Zaretskii
2024-06-16 10:42                 ` Arash Esbati
2024-06-04  8:09         ` Stephen Berman via Bug reports for GNU Emacs, the Swiss army knife of text editors

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87frtu9lts.fsf@gmx.net \
    --to=bug-gnu-emacs@gnu.org \
    --cc=71337@debbugs.gnu.org \
    --cc=arash@gnu.org \
    --cc=stephen.berman@gmx.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).