aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2013-12-27 07:53:57 -0500
committerStefan Monnier2013-12-27 07:53:57 -0500
commit7514d3f8063a829d681faa76c408961ade61733f (patch)
tree1253904636eab36fb1e7ded85e59ce9268395ee9
parent765fe182c4b39093b4763c065b98cf7019cc6979 (diff)
downloademacs-7514d3f8063a829d681faa76c408961ade61733f.tar.gz
emacs-7514d3f8063a829d681faa76c408961ade61733f.zip
* lisp/electric.el: Move all electric-pair-* to elec-pair.el.
* lisp/elec-pair.el: New file, split from electric.el.
-rw-r--r--lisp/ChangeLog52
-rw-r--r--lisp/elec-pair.el566
-rw-r--r--lisp/electric.el527
3 files changed, 594 insertions, 551 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 379e49dc11d..e9685a23299 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,8 @@
12013-12-27 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * electric.el: Move all electric-pair-* to elec-pair.el.
4 * elec-pair.el: New file, split from electric.el.
5
12013-12-27 Lars Ingebrigtsen <larsi@gnus.org> 62013-12-27 Lars Ingebrigtsen <larsi@gnus.org>
2 7
3 * net/shr.el (shr-find-fill-point): Don't try to fill if the 8 * net/shr.el (shr-find-fill-point): Don't try to fill if the
@@ -8,26 +13,25 @@
8 (shr-find-fill-point): Off by one error in comparison with the 13 (shr-find-fill-point): Off by one error in comparison with the
9 indentation. 14 indentation.
10 15
112013-12-26 João Távora <joaotavora@gmail.com> 162013-12-26 João Távora <joaotavora@gmail.com>
12 17
13 * electric.el (electric-pair-mode): More flexible engine for skip- 18 * electric.el (electric-pair-mode): More flexible engine for skip-
14 and inhibit predicates, new options for pairing-related 19 and inhibit predicates, new options for pairing-related functionality.
15 functionality.
16 (electric-pair-preserve-balance): Pair/skip parentheses and quotes 20 (electric-pair-preserve-balance): Pair/skip parentheses and quotes
17 if that keeps or improves their balance in buffers. 21 if that keeps or improves their balance in buffers.
18 (electric-pair-delete-adjacent-pairs): Delete the pair when 22 (electric-pair-delete-adjacent-pairs): Delete the pair when
19 backspacing over adjacent matched delimiters. 23 backspacing over adjacent matched delimiters.
20 (electric-pair-open-extra-newline): Open extra newline when 24 (electric-pair-open-extra-newline): Open extra newline when
21 inserting newlines between adjacent matched delimiters. 25 inserting newlines between adjacent matched delimiters.
22 (electric--sort-post-self-insertion-hook): Sort 26 (electric--sort-post-self-insertion-hook):
23 post-self-insert-hook according to priority values when 27 Sort post-self-insert-hook according to priority values when
24 minor-modes are activated. 28 minor-modes are activated.
25 * simple.el (newline-and-indent): Call newline with interactive 29 * simple.el (newline-and-indent): Call newline with interactive
26 set to t. 30 set to t.
27 (blink-paren-post-self-insert-function): Set priority to 100. 31 (blink-paren-post-self-insert-function): Set priority to 100.
28 * emacs-lisp/lisp-mode.el (lisp-mode-variables): Use 32 * emacs-lisp/lisp-mode.el (lisp-mode-variables):
29 electric-pair-text-pairs to pair backtick-and-quote in strings and 33 Use electric-pair-text-pairs to pair backtick-and-quote in strings and
30 comments. Locally set electric-pair-skip-whitespace to 'chomp and 34 comments. Locally set electric-pair-skip-whitespace to 'chomp and
31 electric-pair-open-newline-between-pairs to nil. 35 electric-pair-open-newline-between-pairs to nil.
32 36
332013-12-26 Fabián Ezequiel Gallina <fgallina@gnu.org> 372013-12-26 Fabián Ezequiel Gallina <fgallina@gnu.org>
@@ -64,8 +68,8 @@
64 (Bug#16191). 68 (Bug#16191).
65 (python-nav-backward-sexp, python-nav-forward-sexp-safe) 69 (python-nav-backward-sexp, python-nav-forward-sexp-safe)
66 (python-nav-backward-sexp-safe): New functions. 70 (python-nav-backward-sexp-safe): New functions.
67 (python-shell-buffer-substring): Use 71 (python-shell-buffer-substring):
68 `python-nav-forward-sexp-safe'. 72 Use `python-nav-forward-sexp-safe'.
69 73
702013-12-25 Lars Ingebrigtsen <larsi@gnus.org> 742013-12-25 Lars Ingebrigtsen <larsi@gnus.org>
71 75
@@ -73,8 +77,7 @@
73 quotation mark. 77 quotation mark.
74 (shr-char-kinsoku-bol-p): The quotation mark isn't a kinsoky BOL char. 78 (shr-char-kinsoku-bol-p): The quotation mark isn't a kinsoky BOL char.
75 (shr-find-fill-point): Remove the special checks for the quotation 79 (shr-find-fill-point): Remove the special checks for the quotation
76 mark, since `shr-char-kinsoku-bol-p' should now return the right 80 mark, since `shr-char-kinsoku-bol-p' should now return the right thing.
77 thing.
78 81
792013-12-25 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> 822013-12-25 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com>
80 83
@@ -84,8 +87,8 @@
84 87
852013-12-24 Fabián Ezequiel Gallina <fgallina@gnu.org> 882013-12-24 Fabián Ezequiel Gallina <fgallina@gnu.org>
86 89
87 * progmodes/python.el (python-nav-beginning-of-statement): Speed 90 * progmodes/python.el (python-nav-beginning-of-statement):
88 up (Bug#15295). 91 Speed up (Bug#15295).
89 92
902013-12-24 Lars Ingebrigtsen <larsi@gnus.org> 932013-12-24 Lars Ingebrigtsen <larsi@gnus.org>
91 94
@@ -115,8 +118,7 @@
115 (icomplete-show-matches-on-no-input): New customizable variable. 118 (icomplete-show-matches-on-no-input): New customizable variable.
116 (icomplete-minibuffer-setup): Call `icomplete-exhibit' on setup if 119 (icomplete-minibuffer-setup): Call `icomplete-exhibit' on setup if
117 we have something to show. 120 we have something to show.
118 (icomplete-exhibit): Compute completions even if we have no user 121 (icomplete-exhibit): Compute completions even if we have no user input.
119 input.
120 122
1212013-12-23 Daniel Colascione <dancol@dancol.org> 1232013-12-23 Daniel Colascione <dancol@dancol.org>
122 124
@@ -146,7 +148,7 @@
146 148
147 * net/eww.el (eww-tag-select): Add text-property to jump to next 149 * net/eww.el (eww-tag-select): Add text-property to jump to next
148 select field. 150 select field.
149 (eww) : Add non-supported ftp error. 151 (eww) : Add non-supported ftp error.
150 152
1512013-12-22 Dmitry Gutov <dgutov@yandex.ru> 1532013-12-22 Dmitry Gutov <dgutov@yandex.ru>
152 154
@@ -156,8 +158,8 @@
1562013-12-22 Chong Yidong <cyd@gnu.org> 1582013-12-22 Chong Yidong <cyd@gnu.org>
157 159
158 * faces.el (face-spec-recalc): If the theme specs are not 160 * faces.el (face-spec-recalc): If the theme specs are not
159 applicable to a frame, fall back on the defface spec. This 161 applicable to a frame, fall back on the defface spec.
160 prevents themes from obliterating faces on low-color terminals. 162 This prevents themes from obliterating faces on low-color terminals.
161 163
1622013-12-22 Dmitry Gutov <dgutov@yandex.ru> 1642013-12-22 Dmitry Gutov <dgutov@yandex.ru>
163 165
@@ -774,8 +776,10 @@
774 * emacs-lisp/package.el (package--prepare-dependencies): New function. 776 * emacs-lisp/package.el (package--prepare-dependencies): New function.
775 (package-buffer-info): Use it (bug#15108). 777 (package-buffer-info): Use it (bug#15108).
776 778
7792013-12-14 Stefan Monnier <monnier@iro.umontreal.ca>
780
777 * icomplete.el (icomplete-completions): Make sure the prefix is already 781 * icomplete.el (icomplete-completions): Make sure the prefix is already
778 displayed elsewhere before hiding it. 782 displayed elsewhere before hiding it (bug#16219).
779 783
7802013-12-14 Dmitry Gutov <dgutov@yandex.ru> 7842013-12-14 Dmitry Gutov <dgutov@yandex.ru>
781 785
@@ -976,7 +980,7 @@
976 * bindings.el: Map kp keys to non-kp keys systematically 980 * bindings.el: Map kp keys to non-kp keys systematically
977 with basic modifiers control, meta and shift. (Bug#14397) 981 with basic modifiers control, meta and shift. (Bug#14397)
978 982
9792013-12-11 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com> (tiny change) 9832013-12-11 Kenjiro NAKAYAMA <nakayamakenjiro@gmail.com>
980 984
981 * net/eww.el (eww-mode-map): Instead of "Quit" show "Exit" and 985 * net/eww.el (eww-mode-map): Instead of "Quit" show "Exit" and
982 "Close browser" menu items. Fix wrong function of "List 986 "Close browser" menu items. Fix wrong function of "List
@@ -1593,10 +1597,10 @@
1593 * leim/quail/uni-input.el (ucs-input-activate): Add autoload cookie. 1597 * leim/quail/uni-input.el (ucs-input-activate): Add autoload cookie.
1594 (generated-autoload-load-name): Set file-local value. 1598 (generated-autoload-load-name): Set file-local value.
1595 1599
15962013-11-26 Kenjiro NAKAYAMA <knakayam@redhat.com> (tiny change) 16002013-11-26 Kenjiro NAKAYAMA <knakayam@redhat.com>
1597 1601
1598 * net/eww.el (eww-bookmark-browse): Use 'eww-browse-url'. 1602 * net/eww.el (eww-bookmark-browse): Use 'eww-browse-url'.
1599 (eww-add-bookmark): Ask confirmation when add to bookmarks 1603 (eww-add-bookmark): Ask confirmation when add to bookmarks.
1600 (eww-quit): Ask confirmation before quitting eww. 1604 (eww-quit): Ask confirmation before quitting eww.
1601 1605
16022013-11-26 Eli Zaretskii <eliz@gnu.org> 16062013-11-26 Eli Zaretskii <eliz@gnu.org>
@@ -1777,7 +1781,7 @@
1777 Add `octave-source-file'. 1781 Add `octave-source-file'.
1778 (octave-source-file): New function. (Bug#15935) 1782 (octave-source-file): New function. (Bug#15935)
1779 1783
17802013-11-21 Kenjiro Nakayama <nakayamakenjiro@gmail.com> (tiny change) 17842013-11-21 Kenjiro Nakayama <nakayamakenjiro@gmail.com>
1781 1785
1782 * net/eww.el (eww-local-regex): New variable. 1786 * net/eww.el (eww-local-regex): New variable.
1783 (eww): Use it to detect localhost and similar. 1787 (eww): Use it to detect localhost and similar.
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
new file mode 100644
index 00000000000..130ce9f4ca2
--- /dev/null
+++ b/lisp/elec-pair.el
@@ -0,0 +1,566 @@
1;;; elec-pair.el --- Automatic parenthesis pairing -*- lexical-binding:t -*-
2
3;; Copyright (C) 2013 Free Software Foundation, Inc.
4
5;; Author: João Távora <joaotavora@gmail.com>
6
7;; This file is part of GNU Emacs.
8
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.
13
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.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23
24;;; Code:
25
26(require 'electric)
27
28;;; Electric pairing.
29
30(defcustom electric-pair-pairs
31 '((?\" . ?\"))
32 "Alist of pairs that should be used regardless of major mode.
33
34Pairs of delimiters in this list are a fallback in case they have
35no syntax relevant to `electric-pair-mode' in the mode's syntax
36table.
37
38See also the variable `electric-pair-text-pairs'."
39 :version "24.1"
40 :group 'electricity
41 :type '(repeat (cons character character)))
42
43;;;###autoload
44(defcustom electric-pair-text-pairs
45 '((?\" . ?\" ))
46 "Alist of pairs that should always be used in comments and strings.
47
48Pairs of delimiters in this list are a fallback in case they have
49no syntax relevant to `electric-pair-mode' in the syntax table
50defined in `electric-pair-text-syntax-table'"
51 :version "24.4"
52 :group 'electricity
53 :type '(repeat (cons character character)))
54
55(defcustom electric-pair-skip-self #'electric-pair-default-skip-self
56 "If non-nil, skip char instead of inserting a second closing paren.
57
58When inserting a closing paren character right before the same character,
59just skip that character instead, so that hitting ( followed by ) results
60in \"()\" rather than \"())\".
61
62This can be convenient for people who find it easier to hit ) than C-f.
63
64Can also be a function of one argument (the closer char just
65inserted), in which case that function's return value is
66considered instead."
67 :version "24.1"
68 :group 'electricity
69 :type '(choice
70 (const :tag "Never skip" nil)
71 (const :tag "Help balance" electric-pair-default-skip-self)
72 (const :tag "Always skip" t)
73 function))
74
75(defcustom electric-pair-inhibit-predicate
76 #'electric-pair-default-inhibit
77 "Predicate to prevent insertion of a matching pair.
78
79The function is called with a single char (the opening char just inserted).
80If it returns non-nil, then `electric-pair-mode' will not insert a matching
81closer."
82 :version "24.4"
83 :group 'electricity
84 :type '(choice
85 (const :tag "Conservative" electric-pair-conservative-inhibit)
86 (const :tag "Help balance" electric-pair-default-inhibit)
87 (const :tag "Always pair" ignore)
88 function))
89
90(defcustom electric-pair-preserve-balance t
91 "Non-nil if default pairing and skipping should help balance parentheses.
92
93The default values of `electric-pair-inhibit-predicate' and
94`electric-pair-skip-self' check this variable before delegating to other
95predicates reponsible for making decisions on whether to pair/skip some
96characters based on the actual state of the buffer's parenthesis and
97quotes."
98 :version "24.4"
99 :group 'electricity
100 :type 'boolean)
101
102(defcustom electric-pair-delete-adjacent-pairs t
103 "If non-nil, backspacing an open paren also deletes adjacent closer.
104
105Can also be a function of no arguments, in which case that function's
106return value is considered instead."
107 :version "24.4"
108 :group 'electricity
109 :type '(choice
110 (const :tag "Yes" t)
111 (const :tag "No" nil)
112 function))
113
114(defcustom electric-pair-open-newline-between-pairs t
115 "If non-nil, a newline between adjacent parentheses opens an extra one.
116
117Can also be a function of no arguments, in which case that function's
118return value is considered instead."
119 :version "24.4"
120 :group 'electricity
121 :type '(choice
122 (const :tag "Yes" t)
123 (const :tag "No" nil)
124 function))
125
126(defcustom electric-pair-skip-whitespace t
127 "If non-nil skip whitespace when skipping over closing parens.
128
129The specific kind of whitespace skipped is given by the variable
130`electric-pair-skip-whitespace-chars'.
131
132The symbol `chomp' specifies that the skipped-over whitespace
133should be deleted.
134
135Can also be a function of no arguments, in which case that function's
136return value is considered instead."
137 :version "24.4"
138 :group 'electricity
139 :type '(choice
140 (const :tag "Yes, jump over whitespace" t)
141 (const :tag "Yes, and delete whitespace" 'chomp)
142 (const :tag "No, no whitespace skipping" nil)
143 function))
144
145(defcustom electric-pair-skip-whitespace-chars (list ?\t ?\s ?\n)
146 "Whitespace characters considered by `electric-pair-skip-whitespace'."
147 :version "24.4"
148 :group 'electricity
149 :type '(choice (set (const :tag "Space" ?\s)
150 (const :tag "Tab" ?\t)
151 (const :tag "Newline" ?\n))
152 (list character)))
153
154(defun electric-pair--skip-whitespace ()
155 "Skip whitespace forward, not crossing comment or string boundaries."
156 (let ((saved (point))
157 (string-or-comment (nth 8 (syntax-ppss))))
158 (skip-chars-forward (apply #'string electric-pair-skip-whitespace-chars))
159 (unless (eq string-or-comment (nth 8 (syntax-ppss)))
160 (goto-char saved))))
161
162(defvar electric-pair-text-syntax-table prog-mode-syntax-table
163 "Syntax table used when pairing inside comments and strings.
164
165`electric-pair-mode' considers this syntax table only when point in inside
166quotes or comments. If lookup fails here, `electric-pair-text-pairs' will
167be considered.")
168
169(defun electric-pair-backward-delete-char (n &optional killflag untabify)
170 "Delete characters backward, and maybe also two adjacent paired delimiters.
171
172Remaining behaviour is given by `backward-delete-char' or, if UNTABIFY is
173non-nil, `backward-delete-char-untabify'."
174 (interactive "*p\nP")
175 (let* ((prev (char-before))
176 (next (char-after))
177 (syntax-info (electric-pair-syntax-info prev))
178 (syntax (car syntax-info))
179 (pair (cadr syntax-info)))
180 (when (and (if (functionp electric-pair-delete-adjacent-pairs)
181 (funcall electric-pair-delete-adjacent-pairs)
182 electric-pair-delete-adjacent-pairs)
183 next
184 (memq syntax '(?\( ?\" ?\$))
185 (eq pair next))
186 (delete-char 1 killflag))
187 (if untabify
188 (backward-delete-char-untabify n killflag)
189 (backward-delete-char n killflag))))
190
191(defun electric-pair-backward-delete-char-untabify (n &optional killflag)
192 "Delete characters backward, and maybe also two adjacent paired delimiters.
193
194Remaining behaviour is given by `backward-delete-char-untabify'."
195 (interactive "*p\nP")
196 (electric-pair-backward-delete-char n killflag t))
197
198(defun electric-pair-conservative-inhibit (char)
199 (or
200 ;; I find it more often preferable not to pair when the
201 ;; same char is next.
202 (eq char (char-after))
203 ;; Don't pair up when we insert the second of "" or of ((.
204 (and (eq char (char-before))
205 (eq char (char-before (1- (point)))))
206 ;; I also find it often preferable not to pair next to a word.
207 (eq (char-syntax (following-char)) ?w)))
208
209(defun electric-pair-syntax-info (command-event)
210 "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START).
211
212SYNTAX is COMMAND-EVENT's syntax character. PAIR is
213COMMAND-EVENT's pair. UNCONDITIONAL indicates the variables
214`electric-pair-pairs' or `electric-pair-text-pairs' were used to
215lookup syntax. STRING-OR-COMMENT-START indicates that point is
216inside a comment of string."
217 (let* ((pre-string-or-comment (nth 8 (save-excursion
218 (syntax-ppss (1- (point))))))
219 (post-string-or-comment (nth 8 (syntax-ppss (point))))
220 (string-or-comment (and post-string-or-comment
221 pre-string-or-comment))
222 (table (if string-or-comment
223 electric-pair-text-syntax-table
224 (syntax-table)))
225 (table-syntax-and-pair (with-syntax-table table
226 (list (char-syntax command-event)
227 (or (matching-paren command-event)
228 command-event))))
229 (fallback (if string-or-comment
230 (append electric-pair-text-pairs
231 electric-pair-pairs)
232 electric-pair-pairs))
233 (direct (assq command-event fallback))
234 (reverse (rassq command-event fallback)))
235 (cond
236 ((memq (car table-syntax-and-pair)
237 '(?\" ?\( ?\) ?\$))
238 (append table-syntax-and-pair (list nil string-or-comment)))
239 (direct (if (eq (car direct) (cdr direct))
240 (list ?\" command-event t string-or-comment)
241 (list ?\( (cdr direct) t string-or-comment)))
242 (reverse (list ?\) (car reverse) t string-or-comment)))))
243
244(defun electric-pair--insert (char)
245 (let ((last-command-event char)
246 (blink-matching-paren nil)
247 (electric-pair-mode nil))
248 (self-insert-command 1)))
249
250(defun electric-pair--syntax-ppss (&optional pos where)
251 "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
252
253WHERE is list defaulting to '(string comment) and indicates
254when to fallback to `parse-partial-sexp'."
255 (let* ((pos (or pos (point)))
256 (where (or where '(string comment)))
257 (quick-ppss (syntax-ppss))
258 (quick-ppss-at-pos (syntax-ppss pos)))
259 (if (or (and (nth 3 quick-ppss) (memq 'string where))
260 (and (nth 4 quick-ppss) (memq 'comment where)))
261 (with-syntax-table electric-pair-text-syntax-table
262 (parse-partial-sexp (1+ (nth 8 quick-ppss)) pos))
263 ;; HACK! cc-mode apparently has some `syntax-ppss' bugs
264 (if (memq major-mode '(c-mode c++ mode))
265 (parse-partial-sexp (point-min) pos)
266 quick-ppss-at-pos))))
267
268;; Balancing means controlling pairing and skipping of parentheses so
269;; that, if possible, the buffer ends up at least as balanced as
270;; before, if not more. The algorithm is slightly complex because some
271;; situations like "()))" need pairing to occur at the end but not at
272;; the beginning. Balancing should also happen independently for
273;; different types of parentheses, so that having your {}'s unbalanced
274;; doesn't keep `electric-pair-mode' from balancing your ()'s and your
275;; []'s.
276(defun electric-pair--balance-info (direction string-or-comment)
277 "Examine lists forward or backward according to DIRECTIONS's sign.
278
279STRING-OR-COMMENT is info suitable for running `parse-partial-sexp'.
280
281Return a cons of two descritions (MATCHED-P . PAIR) for the
282innermost and outermost lists that enclose point. The outermost
283list enclosing point is either the first top-level or first
284mismatched list found by uplisting.
285
286If the outermost list is matched, don't rely on its PAIR. If
287point is not enclosed by any lists, return ((T) (T))."
288 (let* (innermost
289 outermost
290 (table (if string-or-comment
291 electric-pair-text-syntax-table
292 (syntax-table)))
293 (at-top-level-or-equivalent-fn
294 ;; called when `scan-sexps' ran perfectly, when when it
295 ;; found a parenthesis pointing in the direction of
296 ;; travel. Also when travel started inside a comment and
297 ;; exited it
298 #'(lambda ()
299 (setq outermost (list t))
300 (unless innermost
301 (setq innermost (list t)))))
302 (ended-prematurely-fn
303 ;; called when `scan-sexps' crashed against a parenthesis
304 ;; pointing opposite the direction of travel. After
305 ;; traversing that character, the idea is to travel one sexp
306 ;; in the opposite direction looking for a matching
307 ;; delimiter.
308 #'(lambda ()
309 (let* ((pos (point))
310 (matched
311 (save-excursion
312 (cond ((< direction 0)
313 (condition-case nil
314 (eq (char-after pos)
315 (with-syntax-table table
316 (matching-paren
317 (char-before
318 (scan-sexps (point) 1)))))
319 (scan-error nil)))
320 (t
321 ;; In this case, no need to use
322 ;; `scan-sexps', we can use some
323 ;; `electric-pair--syntax-ppss' in this
324 ;; case (which uses the quicker
325 ;; `syntax-ppss' in some cases)
326 (let* ((ppss (electric-pair--syntax-ppss
327 (1- (point))))
328 (start (car (last (nth 9 ppss))))
329 (opener (char-after start)))
330 (and start
331 (eq (char-before pos)
332 (or (with-syntax-table table
333 (matching-paren opener))
334 opener))))))))
335 (actual-pair (if (> direction 0)
336 (char-before (point))
337 (char-after (point)))))
338 (unless innermost
339 (setq innermost (cons matched actual-pair)))
340 (unless matched
341 (setq outermost (cons matched actual-pair)))))))
342 (save-excursion
343 (while (not outermost)
344 (condition-case err
345 (with-syntax-table table
346 (scan-sexps (point) (if (> direction 0)
347 (point-max)
348 (- (point-max))))
349 (funcall at-top-level-or-equivalent-fn))
350 (scan-error
351 (cond ((or
352 ;; some error happened and it is not of the "ended
353 ;; prematurely" kind"...
354 (not (string-match "ends prematurely" (nth 1 err)))
355 ;; ... or we were in a comment and just came out of
356 ;; it.
357 (and string-or-comment
358 (not (nth 8 (syntax-ppss)))))
359 (funcall at-top-level-or-equivalent-fn))
360 (t
361 ;; exit the sexp
362 (goto-char (nth 3 err))
363 (funcall ended-prematurely-fn)))))))
364 (cons innermost outermost)))
365
366(defun electric-pair--looking-at-unterminated-string-p (char)
367 "Say if following string starts with CHAR and is unterminated."
368 ;; FIXME: ugly/naive
369 (save-excursion
370 (skip-chars-forward (format "^%c" char))
371 (while (not (zerop (% (save-excursion (skip-syntax-backward "\\")) 2)))
372 (unless (eobp)
373 (forward-char 1)
374 (skip-chars-forward (format "^%c" char))))
375 (and (not (eobp))
376 (condition-case nil
377 (progn (forward-sexp) nil)
378 (scan-error t)))))
379
380(defun electric-pair--inside-string-p (char)
381 "Say if point is inside a string started by CHAR.
382
383A comments text is parsed with `electric-pair-text-syntax-table'.
384Also consider strings within comments, but not strings within
385strings."
386 ;; FIXME: could also consider strings within strings by examining
387 ;; delimiters.
388 (let* ((ppss (electric-pair--syntax-ppss (point) '(comment))))
389 (memq (nth 3 ppss) (list t char))))
390
391(defun electric-pair-inhibit-if-helps-balance (char)
392 "Return non-nil if auto-pairing of CHAR would hurt parentheses' balance.
393
394Works by first removing the character from the buffer, then doing
395some list calculations, finally restoring the situation as if nothing
396happened."
397 (pcase (electric-pair-syntax-info char)
398 (`(,syntax ,pair ,_ ,s-or-c)
399 (unwind-protect
400 (progn
401 (delete-char -1)
402 (cond ((eq ?\( syntax)
403 (let* ((pair-data
404 (electric-pair--balance-info 1 s-or-c))
405 (outermost (cdr pair-data)))
406 (cond ((car outermost)
407 nil)
408 (t
409 (eq (cdr outermost) pair)))))
410 ((eq syntax ?\")
411 (electric-pair--looking-at-unterminated-string-p char))))
412 (insert-char char)))))
413
414(defun electric-pair-skip-if-helps-balance (char)
415 "Return non-nil if skipping CHAR would benefit parentheses' balance.
416
417Works by first removing the character from the buffer, then doing
418some list calculations, finally restoring the situation as if nothing
419happened."
420 (pcase (electric-pair-syntax-info char)
421 (`(,syntax ,pair ,_ ,s-or-c)
422 (unwind-protect
423 (progn
424 (delete-char -1)
425 (cond ((eq syntax ?\))
426 (let* ((pair-data
427 (electric-pair--balance-info
428 -1 s-or-c))
429 (innermost (car pair-data))
430 (outermost (cdr pair-data)))
431 (and
432 (cond ((car outermost)
433 (car innermost))
434 ((car innermost)
435 (not (eq (cdr outermost) pair)))))))
436 ((eq syntax ?\")
437 (electric-pair--inside-string-p char))))
438 (insert-char char)))))
439
440(defun electric-pair-default-skip-self (char)
441 (if electric-pair-preserve-balance
442 (electric-pair-skip-if-helps-balance char)
443 t))
444
445(defun electric-pair-default-inhibit (char)
446 (if electric-pair-preserve-balance
447 (electric-pair-inhibit-if-helps-balance char)
448 (electric-pair-conservative-inhibit char)))
449
450(defun electric-pair-post-self-insert-function ()
451 (let* ((pos (and electric-pair-mode (electric--after-char-pos)))
452 (skip-whitespace-info))
453 (pcase (electric-pair-syntax-info last-command-event)
454 (`(,syntax ,pair ,unconditional ,_)
455 (cond
456 ((null pos) nil)
457 ;; Wrap a pair around the active region.
458 ;;
459 ((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
460 ;; FIXME: To do this right, we'd need a post-self-insert-function
461 ;; so we could add-function around it and insert the closer after
462 ;; all the rest of the hook has run.
463 (if (or (eq syntax ?\")
464 (and (eq syntax ?\))
465 (>= (point) (mark)))
466 (and (not (eq syntax ?\)))
467 (>= (mark) (point))))
468 (save-excursion
469 (goto-char (mark))
470 (electric-pair--insert pair))
471 (delete-region pos (1- pos))
472 (electric-pair--insert pair)
473 (goto-char (mark))
474 (electric-pair--insert last-command-event)))
475 ;; Backslash-escaped: no pairing, no skipping.
476 ((save-excursion
477 (goto-char (1- pos))
478 (not (zerop (% (skip-syntax-backward "\\") 2))))
479 nil)
480 ;; Skip self.
481 ((and (memq syntax '(?\) ?\" ?\$))
482 (and (or unconditional
483 (if (functionp electric-pair-skip-self)
484 (funcall electric-pair-skip-self last-command-event)
485 electric-pair-skip-self))
486 (save-excursion
487 (when (setq skip-whitespace-info
488 (if (functionp electric-pair-skip-whitespace)
489 (funcall electric-pair-skip-whitespace)
490 electric-pair-skip-whitespace))
491 (electric-pair--skip-whitespace))
492 (eq (char-after) last-command-event))))
493 ;; This is too late: rather than insert&delete we'd want to only
494 ;; skip (or insert in overwrite mode). The difference is in what
495 ;; goes in the undo-log and in the intermediate state which might
496 ;; be visible to other post-self-insert-hook. We'll just have to
497 ;; live with it for now.
498 (when skip-whitespace-info
499 (electric-pair--skip-whitespace))
500 (delete-region (1- pos) (if (eq skip-whitespace-info 'chomp)
501 (point)
502 pos))
503 (forward-char))
504 ;; Insert matching pair.
505 ((and (memq syntax `(?\( ?\" ?\$))
506 (not overwrite-mode)
507 (or unconditional
508 (not (funcall electric-pair-inhibit-predicate
509 last-command-event))))
510 (save-excursion (electric-pair--insert pair)))))
511 (t
512 (when (and (if (functionp electric-pair-open-newline-between-pairs)
513 (funcall electric-pair-open-newline-between-pairs)
514 electric-pair-open-newline-between-pairs)
515 (eq last-command-event ?\n)
516 (not (eobp))
517 (eq (save-excursion
518 (skip-chars-backward "\t\s")
519 (char-before (1- (point))))
520 (matching-paren (char-after))))
521 (save-excursion (newline 1 t)))))))
522
523(put 'electric-pair-post-self-insert-function 'priority 20)
524
525(defun electric-pair-will-use-region ()
526 (and (use-region-p)
527 (memq (car (electric-pair-syntax-info last-command-event))
528 '(?\( ?\) ?\" ?\$))))
529
530(defvar electric-pair-mode-map
531 (let ((map (make-sparse-keymap)))
532 (define-key map [remap backward-delete-char-untabify]
533 'electric-pair-backward-delete-char-untabify)
534 (define-key map [remap backward-delete-char]
535 'electric-pair-backward-delete-char)
536 (define-key map [remap delete-backward-char]
537 'electric-pair-backward-delete-char)
538 map)
539 "Keymap used by `electric-pair-mode'.")
540
541;;;###autoload
542(define-minor-mode electric-pair-mode
543 "Toggle automatic parens pairing (Electric Pair mode).
544With a prefix argument ARG, enable Electric Pair mode if ARG is
545positive, and disable it otherwise. If called from Lisp, enable
546the mode if ARG is omitted or nil.
547
548Electric Pair mode is a global minor mode. When enabled, typing
549an open parenthesis automatically inserts the corresponding
550closing parenthesis. \(Likewise for brackets, etc.)."
551 :global t :group 'electricity
552 (if electric-pair-mode
553 (progn
554 (add-hook 'post-self-insert-hook
555 #'electric-pair-post-self-insert-function)
556 (electric--sort-post-self-insertion-hook)
557 (add-hook 'self-insert-uses-region-functions
558 #'electric-pair-will-use-region))
559 (remove-hook 'post-self-insert-hook
560 #'electric-pair-post-self-insert-function)
561 (remove-hook 'self-insert-uses-region-functions
562 #'electric-pair-will-use-region)))
563
564(provide 'elec-pair)
565
566;;; elec-pair.el ends here
diff --git a/lisp/electric.el b/lisp/electric.el
index fc5e63f90bb..9e9a25213e8 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -325,533 +325,6 @@ insert a character from `electric-indent-chars'."
325 (setq-default electric-indent-mode nil) ; But keep it globally disabled. 325 (setq-default electric-indent-mode nil) ; But keep it globally disabled.
326 ))) 326 )))
327 327
328;;; Electric pairing.
329
330(defcustom electric-pair-pairs
331 '((?\" . ?\"))
332 "Alist of pairs that should be used regardless of major mode.
333
334Pairs of delimiters in this list are a fallback in case they have
335no syntax relevant to `electric-pair-mode' in the mode's syntax
336table.
337
338See also the variable `electric-pair-text-pairs'."
339 :version "24.1"
340 :type '(repeat (cons character character)))
341
342(defcustom electric-pair-text-pairs
343 '((?\" . ?\" ))
344 "Alist of pairs that should always be used in comments and strings.
345
346Pairs of delimiters in this list are a fallback in case they have
347no syntax relevant to `electric-pair-mode' in the syntax table
348defined in `electric-pair-text-syntax-table'"
349 :version "24.4"
350 :type '(repeat (cons character character)))
351
352(defcustom electric-pair-skip-self #'electric-pair-default-skip-self
353 "If non-nil, skip char instead of inserting a second closing paren.
354
355When inserting a closing paren character right before the same character,
356just skip that character instead, so that hitting ( followed by ) results
357in \"()\" rather than \"())\".
358
359This can be convenient for people who find it easier to hit ) than C-f.
360
361Can also be a function of one argument (the closer char just
362inserted), in which case that function's return value is
363considered instead."
364 :version "24.1"
365 :type '(choice
366 (const :tag "Never skip" nil)
367 (const :tag "Help balance" electric-pair-default-skip-self)
368 (const :tag "Always skip" t)
369 function))
370
371(defcustom electric-pair-inhibit-predicate
372 #'electric-pair-default-inhibit
373 "Predicate to prevent insertion of a matching pair.
374
375The function is called with a single char (the opening char just inserted).
376If it returns non-nil, then `electric-pair-mode' will not insert a matching
377closer."
378 :version "24.4"
379 :type '(choice
380 (const :tag "Conservative" electric-pair-conservative-inhibit)
381 (const :tag "Help balance" electric-pair-default-inhibit)
382 (const :tag "Always pair" ignore)
383 function))
384
385(defcustom electric-pair-preserve-balance t
386 "Non-nil if default pairing and skipping should help balance parentheses.
387
388The default values of `electric-pair-inhibit-predicate' and
389`electric-pair-skip-self' check this variable before delegating to other
390predicates reponsible for making decisions on whether to pair/skip some
391characters based on the actual state of the buffer's parenthesis and
392quotes."
393 :version "24.4"
394 :type 'boolean)
395
396(defcustom electric-pair-delete-adjacent-pairs t
397 "If non-nil, backspacing an open paren also deletes adjacent closer.
398
399Can also be a function of no arguments, in which case that function's
400return value is considered instead."
401 :version "24.4"
402 :type '(choice
403 (const :tag "Yes" t)
404 (const :tag "No" nil)
405 function))
406
407(defcustom electric-pair-open-newline-between-pairs t
408 "If non-nil, a newline between adjacent parentheses opens an extra one.
409
410Can also be a function of no arguments, in which case that function's
411return value is considered instead."
412 :version "24.4"
413 :type '(choice
414 (const :tag "Yes" t)
415 (const :tag "No" nil)
416 function))
417
418(defcustom electric-pair-skip-whitespace t
419 "If non-nil skip whitespace when skipping over closing parens.
420
421The specific kind of whitespace skipped is given by the variable
422`electric-pair-skip-whitespace-chars'.
423
424The symbol `chomp' specifies that the skipped-over whitespace
425should be deleted.
426
427Can also be a function of no arguments, in which case that function's
428return value is considered instead."
429 :version "24.4"
430 :type '(choice
431 (const :tag "Yes, jump over whitespace" t)
432 (const :tag "Yes, and delete whitespace" 'chomp)
433 (const :tag "No, no whitespace skipping" nil)
434 function))
435
436(defcustom electric-pair-skip-whitespace-chars (list ?\t ?\s ?\n)
437 "Whitespace characters considered by `electric-pair-skip-whitespace'."
438 :version "24.4"
439 :type '(choice (set (const :tag "Space" ?\s)
440 (const :tag "Tab" ?\t)
441 (const :tag "Newline" ?\n))
442 (list character)))
443
444(defun electric-pair--skip-whitespace ()
445 "Skip whitespace forward, not crossing comment or string boundaries."
446 (let ((saved (point))
447 (string-or-comment (nth 8 (syntax-ppss))))
448 (skip-chars-forward (apply #'string electric-pair-skip-whitespace-chars))
449 (unless (eq string-or-comment (nth 8 (syntax-ppss)))
450 (goto-char saved))))
451
452(defvar electric-pair-text-syntax-table prog-mode-syntax-table
453 "Syntax table used when pairing inside comments and strings.
454
455`electric-pair-mode' considers this syntax table only when point in inside
456quotes or comments. If lookup fails here, `electric-pair-text-pairs' will
457be considered.")
458
459(defun electric-pair-backward-delete-char (n &optional killflag untabify)
460 "Delete characters backward, and maybe also two adjacent paired delimiters.
461
462Remaining behaviour is given by `backward-delete-char' or, if UNTABIFY is
463non-nil, `backward-delete-char-untabify'."
464 (interactive "*p\nP")
465 (let* ((prev (char-before))
466 (next (char-after))
467 (syntax-info (electric-pair-syntax-info prev))
468 (syntax (car syntax-info))
469 (pair (cadr syntax-info)))
470 (when (and (if (functionp electric-pair-delete-adjacent-pairs)
471 (funcall electric-pair-delete-adjacent-pairs)
472 electric-pair-delete-adjacent-pairs)
473 next
474 (memq syntax '(?\( ?\" ?\$))
475 (eq pair next))
476 (delete-char 1 killflag))
477 (if untabify
478 (backward-delete-char-untabify n killflag)
479 (backward-delete-char n killflag))))
480
481(defun electric-pair-backward-delete-char-untabify (n &optional killflag)
482 "Delete characters backward, and maybe also two adjacent paired delimiters.
483
484Remaining behaviour is given by `backward-delete-char-untabify'."
485 (interactive "*p\nP")
486 (electric-pair-backward-delete-char n killflag t))
487
488(defun electric-pair-conservative-inhibit (char)
489 (or
490 ;; I find it more often preferable not to pair when the
491 ;; same char is next.
492 (eq char (char-after))
493 ;; Don't pair up when we insert the second of "" or of ((.
494 (and (eq char (char-before))
495 (eq char (char-before (1- (point)))))
496 ;; I also find it often preferable not to pair next to a word.
497 (eq (char-syntax (following-char)) ?w)))
498
499(defun electric-pair-syntax-info (command-event)
500 "Calculate a list (SYNTAX PAIR UNCONDITIONAL STRING-OR-COMMENT-START).
501
502SYNTAX is COMMAND-EVENT's syntax character. PAIR is
503COMMAND-EVENT's pair. UNCONDITIONAL indicates the variables
504`electric-pair-pairs' or `electric-pair-text-pairs' were used to
505lookup syntax. STRING-OR-COMMENT-START indicates that point is
506inside a comment of string."
507 (let* ((pre-string-or-comment (nth 8 (save-excursion
508 (syntax-ppss (1- (point))))))
509 (post-string-or-comment (nth 8 (syntax-ppss (point))))
510 (string-or-comment (and post-string-or-comment
511 pre-string-or-comment))
512 (table (if string-or-comment
513 electric-pair-text-syntax-table
514 (syntax-table)))
515 (table-syntax-and-pair (with-syntax-table table
516 (list (char-syntax command-event)
517 (or (matching-paren command-event)
518 command-event))))
519 (fallback (if string-or-comment
520 (append electric-pair-text-pairs
521 electric-pair-pairs)
522 electric-pair-pairs))
523 (direct (assq command-event fallback))
524 (reverse (rassq command-event fallback)))
525 (cond
526 ((memq (car table-syntax-and-pair)
527 '(?\" ?\( ?\) ?\$))
528 (append table-syntax-and-pair (list nil string-or-comment)))
529 (direct (if (eq (car direct) (cdr direct))
530 (list ?\" command-event t string-or-comment)
531 (list ?\( (cdr direct) t string-or-comment)))
532 (reverse (list ?\) (car reverse) t string-or-comment)))))
533
534(defun electric-pair--insert (char)
535 (let ((last-command-event char)
536 (blink-matching-paren nil)
537 (electric-pair-mode nil))
538 (self-insert-command 1)))
539
540(defun electric-pair--syntax-ppss (&optional pos where)
541 "Like `syntax-ppss', but sometimes fallback to `parse-partial-sexp'.
542
543WHERE is list defaulting to '(string comment) and indicates
544when to fallback to `parse-partial-sexp'."
545 (let* ((pos (or pos (point)))
546 (where (or where '(string comment)))
547 (quick-ppss (syntax-ppss))
548 (quick-ppss-at-pos (syntax-ppss pos)))
549 (if (or (and (nth 3 quick-ppss) (memq 'string where))
550 (and (nth 4 quick-ppss) (memq 'comment where)))
551 (with-syntax-table electric-pair-text-syntax-table
552 (parse-partial-sexp (1+ (nth 8 quick-ppss)) pos))
553 ;; HACK! cc-mode apparently has some `syntax-ppss' bugs
554 (if (memq major-mode '(c-mode c++ mode))
555 (parse-partial-sexp (point-min) pos)
556 quick-ppss-at-pos))))
557
558;; Balancing means controlling pairing and skipping of parentheses so
559;; that, if possible, the buffer ends up at least as balanced as
560;; before, if not more. The algorithm is slightly complex because some
561;; situations like "()))" need pairing to occur at the end but not at
562;; the beginning. Balancing should also happen independently for
563;; different types of parentheses, so that having your {}'s unbalanced
564;; doesn't keep `electric-pair-mode' from balancing your ()'s and your
565;; []'s.
566(defun electric-pair--balance-info (direction string-or-comment)
567 "Examine lists forward or backward according to DIRECTIONS's sign.
568
569STRING-OR-COMMENT is info suitable for running `parse-partial-sexp'.
570
571Return a cons of two descritions (MATCHED-P . PAIR) for the
572innermost and outermost lists that enclose point. The outermost
573list enclosing point is either the first top-level or first
574mismatched list found by uplisting.
575
576If the outermost list is matched, don't rely on its PAIR. If
577point is not enclosed by any lists, return ((T) (T))."
578 (let* (innermost
579 outermost
580 (table (if string-or-comment
581 electric-pair-text-syntax-table
582 (syntax-table)))
583 (at-top-level-or-equivalent-fn
584 ;; called when `scan-sexps' ran perfectly, when when it
585 ;; found a parenthesis pointing in the direction of
586 ;; travel. Also when travel started inside a comment and
587 ;; exited it
588 #'(lambda ()
589 (setq outermost (list t))
590 (unless innermost
591 (setq innermost (list t)))))
592 (ended-prematurely-fn
593 ;; called when `scan-sexps' crashed against a parenthesis
594 ;; pointing opposite the direction of travel. After
595 ;; traversing that character, the idea is to travel one sexp
596 ;; in the opposite direction looking for a matching
597 ;; delimiter.
598 #'(lambda ()
599 (let* ((pos (point))
600 (matched
601 (save-excursion
602 (cond ((< direction 0)
603 (condition-case nil
604 (eq (char-after pos)
605 (with-syntax-table table
606 (matching-paren
607 (char-before
608 (scan-sexps (point) 1)))))
609 (scan-error nil)))
610 (t
611 ;; In this case, no need to use
612 ;; `scan-sexps', we can use some
613 ;; `electric-pair--syntax-ppss' in this
614 ;; case (which uses the quicker
615 ;; `syntax-ppss' in some cases)
616 (let* ((ppss (electric-pair--syntax-ppss
617 (1- (point))))
618 (start (car (last (nth 9 ppss))))
619 (opener (char-after start)))
620 (and start
621 (eq (char-before pos)
622 (or (with-syntax-table table
623 (matching-paren opener))
624 opener))))))))
625 (actual-pair (if (> direction 0)
626 (char-before (point))
627 (char-after (point)))))
628 (unless innermost
629 (setq innermost (cons matched actual-pair)))
630 (unless matched
631 (setq outermost (cons matched actual-pair)))))))
632 (save-excursion
633 (while (not outermost)
634 (condition-case err
635 (with-syntax-table table
636 (scan-sexps (point) (if (> direction 0)
637 (point-max)
638 (- (point-max))))
639 (funcall at-top-level-or-equivalent-fn))
640 (scan-error
641 (cond ((or
642 ;; some error happened and it is not of the "ended
643 ;; prematurely" kind"...
644 (not (string-match "ends prematurely" (nth 1 err)))
645 ;; ... or we were in a comment and just came out of
646 ;; it.
647 (and string-or-comment
648 (not (nth 8 (syntax-ppss)))))
649 (funcall at-top-level-or-equivalent-fn))
650 (t
651 ;; exit the sexp
652 (goto-char (nth 3 err))
653 (funcall ended-prematurely-fn)))))))
654 (cons innermost outermost)))
655
656(defun electric-pair--looking-at-unterminated-string-p (char)
657 "Say if following string starts with CHAR and is unterminated."
658 ;; FIXME: ugly/naive
659 (save-excursion
660 (skip-chars-forward (format "^%c" char))
661 (while (not (zerop (% (save-excursion (skip-syntax-backward "\\")) 2)))
662 (unless (eobp)
663 (forward-char 1)
664 (skip-chars-forward (format "^%c" char))))
665 (and (not (eobp))
666 (condition-case err
667 (progn (forward-sexp) nil)
668 (scan-error t)))))
669
670(defun electric-pair--inside-string-p (char)
671 "Say if point is inside a string started by CHAR.
672
673A comments text is parsed with `electric-pair-text-syntax-table'.
674Also consider strings within comments, but not strings within
675strings."
676 ;; FIXME: could also consider strings within strings by examining
677 ;; delimiters.
678 (let* ((ppss (electric-pair--syntax-ppss (point) '(comment))))
679 (memq (nth 3 ppss) (list t char))))
680
681(defun electric-pair-inhibit-if-helps-balance (char)
682 "Return non-nil if auto-pairing of CHAR would hurt parentheses' balance.
683
684Works by first removing the character from the buffer, then doing
685some list calculations, finally restoring the situation as if nothing
686happened."
687 (pcase (electric-pair-syntax-info char)
688 (`(,syntax ,pair ,_ ,s-or-c)
689 (unwind-protect
690 (progn
691 (delete-char -1)
692 (cond ((eq ?\( syntax)
693 (let* ((pair-data
694 (electric-pair--balance-info 1 s-or-c))
695 (innermost (car pair-data))
696 (outermost (cdr pair-data)))
697 (cond ((car outermost)
698 nil)
699 (t
700 (eq (cdr outermost) pair)))))
701 ((eq syntax ?\")
702 (electric-pair--looking-at-unterminated-string-p char))))
703 (insert-char char)))))
704
705(defun electric-pair-skip-if-helps-balance (char)
706 "Return non-nil if skipping CHAR would benefit parentheses' balance.
707
708Works by first removing the character from the buffer, then doing
709some list calculations, finally restoring the situation as if nothing
710happened."
711 (pcase (electric-pair-syntax-info char)
712 (`(,syntax ,pair ,_ ,s-or-c)
713 (unwind-protect
714 (progn
715 (delete-char -1)
716 (cond ((eq syntax ?\))
717 (let* ((pair-data
718 (electric-pair--balance-info
719 -1 s-or-c))
720 (innermost (car pair-data))
721 (outermost (cdr pair-data)))
722 (and
723 (cond ((car outermost)
724 (car innermost))
725 ((car innermost)
726 (not (eq (cdr outermost) pair)))))))
727 ((eq syntax ?\")
728 (electric-pair--inside-string-p char))))
729 (insert-char char)))))
730
731(defun electric-pair-default-skip-self (char)
732 (if electric-pair-preserve-balance
733 (electric-pair-skip-if-helps-balance char)
734 t))
735
736(defun electric-pair-default-inhibit (char)
737 (if electric-pair-preserve-balance
738 (electric-pair-inhibit-if-helps-balance char)
739 (electric-pair-conservative-inhibit char)))
740
741(defun electric-pair-post-self-insert-function ()
742 (let* ((pos (and electric-pair-mode (electric--after-char-pos)))
743 (skip-whitespace-info))
744 (pcase (electric-pair-syntax-info last-command-event)
745 (`(,syntax ,pair ,unconditional ,_)
746 (cond
747 ((null pos) nil)
748 ;; Wrap a pair around the active region.
749 ;;
750 ((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
751 ;; FIXME: To do this right, we'd need a post-self-insert-function
752 ;; so we could add-function around it and insert the closer after
753 ;; all the rest of the hook has run.
754 (if (or (eq syntax ?\")
755 (and (eq syntax ?\))
756 (>= (point) (mark)))
757 (and (not (eq syntax ?\)))
758 (>= (mark) (point))))
759 (save-excursion
760 (goto-char (mark))
761 (electric-pair--insert pair))
762 (delete-region pos (1- pos))
763 (electric-pair--insert pair)
764 (goto-char (mark))
765 (electric-pair--insert last-command-event)))
766 ;; Backslash-escaped: no pairing, no skipping.
767 ((save-excursion
768 (goto-char (1- pos))
769 (not (zerop (% (skip-syntax-backward "\\") 2))))
770 nil)
771 ;; Skip self.
772 ((and (memq syntax '(?\) ?\" ?\$))
773 (and (or unconditional
774 (if (functionp electric-pair-skip-self)
775 (funcall electric-pair-skip-self last-command-event)
776 electric-pair-skip-self))
777 (save-excursion
778 (when (setq skip-whitespace-info
779 (if (functionp electric-pair-skip-whitespace)
780 (funcall electric-pair-skip-whitespace)
781 electric-pair-skip-whitespace))
782 (electric-pair--skip-whitespace))
783 (eq (char-after) last-command-event))))
784 ;; This is too late: rather than insert&delete we'd want to only
785 ;; skip (or insert in overwrite mode). The difference is in what
786 ;; goes in the undo-log and in the intermediate state which might
787 ;; be visible to other post-self-insert-hook. We'll just have to
788 ;; live with it for now.
789 (when skip-whitespace-info
790 (electric-pair--skip-whitespace))
791 (delete-region (1- pos) (if (eq skip-whitespace-info 'chomp)
792 (point)
793 pos))
794 (forward-char))
795 ;; Insert matching pair.
796 ((and (memq syntax `(?\( ?\" ?\$))
797 (not overwrite-mode)
798 (or unconditional
799 (not (funcall electric-pair-inhibit-predicate
800 last-command-event))))
801 (save-excursion (electric-pair--insert pair)))))
802 (t
803 (when (and (if (functionp electric-pair-open-newline-between-pairs)
804 (funcall electric-pair-open-newline-between-pairs)
805 electric-pair-open-newline-between-pairs)
806 (eq last-command-event ?\n)
807 (not (eobp))
808 (eq (save-excursion
809 (skip-chars-backward "\t\s")
810 (char-before (1- (point))))
811 (matching-paren (char-after))))
812 (save-excursion (newline 1 t)))))))
813
814(put 'electric-pair-post-self-insert-function 'priority 20)
815
816(defun electric-pair-will-use-region ()
817 (and (use-region-p)
818 (memq (car (electric-pair-syntax-info last-command-event))
819 '(?\( ?\) ?\" ?\$))))
820
821(defvar electric-pair-mode-map
822 (let ((map (make-sparse-keymap)))
823 (define-key map [remap backward-delete-char-untabify]
824 'electric-pair-backward-delete-char-untabify)
825 (define-key map [remap backward-delete-char]
826 'electric-pair-backward-delete-char)
827 (define-key map [remap delete-backward-char]
828 'electric-pair-backward-delete-char)
829 map)
830 "Keymap used by `electric-pair-mode'.")
831
832;;;###autoload
833(define-minor-mode electric-pair-mode
834 "Toggle automatic parens pairing (Electric Pair mode).
835With a prefix argument ARG, enable Electric Pair mode if ARG is
836positive, and disable it otherwise. If called from Lisp, enable
837the mode if ARG is omitted or nil.
838
839Electric Pair mode is a global minor mode. When enabled, typing
840an open parenthesis automatically inserts the corresponding
841closing parenthesis. \(Likewise for brackets, etc.)."
842 :global t :group 'electricity
843 (if electric-pair-mode
844 (progn
845 (add-hook 'post-self-insert-hook
846 #'electric-pair-post-self-insert-function)
847 (electric--sort-post-self-insertion-hook)
848 (add-hook 'self-insert-uses-region-functions
849 #'electric-pair-will-use-region))
850 (remove-hook 'post-self-insert-hook
851 #'electric-pair-post-self-insert-function)
852 (remove-hook 'self-insert-uses-region-functions
853 #'electric-pair-will-use-region)))
854
855;;; Electric newlines after/before/around some chars. 328;;; Electric newlines after/before/around some chars.
856 329
857(defvar electric-layout-rules nil 330(defvar electric-layout-rules nil