summaryrefslogtreecommitdiff
path: root/lisp/elec-pair.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/elec-pair.el')
-rw-r--r--lisp/elec-pair.el94
1 files changed, 63 insertions, 31 deletions
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index b8a243b38a9..5fb9d751e25 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -155,6 +155,13 @@ return value is considered instead."
(const :tag "Newline" ?\n))
(list character)))
+(defvar-local electric-pair-skip-whitespace-function
+ #'electric-pair--skip-whitespace
+ "Function to use to skip whitespace forward.
+Before attempting a skip, if `electric-pair-skip-whitespace' is
+non-nil, this function is called. It move point to a new buffer
+position, presumably skipping only whitespace in between.")
+
(defun electric-pair--skip-whitespace ()
"Skip whitespace forward, not crossing comment or string boundaries."
(let ((saved (point))
@@ -220,7 +227,14 @@ inside a comment or string."
(defun electric-pair--insert (char)
(let ((last-command-event char)
(blink-matching-paren nil)
- (electric-pair-mode nil))
+ (electric-pair-mode nil)
+ ;; When adding the "closer" delimiter, a job his function is
+ ;; frequently used for, we don't want to munch any extra
+ ;; newlines above us. That would be the default behaviour of
+ ;; `electric-layout-mode', which potentially kicked in before
+ ;; 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)))
(cl-defmacro electric-pair--with-uncached-syntax ((table &optional start) &rest body)
@@ -232,7 +246,7 @@ functions when `parse-sexp-lookup-properties' is non-nil. The
cache is flushed from position START, defaulting to point."
(declare (debug ((form &optional form) body)) (indent 1))
(let ((start-var (make-symbol "start")))
- `(let ((syntax-propertize-function nil)
+ `(let ((syntax-propertize-function #'ignore)
(,start-var ,(or start '(point))))
(unwind-protect
(with-syntax-table ,table
@@ -398,6 +412,15 @@ strings."
(let ((ppss (electric-pair--syntax-ppss (point) '(comment))))
(memq (nth 3 ppss) (list t char))))
+(defmacro electric-pair--save-literal-point-excursion (&rest body)
+ ;; FIXME: need this instead of `save-excursion' when functions in
+ ;; BODY, such as `electric-pair-inhibit-if-helps-balance' and
+ ;; `electric-pair-skip-if-helps-balance' modify and restore the
+ ;; buffer in a way that modifies the marker used by save-excursion.
+ (let ((point (make-symbol "point")))
+ `(let ((,point (point)))
+ (unwind-protect (progn ,@body) (goto-char ,point)))))
+
(defun electric-pair-inhibit-if-helps-balance (char)
"Return non-nil if auto-pairing of CHAR would hurt parentheses' balance.
@@ -406,24 +429,28 @@ 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))
- (outermost (cdr pair-data)))
- (cond ((car outermost)
- nil)
- (t
- (eq (cdr outermost) pair)))))
- ((eq syntax ?\")
- (electric-pair--unbalanced-strings-p char))))
- (insert-char char)))))
+ (catch 'done
+ ;; FIXME: modify+undo is *very* tricky business. We used to
+ ;; use `delete-char' followed by `insert', but this changed the
+ ;; position some markers. The real fix would be to compute the
+ ;; result without having to modify the buffer at all.
+ (atomic-change-group
+ (delete-char -1)
+ (throw
+ 'done
+ (cond ((eq ?\( syntax)
+ (let* ((pair-data
+ (electric-pair--balance-info 1 s-or-c))
+ (outermost (cdr pair-data)))
+ (cond ((car outermost)
+ nil)
+ (t
+ (eq (cdr outermost) pair)))))
+ ((eq syntax ?\")
+ (electric-pair--unbalanced-strings-p char)))))))))
(defun electric-pair-skip-if-helps-balance (char)
"Return non-nil if skipping CHAR would benefit parentheses' balance.
-
Works by first removing the character from the buffer, then doing
some list calculations, finally restoring the situation as if nothing
happened."
@@ -445,7 +472,7 @@ happened."
(not (eq (cdr outermost) pair)))))))
((eq syntax ?\")
(electric-pair--inside-string-p char))))
- (insert-char char)))))
+ (insert char)))))
(defun electric-pair-default-skip-self (char)
(if electric-pair-preserve-balance
@@ -491,7 +518,9 @@ happened."
((and (memq syntax '(?\) ?\" ?\$))
(and (or unconditional
(if (functionp electric-pair-skip-self)
- (funcall electric-pair-skip-self last-command-event)
+ (electric-pair--save-literal-point-excursion
+ (goto-char pos)
+ (funcall electric-pair-skip-self last-command-event))
electric-pair-skip-self))
(save-excursion
(when (and (not (and unconditional
@@ -501,7 +530,7 @@ happened."
(functionp electric-pair-skip-whitespace))
(funcall electric-pair-skip-whitespace)
electric-pair-skip-whitespace)))
- (electric-pair--skip-whitespace))
+ (funcall electric-pair-skip-whitespace-function))
(eq (char-after) last-command-event))))
;; This is too late: rather than insert&delete we'd want to only
;; skip (or insert in overwrite mode). The difference is in what
@@ -509,17 +538,19 @@ happened."
;; be visible to other post-self-insert-hook. We'll just have to
;; live with it for now.
(when skip-whitespace-info
- (electric-pair--skip-whitespace))
+ (funcall electric-pair-skip-whitespace-function))
(delete-region (1- pos) (if (eq skip-whitespace-info 'chomp)
(point)
pos))
(forward-char))
;; Insert matching pair.
- ((and (memq syntax `(?\( ?\" ?\$))
+ ((and (memq syntax '(?\( ?\" ?\$))
(not overwrite-mode)
(or unconditional
- (not (funcall electric-pair-inhibit-predicate
- last-command-event))))
+ (not (electric-pair--save-literal-point-excursion
+ (goto-char pos)
+ (funcall electric-pair-inhibit-predicate
+ last-command-event)))))
(save-excursion (electric-pair--insert pair)))))
(_
(when (and (if (functionp electric-pair-open-newline-between-pairs)
@@ -533,8 +564,6 @@ happened."
(matching-paren (char-after))))
(save-excursion (newline 1 t)))))))
-(put 'electric-pair-post-self-insert-function 'priority 20)
-
(defun electric-pair-will-use-region ()
(and (use-region-p)
(memq (car (electric-pair-syntax-info last-command-event))
@@ -574,9 +603,6 @@ ARG and KILLP are passed directly to
;;;###autoload
(define-minor-mode electric-pair-mode
"Toggle automatic parens pairing (Electric Pair mode).
-With a prefix argument ARG, enable Electric Pair mode if ARG is
-positive, and disable it otherwise. If called from Lisp, enable
-the mode if ARG is omitted or nil.
Electric Pair mode is a global minor mode. When enabled, typing
an open parenthesis automatically inserts the corresponding
@@ -589,8 +615,14 @@ To toggle the mode in a single buffer, use `electric-pair-local-mode'."
(if electric-pair-mode
(progn
(add-hook 'post-self-insert-hook
- #'electric-pair-post-self-insert-function)
- (electric--sort-post-self-insertion-hook)
+ #'electric-pair-post-self-insert-function
+ ;; Prioritize this to kick in after
+ ;; `electric-layout-post-self-insert-function': that
+ ;; considerably simplifies interoperation when
+ ;; `electric-pair-mode', `electric-layout-mode' and
+ ;; `electric-indent-mode' are used together.
+ ;; Use `vc-region-history' on these lines for more info.
+ 50)
(add-hook 'self-insert-uses-region-functions
#'electric-pair-will-use-region))
(remove-hook 'post-self-insert-hook