bug#50236: 27.2; electric-pair-mode is inconvenient in comint

João Távora <[email protected]>
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
João Távora <[email protected]> writes:

> On Mon, Aug 17, 2026, 11:56 Eli Zaretskii <[email protected]> wrote:

>  If not, I'm not sure it is wise to
>  install on the emacs-31 branchrvof so close to the release.  Sean, WDYT?
>
> Should be reasonably safe, is my judgement. It's very elegant and
> small. Also I made it a noop in anything but comint.el modes.

Actualy, the patch had a tiny bug.  Should be setting the controlling
variable with setq-local, not setq, so that it is truly isolated to
comint.el-based modes.  Attaching correct version:


João
0001-Make-electric-pair-mode-respect-field-boundaries-bug.patch (text/x-patch, 5.7 KB)
From 6a5a503de77bddb215746a688daae984bf834e16 Mon Sep 17 00:00:00 2001
From: Andrew Hyatt <[email protected]>
Date: Sun, 16 Aug 2026 12:31:55 +0100
Subject: [PATCH] Make electric-pair-mode respect field boundaries (bug#50236)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Among other potential benefits, this makes e-p-m work correctly in all
comint-based modes.

* lisp/elec-pair.el (electric-pair-field-search-size): New variable.
(electric-pair-post-self-insert-function): Tweak.
(electric--pair-psif-1)

* etc/NEWS: Call out change.

* lisp/comint.el (electric-pair-field-search-size): forward-declare.
(comint-mode): Set electric-pair-field-search-size to 1000.

* test/lisp/electric-tests.el (preserve-balance)
(preserve-balance-not-across-fields): New tests.

Co-authored-by: João Távora <[email protected]>
---
 etc/NEWS                    |  7 +++++++
 lisp/comint.el              |  5 ++++-
 lisp/elec-pair.el           | 24 +++++++++++++++++++++++-
 test/lisp/electric-tests.el | 26 +++++++++++++++++++++++++-
 4 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 5f5f59d2a9f..fe662e4421d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -972,6 +972,13 @@ To use this, add a list to both electric pair user options: '("/*" . "*/")'.
 You can also specify that an extra space should be inserted after the
 first string, like this: '("/*" " */" t)'.
 
+*** Electric pair mode can restrict operation to nearby fields
+This is particularly useful in comint-based modes (like Eshell) and
+other situations where process output may contain unpaired delimiters,
+while keeping delimiters you insert balanced. The
+''electric-pair-field-search-size'' variable controls the search
+distance for nearby fields.
+
 ---
 ** New user option 'electric-indent-actions'.
 This user option specifies a list of actions to reindent.  The possible
diff --git a/lisp/comint.el b/lisp/comint.el
index e5418f4ee67..a78002ab6b8 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -702,6 +702,8 @@ comint-stored-incomplete-input
 
 (put 'comint-mode 'mode-class 'special)
 
+(defvar electric-pair-field-search-size)
+
 (define-derived-mode comint-mode fundamental-mode "Comint"
   "Major mode for interacting with an inferior interpreter.
 Interpreter name is same as buffer name, sans the asterisks.
@@ -792,7 +794,8 @@ comint-mode
   (add-hook 'isearch-mode-hook #'comint-history-isearch-setup nil t)
   (add-hook 'completion-at-point-functions #'comint-completion-at-point nil t)
   ;; This behavior is not useful in comint buffers, and is annoying
-  (setq-local next-line-add-newlines nil))
+  (setq-local next-line-add-newlines nil)
+  (setq-local electric-pair-field-search-size 1000))
 
 (defun comint-check-proc (buffer)
   "Return non-nil if there is a living process associated w/buffer BUFFER.
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index 54fbc960b0f..d7ae555e408 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -596,10 +596,32 @@ electric-pair-default-inhibit
       (electric-pair-inhibit-if-helps-balance char)
     (electric-pair-conservative-inhibit char)))
 
+(defvar electric-pair-field-search-size nil
+  "How far to look for nearby fields to restrict `electric-pair-mode'.
+
+If nil, do not look for nearby fields and use the accessible portion of
+the buffer.  If a integer number of characters, look at most that far
+backward and forward for a field boundary.  If one isn't found, use the
+accessible portion of the buffer in that direction.")
+
 (defun electric-pair-post-self-insert-function ()
   "Do main work for `electric-pair-mode'.
 This function is added to `post-self-insert-hook' when
-`electric-pair-mode' is enabled.
+`electric-pair-mode' is enabled."
+  ;; First, figure out whether to restrit the buffer (bug#50236)
+  (if (or (null electric-pair-field-search-size)
+          (use-region-p))
+      (electric--pair-psif-1)
+    (let* ((min (- (point) electric-pair-field-search-size))
+           (max (+ (point) electric-pair-field-search-size))
+           (beg (field-beginning nil nil (max (point-min) min)))
+           (end (field-end nil nil (min (point-max) max))))
+      (with-restriction
+          (if (= min beg) (point-min) beg) (if (= max end) (point-max) end)
+        (electric--pair-psif-1)))))
+
+(defun electric--pair-psif-1 ()
+  "Do main work for `electric-pair-post-self-insert-function.'
 
 If the newly inserted character C has delimiter syntax, this
 function may decide to insert additional paired delimiters, or
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index 9209e1739fd..d678279c8cc 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -703,7 +703,31 @@ autowrapping-multi-2
                 (goto-char (point-max))
                 (skip-chars-backward "\"")
                 (mark-sexp -1)))
-
+
+(define-electric-pair-test preserve-balance
+ "\"\n\n" "---\""
+ :expected-string "\"\n\n\""
+ :expected-point 5
+ :modes '(fundamental-mode)
+ :test-in-comments nil
+ :test-in-strings nil
+ :bindings '((electric-pair-preserve-balance . t))
+ :fixture-fn (lambda ()
+               (electric-pair-mode 1)))
+
+(define-electric-pair-test preserve-balance-not-across-fields
+ "\"\n\n" "---\""
+ :expected-string "\"\n\n\"\""
+ :expected-point 5
+ :modes '(fundamental-mode)
+ :test-in-comments nil
+ :test-in-strings nil
+ :bindings '((electric-pair-preserve-balance . t)
+             (electric-pair-field-search-size . 100))
+ :fixture-fn (lambda ()
+               (electric-pair-mode 1)
+               (add-text-properties (point-min) (+ (point-min) 2)
+                                    '(field t))))
 
 ;;; Electric quotes
 (define-electric-pair-test electric-quote-string
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.