From: Eshel Yaron via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 72437@debbugs.gnu.org, Stefan Monnier <monnier@iro.umontreal.ca>,
Joseph Turner <joseph@breatheoutbreathe.in>
Subject: bug#72437: Unexpected behavior when inserting with prefix arg in electric-pair-mode
Date: Sat, 03 Aug 2024 13:04:58 +0200 [thread overview]
Message-ID: <m1frrlhnol.fsf@dazzs-mbp.home> (raw)
In-Reply-To: <86h6c2ug0p.fsf@gnu.org> (Eli Zaretskii's message of "Sat, 03 Aug 2024 12:12:06 +0300")
Eli Zaretskii <eliz@gnu.org> writes:
>> Cc: eliz@gnu.org
>> From: Joseph Turner <joseph@breatheoutbreathe.in>
>> Date: Sat, 03 Aug 2024 00:12:33 -0700
>>
>> Migrated from this thread on the devel mailing list:
>>
>> https://yhetil.org/emacs-devel/86ikwiumza.fsf@gnu.org/T/#t
>>
>>
>> On Emacs 29.4, with emacs -Q
>>
>> Turn on electric-pair-mode
>>
>> (electric-pair-mode +1)
>>
>> Then press "C-2 ("
>>
>> Expected result:
>>
>> Either (()) or ()()
>>
>> Actual result:
>>
>> (()
>>
>>
>> I noticed the unexpected behavior when attempting to surround some text
>> with multiple braces in order to create Anki flashcards.
>>
>> More or less, I wanted to go from "foo" to "{{foo}}", and I thought
>> perhaps that with the whole word selected, pressing "C-2 {" would DTRT.
>>
>> In general, I'm not sure whether "{}{}" or "{{}}"is more useful or
>> expected, but I suspect both are better than "{{}".
>
> Making it produce "{}{}" is relatively easy: we just need to call the
> post-self-insert-hook for each of the ARG inserted characters. OTOH,
> to produce "{{}}" we'd probably need to rewrite the
> electric-pair-mode's hook function, but I have no idea how to rewrite
> it to do that.
>
> Stefan, any suggestions?
I'm no Stefan, but I took a quick stab at it. The following diff
teaches electric-pair-mode about numeric prefix arguments:
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index 40618e9ef38..1fae0ba6ba4 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -260,7 +260,7 @@ electric-pair-syntax-info
(list ?\( (cdr direct) t string-or-comment)))
(reverse (list ?\) (car reverse) t string-or-comment)))))
-(defun electric-pair--insert (char)
+(defun electric-pair--insert (char times)
(let ((last-command-event char)
(blink-matching-paren nil)
(electric-pair-mode nil)
@@ -271,7 +271,7 @@ electric-pair--insert
;; us to add these newlines, and is probably about to kick in
;; again after we add the closer.
(electric-layout-allow-duplicate-newlines t))
- (self-insert-command 1)))
+ (self-insert-command times)))
(defun electric-pair--syntax-ppss (&optional pos where)
"Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
@@ -455,7 +455,8 @@ electric-pair-inhibit-if-helps-balance
(atomic-change-group
;; Don't use `delete-char'; that may modify the head of the
;; undo list.
- (delete-region (point) (1- (point)))
+ (delete-region (- (point) (prefix-numeric-value current-prefix-arg))
+ (point))
(throw
'done
(cond ((eq ?\( syntax)
@@ -474,25 +475,26 @@ electric-pair-skip-if-helps-balance
Works by first removing the character from the buffer, then doing
some list calculations, finally restoring the situation as if nothing
happened."
- (pcase (electric-pair-syntax-info char)
- (`(,syntax ,pair ,_ ,s-or-c)
- (unwind-protect
- (progn
- (delete-char -1)
- (cond ((eq syntax ?\))
- (let* ((pair-data
- (electric-pair--balance-info
- -1 s-or-c))
- (innermost (car pair-data))
- (outermost (cdr pair-data)))
- (and
- (cond ((car outermost)
- (car innermost))
- ((car innermost)
- (not (eq (cdr outermost) pair)))))))
- ((eq syntax ?\")
- (electric-pair--inside-string-p char))))
- (insert char)))))
+ (let ((num (prefix-numeric-value current-prefix-arg)))
+ (pcase (electric-pair-syntax-info char)
+ (`(,syntax ,pair ,_ ,s-or-c)
+ (unwind-protect
+ (progn
+ (delete-char (- num))
+ (cond ((eq syntax ?\))
+ (let* ((pair-data
+ (electric-pair--balance-info
+ (- num) s-or-c))
+ (innermost (car pair-data))
+ (outermost (cdr pair-data)))
+ (and
+ (cond ((car outermost)
+ (car innermost))
+ ((car innermost)
+ (not (eq (cdr outermost) pair)))))))
+ ((eq syntax ?\")
+ (electric-pair--inside-string-p char))))
+ (insert (make-string num char)))))))
(defun electric-pair-default-skip-self (char)
(if electric-pair-preserve-balance
@@ -527,11 +529,14 @@ electric-pair-post-self-insert-function
`electric-pair-inhibit-predicate', `electric-pair-skip-self'
and `electric-pair-skip-whitespace' (which see)."
(let* ((pos (and electric-pair-mode (electric--after-char-pos)))
+ (num (when pos (prefix-numeric-value current-prefix-arg)))
+ (beg (when num (- pos num)))
(skip-whitespace-info))
(pcase (electric-pair-syntax-info last-command-event)
(`(,syntax ,pair ,unconditional ,_)
(cond
((null pos) nil)
+ ((zerop num) nil)
;; Wrap a pair around the active region.
;;
((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
@@ -545,23 +550,24 @@ electric-pair-post-self-insert-function
(>= (mark) (point))))
(save-excursion
(goto-char (mark))
- (electric-pair--insert pair))
- (delete-region pos (1- pos))
- (electric-pair--insert pair)
+ (electric-pair--insert pair num))
+ (delete-region beg pos)
+ (electric-pair--insert pair num)
(goto-char (mark))
- (electric-pair--insert last-command-event)))
+ (electric-pair--insert last-command-event num)))
;; Backslash-escaped: no pairing, no skipping.
((save-excursion
- (goto-char (1- pos))
+ (goto-char beg)
(not (zerop (% (skip-syntax-backward "\\") 2))))
- nil)
+ (let ((current-prefix-arg (1- num)))
+ (electric-pair-post-self-insert-function)))
;; 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))
+ (goto-char pos)
+ (funcall electric-pair-skip-self last-command-event))
electric-pair-skip-self))
(save-excursion
(when (and (not (and unconditional
@@ -580,19 +586,19 @@ electric-pair-post-self-insert-function
;; 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))
+ (delete-region beg (if (eq skip-whitespace-info 'chomp)
+ (point)
+ pos))
+ (forward-char num))
;; 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))))))))
+ (goto-char pos)
+ (funcall electric-pair-inhibit-predicate
+ last-command-event)))))
+ (save-excursion (electric-pair--insert pair num))))))))
(defun electric-pair-open-newline-between-pairs-psif ()
"Honor `electric-pair-open-newline-between-pairs'.
@@ -604,7 +610,8 @@ electric-pair-open-newline-between-pairs-psif
(< (1+ (point-min)) (point) (point-max))
(eq (save-excursion
(skip-chars-backward "\t\s")
- (char-before (1- (point))))
+ (char-before (- (point)
+ (prefix-numeric-value current-prefix-arg))))
(matching-paren (char-after))))
(save-excursion (newline 1 t))))
@@ -618,7 +625,7 @@ electric-pair-delete-pair
ARG and KILLP are passed directly to
`backward-delete-char-untabify', which see."
(interactive "*p\nP")
- (delete-char 1)
+ (delete-char arg)
(backward-delete-char-untabify arg killp))
(defvar electric-pair-mode-map
next prev parent reply other threads:[~2024-08-03 11:04 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-03 7:12 bug#72437: Unexpected behavior when inserting with prefix arg in electric-pair-mode Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-03 9:12 ` Eli Zaretskii
2024-08-03 11:04 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2024-08-03 15:40 ` Eli Zaretskii
2024-08-03 18:18 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-03 18:46 ` Eli Zaretskii
2024-08-14 1:00 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-14 5:07 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-14 11:39 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-17 6:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-09-19 5:14 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-09-21 10:23 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-09-21 17:24 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-09-22 8:21 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-09-22 19:32 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-14 0:57 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-16 21:22 ` João Távora
2024-08-17 6:08 ` Eli Zaretskii
2024-08-17 9:30 ` João Távora
2024-08-17 14:03 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-17 14:21 ` Eli Zaretskii
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
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=m1frrlhnol.fsf@dazzs-mbp.home \
--to=bug-gnu-emacs@gnu.org \
--cc=72437@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=joseph@breatheoutbreathe.in \
--cc=me@eshelyaron.com \
--cc=monnier@iro.umontreal.ca \
/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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.