diff --git a/etc/NEWS b/etc/NEWS index e3c5f56216f..510b38ed79e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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 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'). Typing 'M-~' while saving some buffers means not to save the buffer and diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el index 3173160370e..7c32e2521c5 100644 --- a/lisp/elec-pair.el +++ b/lisp/elec-pair.el @@ -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 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'." :version "24.1" :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 `((?\" . ?\") @@ -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 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" :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 "If non-nil, skip char instead of inserting a second closing paren. @@ -276,6 +326,22 @@ string." (direct (assq command-event fallback)) (reverse (rassq command-event fallback))) (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) '(?\" ?\( ?\) ?\$)) (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))) (skip-whitespace-info)) (pcase (electric-pair-syntax-info last-command-event) - (`(,syntax ,pair ,unconditional ,_) + (`(,syntax ,pair ,unconditional ,space) (cond ((null pos) nil) ((zerop num) nil) @@ -622,6 +688,12 @@ The decision is taken by order of preference: pos)) (forward-char num)) ;; Insert matching pair. + ;; String pairs + ((and (eq syntax 'str) (not overwrite-mode)) + (if space (insert " ")) + (save-excursion + (insert pair))) + ;; Char pairs ((and (memq syntax '(?\( ?\" ?\$)) (not overwrite-mode) (or unconditional diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el index ad7506f68ff..4468559cf38 100644 --- a/test/lisp/electric-tests.el +++ b/test/lisp/electric-tests.el @@ -549,6 +549,33 @@ baz\"\"" (electric-pair-mode 1) (electric-indent-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