1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

Support strings for electric pairs (bug#78053)

This add support for insert string pairs in 'electric-pairs-mode'.
* lisp/elec-pair.el (electric-pair-pairs)
(electric-pair-text-pairs): Add new defcustom types.
(electric-pair-syntax-info)
(electric-pair-post-self-insert-function): Add support for
strings.

* etc/NEWS: Announce changes.

* test/lisp/electric-tests.el: Add new tests.
This commit is contained in:
Elías Gabriel Pérez 2025-04-24 17:34:58 -06:00 committed by Eli Zaretskii
parent e379f14193
commit 60fbeda771
3 changed files with 113 additions and 4 deletions

View file

@ -563,6 +563,16 @@ You can now insert or wrap text with multiple sets of parentheses and
other matching delimiters at once with Electric Pair mode, by providing other matching delimiters at once with Electric Pair mode, by providing
a prefix argument when inserting one of the delimiters. a prefix argument when inserting one of the delimiters.
---
** Electric pair mode now supports multi-character paired delimiters.
'electric-pair-pairs' and 'electric-pair-text-pairs' now allows using
strings for multi-character paired delimiters.
To use this add a list to both electric pair variables: ("/*" . "*/").
You can also specify to insert an extra space after the first string
pair: ("/*" " */" t).
+++ +++
** You can now use 'M-~' during 'C-x s' ('save-some-buffers'). ** You can now use 'M-~' during 'C-x s' ('save-some-buffers').
Typing 'M-~' while saving some buffers means not to save the buffer and Typing 'M-~' while saving some buffers means not to save the buffer and

View file

@ -43,10 +43,34 @@ Pairs of delimiters in this list are a fallback in case they have
no syntax relevant to `electric-pair-mode' in the mode's syntax no syntax relevant to `electric-pair-mode' in the mode's syntax
table. table.
Each list element should be in one of these forms:
(CHAR . CHAR)
Where CHAR is character to be used as pair.
(STRING STRING SPC)
Where STRING is a string to be used as pair and SPC a non-nil value
which specifies to insert an extra space after first STRING.
(STRING . STRING)
This is similar to (STRING STRING SPC) form, except that SPC (space) is
ignored and will not be inserted.
In both string pairs forms, the first string pair must be a regular
expression.
In comparation to character pairs, string pairs does not support
inserting pairs in regions and can not be deleted with
`electric-pair-delete-pair', thus string pairs should be used only for
multi-character pairs.
See also the variable `electric-pair-text-pairs'." See also the variable `electric-pair-text-pairs'."
:version "24.1" :version "24.1"
:group 'electricity :group 'electricity
:type '(repeat (cons character character))) :type '(repeat
(choice (cons :tag "Characters" character character)
(cons :tag "Strings" string string)
(list :tag "Strings, plus insert SPC after first string"
string string boolean))))
(defcustom electric-pair-text-pairs (defcustom electric-pair-text-pairs
`((?\" . ?\") `((?\" . ?\")
@ -56,10 +80,36 @@ See also the variable `electric-pair-text-pairs'."
Pairs of delimiters in this list are a fallback in case they have Pairs of delimiters in this list are a fallback in case they have
no syntax relevant to `electric-pair-mode' in the syntax table no syntax relevant to `electric-pair-mode' in the syntax table
defined in `electric-pair-text-syntax-table'." defined in `electric-pair-text-syntax-table'.
Each list element should be in one of these forms:
(CHAR . CHAR)
Where CHAR is character to be used as pair.
(STRING STRING SPC)
Where STRING is a string to be used as pair and SPC a non-nil value
which specifies to insert an extra space after first STRING.
(STRING . STRING)
This is similar to (STRING STRING SPC) form, except that SPC (space) is
ignored and will not be inserted.
In both string pairs forms, the first string pair must be a regular
expression.
In comparation to character pairs, string pairs does not support
inserting pairs in regions and can not be deleted with
`electric-pair-delete-pair', thus string pairs should be used only for
multi-character pairs.
See also the variable `electric-pair-pairs'."
:version "24.4" :version "24.4"
:group 'electricity :group 'electricity
:type '(repeat (cons character character))) :type '(repeat
(choice (cons :tag "Characters" character character)
(cons :tag "Strings" string string)
(list :tag "Strings, plus insert SPC after first string"
string string boolean))))
(defcustom electric-pair-skip-self #'electric-pair-default-skip-self (defcustom electric-pair-skip-self #'electric-pair-default-skip-self
"If non-nil, skip char instead of inserting a second closing paren. "If non-nil, skip char instead of inserting a second closing paren.
@ -276,6 +326,22 @@ string."
(direct (assq command-event fallback)) (direct (assq command-event fallback))
(reverse (rassq command-event fallback))) (reverse (rassq command-event fallback)))
(cond (cond
((cl-loop
for pairs in fallback
if (and
(stringp (car pairs))
(looking-back (car pairs) (pos-bol)))
return (list
'str
;; Get pair ender
(if (proper-list-p pairs)
(nth 1 pairs)
(cdr pairs))
nil
;; Check if pairs have to insert a space after
;; first pair was inserted.
(if (proper-list-p pairs)
(nth 2 pairs)))))
((memq (car table-syntax-and-pair) ((memq (car table-syntax-and-pair)
'(?\" ?\( ?\) ?\$)) '(?\" ?\( ?\) ?\$))
(append table-syntax-and-pair (list nil string-or-comment))) (append table-syntax-and-pair (list nil string-or-comment)))
@ -560,7 +626,7 @@ The decision is taken by order of preference:
(beg (when num (- pos num))) (beg (when num (- pos num)))
(skip-whitespace-info)) (skip-whitespace-info))
(pcase (electric-pair-syntax-info last-command-event) (pcase (electric-pair-syntax-info last-command-event)
(`(,syntax ,pair ,unconditional ,_) (`(,syntax ,pair ,unconditional ,space)
(cond (cond
((null pos) nil) ((null pos) nil)
((zerop num) nil) ((zerop num) nil)
@ -622,6 +688,12 @@ The decision is taken by order of preference:
pos)) pos))
(forward-char num)) (forward-char num))
;; Insert matching pair. ;; Insert matching pair.
;; String pairs
((and (eq syntax 'str) (not overwrite-mode))
(if space (insert " "))
(save-excursion
(insert pair)))
;; Char pairs
((and (memq syntax '(?\( ?\" ?\$)) ((and (memq syntax '(?\( ?\" ?\$))
(not overwrite-mode) (not overwrite-mode)
(or unconditional (or unconditional

View file

@ -549,6 +549,33 @@ baz\"\""
(electric-pair-mode 1) (electric-pair-mode 1)
(electric-indent-mode 1) (electric-indent-mode 1)
(electric-layout-mode 1))) (electric-layout-mode 1)))
;;; String pairs
;;; TODO: add more tests
;;;
;; NOTE: Currently string pairs do not support insert pairs in region
;; or delete them with electric-pair-delete-pair
(ert-deftest electric-pair-strings-pairs ()
(save-electric-modes
(with-temp-buffer
(setq-local electric-pair-pairs `((,(regexp-quote "/*") . "*/")))
(electric-pair-local-mode)
(insert "/")
(let ((last-command-event ?\*))
(ert-simulate-command '(self-insert-command 1)))
(should (equal "/**/" (buffer-string))))))
(ert-deftest electric-pair-strings-pairs-with-space ()
(save-electric-modes
(with-temp-buffer
(setq-local electric-pair-pairs `((,(regexp-quote "/*") " */" t)))
(electric-pair-local-mode)
(insert "/")
(let ((last-command-event ?\*))
(ert-simulate-command '(self-insert-command 1)))
(should (equal "/* */" (buffer-string))))))
;;; Backspacing ;;; Backspacing