aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/elec-pair.el86
1 files changed, 47 insertions, 39 deletions
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index 720f6083681..247e9b93ec2 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -188,6 +188,25 @@ be considered.")
188 ;; I also find it often preferable not to pair next to a word. 188 ;; I also find it often preferable not to pair next to a word.
189 (eq (char-syntax (following-char)) ?w))) 189 (eq (char-syntax (following-char)) ?w)))
190 190
191(cl-defmacro electric-pair--with-text-syntax ((&optional start) &rest body)
192 "Run BODY with `electric-pair-text-syntax-table' active.
193This ensures that all syntax related values are set properly and the
194`syntax-ppss' cache is cleared before and after.
195In particular, this must be used when BODY contains code which may
196update the `syntax-ppss' cache. This includes calling
197`parse-partial-sexp' and any sexp-based movement functions when
198`parse-sexp-lookup-properties' is non-nil. The cache is flushed from
199position START, defaulting to point."
200 (declare (debug ((&optional form) body)) (indent 1))
201 (let ((start-var (make-symbol "start")))
202 `(let ((syntax-propertize-function nil)
203 (,start-var ,(or start '(point))))
204 (syntax-ppss-flush-cache ,start-var)
205 (unwind-protect
206 (with-syntax-table electric-pair-text-syntax-table
207 ,@body)
208 (syntax-ppss-flush-cache ,start-var)))))
209
191(defun electric-pair-syntax-info (command-event) 210(defun electric-pair-syntax-info (command-event)
192 "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START). 211 "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START).
193 212
@@ -202,13 +221,14 @@ inside a comment or string."
202 (post-string-or-comment (nth 8 (syntax-ppss (point)))) 221 (post-string-or-comment (nth 8 (syntax-ppss (point))))
203 (string-or-comment (and post-string-or-comment 222 (string-or-comment (and post-string-or-comment
204 pre-string-or-comment)) 223 pre-string-or-comment))
205 (table (if string-or-comment 224 (table-syntax-and-pair
206 electric-pair-text-syntax-table 225 (cl-flet ((f ()
207 (syntax-table))) 226 (list (char-syntax command-event)
208 (table-syntax-and-pair (with-syntax-table table 227 (or (matching-paren command-event)
209 (list (char-syntax command-event) 228 command-event))))
210 (or (matching-paren command-event) 229 (if string-or-comment
211 command-event)))) 230 (electric-pair--with-text-syntax () (f))
231 (f))))
212 (fallback (if string-or-comment 232 (fallback (if string-or-comment
213 (append electric-pair-text-pairs 233 (append electric-pair-text-pairs
214 electric-pair-pairs) 234 electric-pair-pairs)
@@ -237,22 +257,6 @@ inside a comment or string."
237 (electric-layout-allow-duplicate-newlines t)) 257 (electric-layout-allow-duplicate-newlines t))
238 (self-insert-command 1))) 258 (self-insert-command 1)))
239 259
240(cl-defmacro electric-pair--with-uncached-syntax ((table &optional start) &rest body)
241 "Like `with-syntax-table', but flush the `syntax-ppss' cache afterwards.
242Use this instead of (with-syntax-table TABLE BODY) when BODY
243contains code which may update the `syntax-ppss' cache. This
244includes calling `parse-partial-sexp' and any sexp-based movement
245functions when `parse-sexp-lookup-properties' is non-nil. The
246cache is flushed from position START, defaulting to point."
247 (declare (debug ((form &optional form) body)) (indent 1))
248 (let ((start-var (make-symbol "start")))
249 `(let ((syntax-propertize-function #'ignore)
250 (,start-var ,(or start '(point))))
251 (unwind-protect
252 (with-syntax-table ,table
253 ,@body)
254 (syntax-ppss-flush-cache ,start-var)))))
255
256(defun electric-pair--syntax-ppss (&optional pos where) 260(defun electric-pair--syntax-ppss (&optional pos where)
257 "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'. 261 "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
258 262
@@ -271,8 +275,7 @@ when to fallback to `parse-partial-sexp'."
271 (skip-syntax-forward " >!") 275 (skip-syntax-forward " >!")
272 (point))))) 276 (point)))))
273 (if s-or-c-start 277 (if s-or-c-start
274 (electric-pair--with-uncached-syntax (electric-pair-text-syntax-table 278 (electric-pair--with-text-syntax (s-or-c-start)
275 s-or-c-start)
276 (parse-partial-sexp s-or-c-start pos)) 279 (parse-partial-sexp s-or-c-start pos))
277 ;; HACK! cc-mode apparently has some `syntax-ppss' bugs 280 ;; HACK! cc-mode apparently has some `syntax-ppss' bugs
278 (if (memq major-mode '(c-mode c++ mode)) 281 (if (memq major-mode '(c-mode c++ mode))
@@ -301,9 +304,6 @@ If the outermost list is matched, don't rely on its PAIR.
301If point is not enclosed by any lists, return ((t) . (t))." 304If point is not enclosed by any lists, return ((t) . (t))."
302 (let* (innermost 305 (let* (innermost
303 outermost 306 outermost
304 (table (if string-or-comment
305 electric-pair-text-syntax-table
306 (syntax-table)))
307 (at-top-level-or-equivalent-fn 307 (at-top-level-or-equivalent-fn
308 ;; called when `scan-sexps' ran perfectly, when it found 308 ;; called when `scan-sexps' ran perfectly, when it found
309 ;; a parenthesis pointing in the direction of travel. 309 ;; a parenthesis pointing in the direction of travel.
@@ -325,11 +325,14 @@ If point is not enclosed by any lists, return ((t) . (t))."
325 (cond ((< direction 0) 325 (cond ((< direction 0)
326 (condition-case nil 326 (condition-case nil
327 (eq (char-after pos) 327 (eq (char-after pos)
328 (electric-pair--with-uncached-syntax 328 (cl-flet ((f ()
329 (table) 329 (matching-paren
330 (matching-paren 330 (char-before
331 (char-before 331 (scan-sexps (point) 1)))))
332 (scan-sexps (point) 1))))) 332 (if string-or-comment
333 (electric-pair--with-text-syntax ()
334 (f))
335 (f))))
333 (scan-error nil))) 336 (scan-error nil)))
334 (t 337 (t
335 ;; In this case, no need to use 338 ;; In this case, no need to use
@@ -343,7 +346,9 @@ If point is not enclosed by any lists, return ((t) . (t))."
343 (opener (char-after start))) 346 (opener (char-after start)))
344 (and start 347 (and start
345 (eq (char-before pos) 348 (eq (char-before pos)
346 (or (with-syntax-table table 349 (or (if string-or-comment
350 (electric-pair--with-text-syntax ()
351 (matching-paren opener))
347 (matching-paren opener)) 352 (matching-paren opener))
348 opener)))))))) 353 opener))))))))
349 (actual-pair (if (> direction 0) 354 (actual-pair (if (> direction 0)
@@ -356,11 +361,14 @@ If point is not enclosed by any lists, return ((t) . (t))."
356 (save-excursion 361 (save-excursion
357 (while (not outermost) 362 (while (not outermost)
358 (condition-case err 363 (condition-case err
359 (electric-pair--with-uncached-syntax (table) 364 (cl-flet ((f ()
360 (scan-sexps (point) (if (> direction 0) 365 (scan-sexps (point) (if (> direction 0)
361 (point-max) 366 (point-max)
362 (- (point-max)))) 367 (- (point-max))))
363 (funcall at-top-level-or-equivalent-fn)) 368 (funcall at-top-level-or-equivalent-fn)))
369 (if string-or-comment
370 (electric-pair--with-text-syntax () (f))
371 (f)))
364 (scan-error 372 (scan-error
365 (cond ((or 373 (cond ((or
366 ;; some error happened and it is not of the "ended 374 ;; some error happened and it is not of the "ended