Fix bug with min and max and NaNs
[emacs.git] / lisp / elec-pair.el
blob7f523d1df451a6f7124acbb92e22ddbfb4909122
1 ;;; elec-pair.el --- Automatic parenthesis pairing -*- lexical-binding:t -*-
3 ;; Copyright (C) 2013-2017 Free Software Foundation, Inc.
5 ;; Author: João Távora <joaotavora@gmail.com>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
22 ;;; Commentary:
24 ;;; Code:
26 (require 'electric)
28 ;;; Electric pairing.
30 (defcustom electric-pair-pairs
31 `((?\" . ?\")
32 (,(nth 0 electric-quote-chars) . ,(nth 1 electric-quote-chars))
33 (,(nth 2 electric-quote-chars) . ,(nth 3 electric-quote-chars)))
34 "Alist of pairs that should be used regardless of major mode.
36 Pairs of delimiters in this list are a fallback in case they have
37 no syntax relevant to `electric-pair-mode' in the mode's syntax
38 table.
40 See also the variable `electric-pair-text-pairs'."
41 :version "24.1"
42 :group 'electricity
43 :type '(repeat (cons character character)))
45 (defcustom electric-pair-text-pairs
46 `((?\" . ?\")
47 (,(nth 0 electric-quote-chars) . ,(nth 1 electric-quote-chars))
48 (,(nth 2 electric-quote-chars) . ,(nth 3 electric-quote-chars)))
49 "Alist of pairs that should always be used in comments and strings.
51 Pairs of delimiters in this list are a fallback in case they have
52 no syntax relevant to `electric-pair-mode' in the syntax table
53 defined in `electric-pair-text-syntax-table'"
54 :version "24.4"
55 :group 'electricity
56 :type '(repeat (cons character character)))
58 (defcustom electric-pair-skip-self #'electric-pair-default-skip-self
59 "If non-nil, skip char instead of inserting a second closing paren.
61 When inserting a closing paren character right before the same character,
62 just skip that character instead, so that hitting ( followed by ) results
63 in \"()\" rather than \"())\".
65 This can be convenient for people who find it easier to hit ) than C-f.
67 Can also be a function of one argument (the closer char just
68 inserted), in which case that function's return value is
69 considered instead."
70 :version "24.1"
71 :group 'electricity
72 :type '(choice
73 (const :tag "Never skip" nil)
74 (const :tag "Help balance" electric-pair-default-skip-self)
75 (const :tag "Always skip" t)
76 function))
78 (defcustom electric-pair-inhibit-predicate
79 #'electric-pair-default-inhibit
80 "Predicate to prevent insertion of a matching pair.
82 The function is called with a single char (the opening char just inserted).
83 If it returns non-nil, then `electric-pair-mode' will not insert a matching
84 closer."
85 :version "24.4"
86 :group 'electricity
87 :type '(choice
88 (const :tag "Conservative" electric-pair-conservative-inhibit)
89 (const :tag "Help balance" electric-pair-default-inhibit)
90 (const :tag "Always pair" ignore)
91 function))
93 (defcustom electric-pair-preserve-balance t
94 "Non-nil if default pairing and skipping should help balance parentheses.
96 The default values of `electric-pair-inhibit-predicate' and
97 `electric-pair-skip-self' check this variable before delegating to other
98 predicates responsible for making decisions on whether to pair/skip some
99 characters based on the actual state of the buffer's parentheses and
100 quotes."
101 :version "24.4"
102 :group 'electricity
103 :type 'boolean)
105 (defcustom electric-pair-delete-adjacent-pairs t
106 "If non-nil, backspacing an open paren also deletes adjacent closer.
108 Can also be a function of no arguments, in which case that function's
109 return value is considered instead."
110 :version "24.4"
111 :group 'electricity
112 :type '(choice
113 (const :tag "Yes" t)
114 (const :tag "No" nil)
115 function))
117 (defcustom electric-pair-open-newline-between-pairs t
118 "If non-nil, a newline between adjacent parentheses opens an extra one.
120 Can also be a function of no arguments, in which case that function's
121 return value is considered instead."
122 :version "24.4"
123 :group 'electricity
124 :type '(choice
125 (const :tag "Yes" t)
126 (const :tag "No" nil)
127 function))
129 (defcustom electric-pair-skip-whitespace t
130 "If non-nil skip whitespace when skipping over closing parens.
132 The specific kind of whitespace skipped is given by the variable
133 `electric-pair-skip-whitespace-chars'.
135 The symbol `chomp' specifies that the skipped-over whitespace
136 should be deleted.
138 Can also be a function of no arguments, in which case that function's
139 return value is considered instead."
140 :version "24.4"
141 :group 'electricity
142 :type '(choice
143 (const :tag "Yes, jump over whitespace" t)
144 (const :tag "Yes, and delete whitespace" chomp)
145 (const :tag "No, no whitespace skipping" nil)
146 function))
148 (defcustom electric-pair-skip-whitespace-chars (list ?\t ?\s ?\n)
149 "Whitespace characters considered by `electric-pair-skip-whitespace'."
150 :version "24.4"
151 :group 'electricity
152 :type '(choice (set (const :tag "Space" ?\s)
153 (const :tag "Tab" ?\t)
154 (const :tag "Newline" ?\n))
155 (list character)))
157 (defun electric-pair--skip-whitespace ()
158 "Skip whitespace forward, not crossing comment or string boundaries."
159 (let ((saved (point))
160 (string-or-comment (nth 8 (syntax-ppss))))
161 (skip-chars-forward (apply #'string electric-pair-skip-whitespace-chars))
162 (unless (eq string-or-comment (nth 8 (syntax-ppss)))
163 (goto-char saved))))
165 (defvar electric-pair-text-syntax-table prog-mode-syntax-table
166 "Syntax table used when pairing inside comments and strings.
168 `electric-pair-mode' considers this syntax table only when point in inside
169 quotes or comments. If lookup fails here, `electric-pair-text-pairs' will
170 be considered.")
172 (defun electric-pair-conservative-inhibit (char)
174 ;; I find it more often preferable not to pair when the
175 ;; same char is next.
176 (eq char (char-after))
177 ;; Don't pair up when we insert the second of "" or of ((.
178 (and (eq char (char-before))
179 (eq char (char-before (1- (point)))))
180 ;; I also find it often preferable not to pair next to a word.
181 (eq (char-syntax (following-char)) ?w)))
183 (defun electric-pair-syntax-info (command-event)
184 "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START).
186 SYNTAX is COMMAND-EVENT's syntax character. PAIR is
187 COMMAND-EVENT's pair. UNCONDITIONAL indicates the variables
188 `electric-pair-pairs' or `electric-pair-text-pairs' were used to
189 lookup syntax. STRING-OR-COMMENT-START indicates that point is
190 inside a comment or string."
191 (let* ((pre-string-or-comment (or (bobp)
192 (nth 8 (save-excursion
193 (syntax-ppss (1- (point)))))))
194 (post-string-or-comment (nth 8 (syntax-ppss (point))))
195 (string-or-comment (and post-string-or-comment
196 pre-string-or-comment))
197 (table (if string-or-comment
198 electric-pair-text-syntax-table
199 (syntax-table)))
200 (table-syntax-and-pair (with-syntax-table table
201 (list (char-syntax command-event)
202 (or (matching-paren command-event)
203 command-event))))
204 (fallback (if string-or-comment
205 (append electric-pair-text-pairs
206 electric-pair-pairs)
207 electric-pair-pairs))
208 (direct (assq command-event fallback))
209 (reverse (rassq command-event fallback)))
210 (cond
211 ((memq (car table-syntax-and-pair)
212 '(?\" ?\( ?\) ?\$))
213 (append table-syntax-and-pair (list nil string-or-comment)))
214 (direct (if (eq (car direct) (cdr direct))
215 (list ?\" command-event t string-or-comment)
216 (list ?\( (cdr direct) t string-or-comment)))
217 (reverse (list ?\) (car reverse) t string-or-comment)))))
219 (defun electric-pair--insert (char)
220 (let ((last-command-event char)
221 (blink-matching-paren nil)
222 (electric-pair-mode nil))
223 (self-insert-command 1)))
225 (defun electric-pair--syntax-ppss (&optional pos where)
226 "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
228 WHERE is a list defaulting to '(string comment) and indicates
229 when to fallback to `parse-partial-sexp'."
230 (let* ((pos (or pos (point)))
231 (where (or where '(string comment)))
232 (quick-ppss (syntax-ppss pos))
233 (in-string (and (nth 3 quick-ppss) (memq 'string where)))
234 (in-comment (and (nth 4 quick-ppss) (memq 'comment where)))
235 (s-or-c-start (cond (in-string
236 (1+ (nth 8 quick-ppss)))
237 (in-comment
238 (goto-char (nth 8 quick-ppss))
239 (forward-comment (- (point-max)))
240 (skip-syntax-forward " >!")
241 (point)))))
242 (if s-or-c-start
243 (with-syntax-table electric-pair-text-syntax-table
244 (parse-partial-sexp s-or-c-start pos))
245 ;; HACK! cc-mode apparently has some `syntax-ppss' bugs
246 (if (memq major-mode '(c-mode c++ mode))
247 (parse-partial-sexp (point-min) pos)
248 quick-ppss))))
250 ;; Balancing means controlling pairing and skipping of parentheses
251 ;; so that, if possible, the buffer ends up at least as balanced as
252 ;; before, if not more. The algorithm is slightly complex because
253 ;; some situations like "()))" need pairing to occur at the end but
254 ;; not at the beginning. Balancing should also happen independently
255 ;; for different types of parentheses, so that having your {}'s
256 ;; unbalanced doesn't keep `electric-pair-mode' from balancing your
257 ;; ()'s and your []'s.
258 (defun electric-pair--balance-info (direction string-or-comment)
259 "Examine lists forward or backward according to DIRECTION's sign.
261 STRING-OR-COMMENT is info suitable for running `parse-partial-sexp'.
263 Return a cons of two descriptions (MATCHED-P . PAIR) for the
264 innermost and outermost lists that enclose point. The outermost
265 list enclosing point is either the first top-level or first
266 mismatched list found by listing up.
268 If the outermost list is matched, don't rely on its PAIR.
269 If point is not enclosed by any lists, return ((t) . (t))."
270 (let* (innermost
271 outermost
272 (table (if string-or-comment
273 electric-pair-text-syntax-table
274 (syntax-table)))
275 (at-top-level-or-equivalent-fn
276 ;; called when `scan-sexps' ran perfectly, when it found
277 ;; a parenthesis pointing in the direction of travel.
278 ;; Also when travel started inside a comment and exited it.
279 #'(lambda ()
280 (setq outermost (list t))
281 (unless innermost
282 (setq innermost (list t)))))
283 (ended-prematurely-fn
284 ;; called when `scan-sexps' crashed against a parenthesis
285 ;; pointing opposite the direction of travel. After
286 ;; traversing that character, the idea is to travel one sexp
287 ;; in the opposite direction looking for a matching
288 ;; delimiter.
289 #'(lambda ()
290 (let* ((pos (point))
291 (matched
292 (save-excursion
293 (cond ((< direction 0)
294 (condition-case nil
295 (eq (char-after pos)
296 (with-syntax-table table
297 (matching-paren
298 (char-before
299 (scan-sexps (point) 1)))))
300 (scan-error nil)))
302 ;; In this case, no need to use
303 ;; `scan-sexps', we can use some
304 ;; `electric-pair--syntax-ppss' in this
305 ;; case (which uses the quicker
306 ;; `syntax-ppss' in some cases)
307 (let* ((ppss (electric-pair--syntax-ppss
308 (1- (point))))
309 (start (car (last (nth 9 ppss))))
310 (opener (char-after start)))
311 (and start
312 (eq (char-before pos)
313 (or (with-syntax-table table
314 (matching-paren opener))
315 opener))))))))
316 (actual-pair (if (> direction 0)
317 (char-before (point))
318 (char-after (point)))))
319 (unless innermost
320 (setq innermost (cons matched actual-pair)))
321 (unless matched
322 (setq outermost (cons matched actual-pair)))))))
323 (save-excursion
324 (while (not outermost)
325 (condition-case err
326 (with-syntax-table table
327 (scan-sexps (point) (if (> direction 0)
328 (point-max)
329 (- (point-max))))
330 (funcall at-top-level-or-equivalent-fn))
331 (scan-error
332 (cond ((or
333 ;; some error happened and it is not of the "ended
334 ;; prematurely" kind...
335 (not (string-match "ends prematurely" (nth 1 err)))
336 ;; ... or we were in a comment and just came out of
337 ;; it.
338 (and string-or-comment
339 (not (nth 8 (syntax-ppss)))))
340 (funcall at-top-level-or-equivalent-fn))
342 ;; exit the sexp
343 (goto-char (nth 3 err))
344 (funcall ended-prematurely-fn)))))))
345 (cons innermost outermost)))
347 (defvar electric-pair-string-bound-function 'point-max
348 "Next buffer position where strings are syntactically unexpected.
349 Value is a function called with no arguments and returning a
350 buffer position. Major modes should set this variable
351 buffer-locally if they experience slowness with
352 `electric-pair-mode' when pairing quotes.")
354 (defun electric-pair--unbalanced-strings-p (char)
355 "Return non-nil if there are unbalanced strings started by CHAR."
356 (let* ((selector-ppss (syntax-ppss))
357 (relevant-ppss (save-excursion
358 (if (nth 4 selector-ppss) ; comment
359 (electric-pair--syntax-ppss
360 (progn
361 (goto-char (nth 8 selector-ppss))
362 (forward-comment (point-max))
363 (skip-syntax-backward " >!")
364 (point)))
365 (syntax-ppss
366 (funcall electric-pair-string-bound-function)))))
367 (string-delim (nth 3 relevant-ppss)))
368 (or (eq t string-delim)
369 (eq char string-delim))))
371 (defun electric-pair--inside-string-p (char)
372 "Return non-nil if point is inside a string started by CHAR.
374 A comments text is parsed with `electric-pair-text-syntax-table'.
375 Also consider strings within comments, but not strings within
376 strings."
377 ;; FIXME: could also consider strings within strings by examining
378 ;; delimiters.
379 (let ((ppss (electric-pair--syntax-ppss (point) '(comment))))
380 (memq (nth 3 ppss) (list t char))))
382 (defun electric-pair-inhibit-if-helps-balance (char)
383 "Return non-nil if auto-pairing of CHAR would hurt parentheses' balance.
385 Works by first removing the character from the buffer, then doing
386 some list calculations, finally restoring the situation as if nothing
387 happened."
388 (pcase (electric-pair-syntax-info char)
389 (`(,syntax ,pair ,_ ,s-or-c)
390 (unwind-protect
391 (progn
392 (delete-char -1)
393 (cond ((eq ?\( syntax)
394 (let* ((pair-data
395 (electric-pair--balance-info 1 s-or-c))
396 (outermost (cdr pair-data)))
397 (cond ((car outermost)
398 nil)
400 (eq (cdr outermost) pair)))))
401 ((eq syntax ?\")
402 (electric-pair--unbalanced-strings-p char))))
403 (insert-char char)))))
405 (defun electric-pair-skip-if-helps-balance (char)
406 "Return non-nil if skipping CHAR would benefit parentheses' balance.
408 Works by first removing the character from the buffer, then doing
409 some list calculations, finally restoring the situation as if nothing
410 happened."
411 (pcase (electric-pair-syntax-info char)
412 (`(,syntax ,pair ,_ ,s-or-c)
413 (unwind-protect
414 (progn
415 (delete-char -1)
416 (cond ((eq syntax ?\))
417 (let* ((pair-data
418 (electric-pair--balance-info
419 -1 s-or-c))
420 (innermost (car pair-data))
421 (outermost (cdr pair-data)))
422 (and
423 (cond ((car outermost)
424 (car innermost))
425 ((car innermost)
426 (not (eq (cdr outermost) pair)))))))
427 ((eq syntax ?\")
428 (electric-pair--inside-string-p char))))
429 (insert-char char)))))
431 (defun electric-pair-default-skip-self (char)
432 (if electric-pair-preserve-balance
433 (electric-pair-skip-if-helps-balance char)
436 (defun electric-pair-default-inhibit (char)
437 (if electric-pair-preserve-balance
438 (electric-pair-inhibit-if-helps-balance char)
439 (electric-pair-conservative-inhibit char)))
441 (defun electric-pair-post-self-insert-function ()
442 (let* ((pos (and electric-pair-mode (electric--after-char-pos)))
443 (skip-whitespace-info))
444 (pcase (electric-pair-syntax-info last-command-event)
445 (`(,syntax ,pair ,unconditional ,_)
446 (cond
447 ((null pos) nil)
448 ;; Wrap a pair around the active region.
450 ((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
451 ;; FIXME: To do this right, we'd need a post-self-insert-function
452 ;; so we could add-function around it and insert the closer after
453 ;; all the rest of the hook has run.
454 (if (or (eq syntax ?\")
455 (and (eq syntax ?\))
456 (>= (point) (mark)))
457 (and (not (eq syntax ?\)))
458 (>= (mark) (point))))
459 (save-excursion
460 (goto-char (mark))
461 (electric-pair--insert pair))
462 (delete-region pos (1- pos))
463 (electric-pair--insert pair)
464 (goto-char (mark))
465 (electric-pair--insert last-command-event)))
466 ;; Backslash-escaped: no pairing, no skipping.
467 ((save-excursion
468 (goto-char (1- pos))
469 (not (zerop (% (skip-syntax-backward "\\") 2))))
470 nil)
471 ;; Skip self.
472 ((and (memq syntax '(?\) ?\" ?\$))
473 (and (or unconditional
474 (if (functionp electric-pair-skip-self)
475 (funcall electric-pair-skip-self last-command-event)
476 electric-pair-skip-self))
477 (save-excursion
478 (when (and (not (and unconditional
479 (eq syntax ?\")))
480 (setq skip-whitespace-info
481 (if (and (not (eq electric-pair-skip-whitespace 'chomp))
482 (functionp electric-pair-skip-whitespace))
483 (funcall electric-pair-skip-whitespace)
484 electric-pair-skip-whitespace)))
485 (electric-pair--skip-whitespace))
486 (eq (char-after) last-command-event))))
487 ;; This is too late: rather than insert&delete we'd want to only
488 ;; skip (or insert in overwrite mode). The difference is in what
489 ;; goes in the undo-log and in the intermediate state which might
490 ;; be visible to other post-self-insert-hook. We'll just have to
491 ;; live with it for now.
492 (when skip-whitespace-info
493 (electric-pair--skip-whitespace))
494 (delete-region (1- pos) (if (eq skip-whitespace-info 'chomp)
495 (point)
496 pos))
497 (forward-char))
498 ;; Insert matching pair.
499 ((and (memq syntax `(?\( ?\" ?\$))
500 (not overwrite-mode)
501 (or unconditional
502 (not (funcall electric-pair-inhibit-predicate
503 last-command-event))))
504 (save-excursion (electric-pair--insert pair)))))
506 (when (and (if (functionp electric-pair-open-newline-between-pairs)
507 (funcall electric-pair-open-newline-between-pairs)
508 electric-pair-open-newline-between-pairs)
509 (eq last-command-event ?\n)
510 (< (1+ (point-min)) (point) (point-max))
511 (eq (save-excursion
512 (skip-chars-backward "\t\s")
513 (char-before (1- (point))))
514 (matching-paren (char-after))))
515 (save-excursion (newline 1 t)))))))
517 (put 'electric-pair-post-self-insert-function 'priority 20)
519 (defun electric-pair-will-use-region ()
520 (and (use-region-p)
521 (memq (car (electric-pair-syntax-info last-command-event))
522 '(?\( ?\) ?\" ?\$))))
524 (defun electric-pair-delete-pair (arg &optional killp)
525 "When between adjacent paired delimiters, delete both of them.
526 ARG and KILLP are passed directly to
527 `backward-delete-char-untabify', which see."
528 (interactive "*p\nP")
529 (delete-char 1)
530 (backward-delete-char-untabify arg killp))
532 (defvar electric-pair-mode-map
533 (let ((map (make-sparse-keymap)))
534 (define-key map "\177"
535 `(menu-item
536 "" electric-pair-delete-pair
537 :filter
538 ,(lambda (cmd)
539 (let* ((prev (char-before))
540 (next (char-after))
541 (syntax-info (and prev
542 (electric-pair-syntax-info prev)))
543 (syntax (car syntax-info))
544 (pair (cadr syntax-info)))
545 (and next pair
546 (memq syntax '(?\( ?\" ?\$))
547 (eq pair next)
548 (if (functionp electric-pair-delete-adjacent-pairs)
549 (funcall electric-pair-delete-adjacent-pairs)
550 electric-pair-delete-adjacent-pairs)
551 cmd)))))
552 map)
553 "Keymap used by `electric-pair-mode'.")
555 ;;;###autoload
556 (define-minor-mode electric-pair-mode
557 "Toggle automatic parens pairing (Electric Pair mode).
558 With a prefix argument ARG, enable Electric Pair mode if ARG is
559 positive, and disable it otherwise. If called from Lisp, enable
560 the mode if ARG is omitted or nil.
562 Electric Pair mode is a global minor mode. When enabled, typing
563 an open parenthesis automatically inserts the corresponding
564 closing parenthesis. (Likewise for brackets, etc.). To toggle
565 the mode in a single buffer, use `electric-pair-local-mode'."
566 :global t :group 'electricity
567 (if electric-pair-mode
568 (progn
569 (add-hook 'post-self-insert-hook
570 #'electric-pair-post-self-insert-function)
571 (electric--sort-post-self-insertion-hook)
572 (add-hook 'self-insert-uses-region-functions
573 #'electric-pair-will-use-region))
574 (remove-hook 'post-self-insert-hook
575 #'electric-pair-post-self-insert-function)
576 (remove-hook 'self-insert-uses-region-functions
577 #'electric-pair-will-use-region)))
579 ;;;###autoload
580 (define-minor-mode electric-pair-local-mode
581 "Toggle `electric-pair-mode' only in this buffer."
582 :variable (buffer-local-value 'electric-pair-mode (current-buffer))
583 (cond
584 ((eq electric-pair-mode (default-value 'electric-pair-mode))
585 (kill-local-variable 'electric-pair-mode))
586 ((not (default-value 'electric-pair-mode))
587 ;; Locally enabled, but globally disabled.
588 (electric-pair-mode 1) ; Setup the hooks.
589 (setq-default electric-pair-mode nil) ; But keep it globally disabled.
592 (provide 'elec-pair)
594 ;;; elec-pair.el ends here