mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-21 06:55:39 +00:00
Teach Electric Pair mode about prefix arguments
* lisp/elec-pair.el (electric-pair--insert): New arg TIMES. (electric-pair-inhibit-if-helps-balance) (electric-pair-post-self-insert-function) (electric-pair-open-newline-between-pairs-psif) (electric-pair-skip-if-helps-balance): Respect prefix arg. (electric-pair-delete-pair): Delete ARG chars, not just 1. * test/lisp/electric-tests.el (autowrapping-multi-1) (autowrapping-multi-2): New tests. * doc/emacs/programs.texi (Matching): Mention prefix arg support in Electric Pair mode documentation. * etc/NEWS: Announce it. (Bug#72437)
This commit is contained in:
parent
f5bf007df1
commit
a7192fd7b7
@ -1061,7 +1061,9 @@ one, no insertion takes places, and that position is simply skipped
|
||||
over. If the region is active (@pxref{Mark}), insertion of a
|
||||
delimiter operates on the region: the characters in the region are
|
||||
enclosed in a pair of matching delimiters, leaving point after the
|
||||
delimiter you typed.
|
||||
delimiter you typed. If you provide a prefix argument when inserting
|
||||
a delimiter, the numeric value of that prefix argument specifies the
|
||||
number of pairs to insert.
|
||||
|
||||
These variables control additional features of Electric Pair mode:
|
||||
|
||||
|
6
etc/NEWS
6
etc/NEWS
@ -160,6 +160,12 @@ This option, if non-nil, makes 'delete-pair' push a mark at the end of
|
||||
the region enclosed by the deleted delimiters. This makes it easy to
|
||||
act on that region. For example, we can highlight it using 'C-x C-x'.
|
||||
|
||||
+++
|
||||
** Electric Pair mode can now pair multiple delimiters at once.
|
||||
You can now insert or wrap text with multiple sets of parentheses and
|
||||
other matching delimiters at once with Electric Pair mode, by providing
|
||||
a prefix argument when inserting one of the delimiters.
|
||||
|
||||
|
||||
* Changes in Specialized Modes and Packages in Emacs 31.1
|
||||
|
||||
|
@ -260,7 +260,7 @@ inside a comment or string."
|
||||
(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 @@ inside a comment or string."
|
||||
;; 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 @@ happened."
|
||||
(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 @@ happened."
|
||||
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 @@ The decision is taken by order of preference:
|
||||
`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,16 +550,17 @@ The decision is taken by order of preference:
|
||||
(>= (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
|
||||
@ -580,10 +586,10 @@ The decision is taken by order of preference:
|
||||
;; 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)
|
||||
@ -592,7 +598,7 @@ The decision is taken by order of preference:
|
||||
(goto-char pos)
|
||||
(funcall electric-pair-inhibit-predicate
|
||||
last-command-event)))))
|
||||
(save-excursion (electric-pair--insert pair))))))))
|
||||
(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 @@ Member of `post-self-insert-hook' if `electric-pair-mode' is on."
|
||||
(< (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 @@ Member of `post-self-insert-hook' if `electric-pair-mode' is on."
|
||||
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
|
||||
|
@ -653,6 +653,22 @@ baz\"\""
|
||||
(skip-chars-backward "\"")
|
||||
(mark-sexp -1)))
|
||||
|
||||
(define-electric-pair-test autowrapping-multi-1
|
||||
"foo" "(" :expected-string "(((((foo)))))" :expected-point 6
|
||||
:bindings '((current-prefix-arg . 5))
|
||||
:fixture-fn (lambda ()
|
||||
(electric-pair-mode 1)
|
||||
(mark-sexp 1)))
|
||||
|
||||
(define-electric-pair-test autowrapping-multi-2
|
||||
"foo" ")" :expected-string "(((((foo)))))" :expected-point 14
|
||||
:bindings '((current-prefix-arg . 5))
|
||||
:fixture-fn (lambda ()
|
||||
(electric-pair-mode 1)
|
||||
(goto-char (point-max))
|
||||
(skip-chars-backward "\"")
|
||||
(mark-sexp -1)))
|
||||
|
||||
|
||||
;;; Electric quotes
|
||||
(define-electric-pair-test electric-quote-string
|
||||
|
Loading…
Reference in New Issue
Block a user