1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-28 07:45:00 +00:00

elec-pair: Fix bug incorrectly hiding syntax-propertize-function

* lisp/elec-pair.el (electric-pair--with-text-syntax): New macro.
(electric-pair-syntax-info):
(electric-pair--balance-info):
(electric-pair--syntax-ppss, electric-pair--balance-info): Use it.
(electric-pair--with-uncached-syntax): Remove (bug#49629).

The main bug that this is fixing is `syntax-propertize-function' being
hidden in `electric-pair--balance-info' when the original syntax table
is to be used, not `electric-pair-text-syntax-table'.

Notably, this causes `electric-pair-mode' to often misbehave in HTML
files when pairing angle brackets.

This commit also flushes the cache before installing
`electric-pair-text-syntax-table', to prevent cached syntax for the
original table from affecting things.
This commit is contained in:
Allen Li 2022-07-03 12:31:15 +02:00 committed by Lars Ingebrigtsen
parent f5a11369ea
commit a2f956a1d6

View File

@ -188,6 +188,25 @@ be considered.")
;; I also find it often preferable not to pair next to a word. ;; I also find it often preferable not to pair next to a word.
(eq (char-syntax (following-char)) ?w))) (eq (char-syntax (following-char)) ?w)))
(cl-defmacro electric-pair--with-text-syntax ((&optional start) &rest body)
"Run BODY with `electric-pair-text-syntax-table' active.
This ensures that all syntax related values are set properly and the
`syntax-ppss' cache is cleared before and after.
In particular, this must be used when BODY contains code which may
update the `syntax-ppss' cache. This includes calling
`parse-partial-sexp' and any sexp-based movement functions when
`parse-sexp-lookup-properties' is non-nil. The cache is flushed from
position START, defaulting to point."
(declare (debug ((&optional form) body)) (indent 1))
(let ((start-var (make-symbol "start")))
`(let ((syntax-propertize-function nil)
(,start-var ,(or start '(point))))
(syntax-ppss-flush-cache ,start-var)
(unwind-protect
(with-syntax-table electric-pair-text-syntax-table
,@body)
(syntax-ppss-flush-cache ,start-var)))))
(defun electric-pair-syntax-info (command-event) (defun electric-pair-syntax-info (command-event)
"Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START). "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START).
@ -202,13 +221,14 @@ inside a comment or string."
(post-string-or-comment (nth 8 (syntax-ppss (point)))) (post-string-or-comment (nth 8 (syntax-ppss (point))))
(string-or-comment (and post-string-or-comment (string-or-comment (and post-string-or-comment
pre-string-or-comment)) pre-string-or-comment))
(table (if string-or-comment (table-syntax-and-pair
electric-pair-text-syntax-table (cl-flet ((f ()
(syntax-table))) (list (char-syntax command-event)
(table-syntax-and-pair (with-syntax-table table (or (matching-paren command-event)
(list (char-syntax command-event) command-event))))
(or (matching-paren command-event) (if string-or-comment
command-event)))) (electric-pair--with-text-syntax () (f))
(f))))
(fallback (if string-or-comment (fallback (if string-or-comment
(append electric-pair-text-pairs (append electric-pair-text-pairs
electric-pair-pairs) electric-pair-pairs)
@ -237,22 +257,6 @@ inside a comment or string."
(electric-layout-allow-duplicate-newlines t)) (electric-layout-allow-duplicate-newlines t))
(self-insert-command 1))) (self-insert-command 1)))
(cl-defmacro electric-pair--with-uncached-syntax ((table &optional start) &rest body)
"Like `with-syntax-table', but flush the `syntax-ppss' cache afterwards.
Use this instead of (with-syntax-table TABLE BODY) when BODY
contains code which may update the `syntax-ppss' cache. This
includes calling `parse-partial-sexp' and any sexp-based movement
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 #'ignore)
(,start-var ,(or start '(point))))
(unwind-protect
(with-syntax-table ,table
,@body)
(syntax-ppss-flush-cache ,start-var)))))
(defun electric-pair--syntax-ppss (&optional pos where) (defun electric-pair--syntax-ppss (&optional pos where)
"Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'. "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
@ -271,8 +275,7 @@ when to fallback to `parse-partial-sexp'."
(skip-syntax-forward " >!") (skip-syntax-forward " >!")
(point))))) (point)))))
(if s-or-c-start (if s-or-c-start
(electric-pair--with-uncached-syntax (electric-pair-text-syntax-table (electric-pair--with-text-syntax (s-or-c-start)
s-or-c-start)
(parse-partial-sexp s-or-c-start pos)) (parse-partial-sexp s-or-c-start pos))
;; HACK! cc-mode apparently has some `syntax-ppss' bugs ;; HACK! cc-mode apparently has some `syntax-ppss' bugs
(if (memq major-mode '(c-mode c++ mode)) (if (memq major-mode '(c-mode c++ mode))
@ -301,9 +304,6 @@ If the outermost list is matched, don't rely on its PAIR.
If point is not enclosed by any lists, return ((t) . (t))." If point is not enclosed by any lists, return ((t) . (t))."
(let* (innermost (let* (innermost
outermost outermost
(table (if string-or-comment
electric-pair-text-syntax-table
(syntax-table)))
(at-top-level-or-equivalent-fn (at-top-level-or-equivalent-fn
;; called when `scan-sexps' ran perfectly, when it found ;; called when `scan-sexps' ran perfectly, when it found
;; a parenthesis pointing in the direction of travel. ;; a parenthesis pointing in the direction of travel.
@ -325,11 +325,14 @@ If point is not enclosed by any lists, return ((t) . (t))."
(cond ((< direction 0) (cond ((< direction 0)
(condition-case nil (condition-case nil
(eq (char-after pos) (eq (char-after pos)
(electric-pair--with-uncached-syntax (cl-flet ((f ()
(table) (matching-paren
(matching-paren (char-before
(char-before (scan-sexps (point) 1)))))
(scan-sexps (point) 1))))) (if string-or-comment
(electric-pair--with-text-syntax ()
(f))
(f))))
(scan-error nil))) (scan-error nil)))
(t (t
;; In this case, no need to use ;; In this case, no need to use
@ -343,7 +346,9 @@ If point is not enclosed by any lists, return ((t) . (t))."
(opener (char-after start))) (opener (char-after start)))
(and start (and start
(eq (char-before pos) (eq (char-before pos)
(or (with-syntax-table table (or (if string-or-comment
(electric-pair--with-text-syntax ()
(matching-paren opener))
(matching-paren opener)) (matching-paren opener))
opener)))))))) opener))))))))
(actual-pair (if (> direction 0) (actual-pair (if (> direction 0)
@ -356,11 +361,14 @@ If point is not enclosed by any lists, return ((t) . (t))."
(save-excursion (save-excursion
(while (not outermost) (while (not outermost)
(condition-case err (condition-case err
(electric-pair--with-uncached-syntax (table) (cl-flet ((f ()
(scan-sexps (point) (if (> direction 0) (scan-sexps (point) (if (> direction 0)
(point-max) (point-max)
(- (point-max)))) (- (point-max))))
(funcall at-top-level-or-equivalent-fn)) (funcall at-top-level-or-equivalent-fn)))
(if string-or-comment
(electric-pair--with-text-syntax () (f))
(f)))
(scan-error (scan-error
(cond ((or (cond ((or
;; some error happened and it is not of the "ended ;; some error happened and it is not of the "ended