aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorJoão Távora2013-12-26 22:02:49 +0000
committerJoão Távora2013-12-26 22:02:49 +0000
commit3b8d5131a316ad2fdc206744cec489a11f0bf1d3 (patch)
tree7a717cd2152141fdd7e5abe20926c7c0d4092869 /lisp
parentfbcc63a3176389f39cb06f5a56f2abb29b06eaab (diff)
downloademacs-3b8d5131a316ad2fdc206744cec489a11f0bf1d3.tar.gz
emacs-3b8d5131a316ad2fdc206744cec489a11f0bf1d3.zip
Make Electric Pair mode smarter/more useful:
* lisp/electric.el: Pairing/skipping helps preserve balance. Autobackspacing behaviour. Opens extra newlines between pairs. Skip whitespace before closing delimiters. * lisp/emacs-lisp/lisp-mode.el (lisp-mode-variables): Use new features. * test/automated/electric-tests.lisp: New file. * doc/emacs/programs.texi: Describe new features. * lisp/simple.el: Pass non-nil interactive arg to newline call inside newline-and-indent.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog22
-rw-r--r--lisp/electric.el599
-rw-r--r--lisp/emacs-lisp/lisp-mode.el8
-rw-r--r--lisp/simple.el8
4 files changed, 542 insertions, 95 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 972106bd26f..2831988efd9 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,25 @@
12013-12-26 João Távora <joaotavora@gmail.com>
2
3 * electric.el (electric-pair-mode): More flexible engine for skip-
4 and inhibit predicates, new options for pairing-related
5 functionality.
6 (electric-pair-preserve-balance): Pair/skip parentheses and quotes
7 if that keeps or improves their balance in buffers.
8 (electric-pair-delete-adjacent-pairs): Delete the pair when
9 backspacing over adjacent matched delimiters.
10 (electric-pair-open-extra-newline): Open extra newline when
11 inserting newlines between adjacent matched delimiters.
12 (electric--sort-post-self-insertion-hook): Sort
13 post-self-insert-hook according to priority values when
14 minor-modes are activated.
15 * simple.el (newline-and-indent): Call newline with interactive
16 set to t.
17 (blink-paren-post-self-insert-function): Set priority to 100.
18 * emacs-lisp/lisp-mode.el (lisp-mode-variables): Use
19 electric-pair-text-pairs to pair backtick-and-quote in strings and
20 comments. Locally set electric-pair-skip-whitespace to 'chomp and
21 electric-pair-open-newline-between-pairs to nil.
22
12013-12-26 Fabián Ezequiel Gallina <fgallina@gnu.org> 232013-12-26 Fabián Ezequiel Gallina <fgallina@gnu.org>
2 24
3 * progmodes/python.el: Use lexical-binding. 25 * progmodes/python.el: Use lexical-binding.
diff --git a/lisp/electric.el b/lisp/electric.el
index 91b99b4bfe7..fc5e63f90bb 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -187,6 +187,17 @@ Returns nil when we can't find this char."
187 (eq (char-before) last-command-event))))) 187 (eq (char-before) last-command-event)))))
188 pos))) 188 pos)))
189 189
190(defun electric--sort-post-self-insertion-hook ()
191 "Ensure order of electric functions in `post-self-insertion-hook'.
192
193Hooks in this variable interact in non-trivial ways, so a
194relative order must be maintained within it."
195 (setq-default post-self-insert-hook
196 (sort (default-value 'post-self-insert-hook)
197 #'(lambda (fn1 fn2)
198 (< (or (get fn1 'priority) 0)
199 (or (get fn2 'priority) 0))))))
200
190;;; Electric indentation. 201;;; Electric indentation.
191 202
192;; Autoloading variables is generally undesirable, but major modes 203;; Autoloading variables is generally undesirable, but major modes
@@ -267,6 +278,8 @@ mode set `electric-indent-inhibit', but this can be used as a workaround.")
267 (> pos (line-beginning-position))) 278 (> pos (line-beginning-position)))
268 (indent-according-to-mode))))) 279 (indent-according-to-mode)))))
269 280
281(put 'electric-indent-post-self-insert-function 'priority 60)
282
270(defun electric-indent-just-newline (arg) 283(defun electric-indent-just-newline (arg)
271 "Insert just a newline, without any auto-indentation." 284 "Insert just a newline, without any auto-indentation."
272 (interactive "*P") 285 (interactive "*P")
@@ -295,20 +308,9 @@ insert a character from `electric-indent-chars'."
295 #'electric-indent-post-self-insert-function)) 308 #'electric-indent-post-self-insert-function))
296 (when (eq (lookup-key global-map [?\C-j]) 'newline-and-indent) 309 (when (eq (lookup-key global-map [?\C-j]) 'newline-and-indent)
297 (define-key global-map [?\C-j] 'electric-indent-just-newline)) 310 (define-key global-map [?\C-j] 'electric-indent-just-newline))
298 ;; post-self-insert-hooks interact in non-trivial ways.
299 ;; It turns out that electric-indent-mode generally works better if run
300 ;; late, but still before blink-paren.
301 (add-hook 'post-self-insert-hook 311 (add-hook 'post-self-insert-hook
302 #'electric-indent-post-self-insert-function 312 #'electric-indent-post-self-insert-function)
303 'append) 313 (electric--sort-post-self-insertion-hook)))
304 ;; FIXME: Ugly!
305 (let ((bp (memq #'blink-paren-post-self-insert-function
306 (default-value 'post-self-insert-hook))))
307 (when (memq #'electric-indent-post-self-insert-function bp)
308 (setcar bp #'electric-indent-post-self-insert-function)
309 (setcdr bp (cons #'blink-paren-post-self-insert-function
310 (delq #'electric-indent-post-self-insert-function
311 (cdr bp))))))))
312 314
313;;;###autoload 315;;;###autoload
314(define-minor-mode electric-indent-local-mode 316(define-minor-mode electric-indent-local-mode
@@ -327,32 +329,163 @@ insert a character from `electric-indent-chars'."
327 329
328(defcustom electric-pair-pairs 330(defcustom electric-pair-pairs
329 '((?\" . ?\")) 331 '((?\" . ?\"))
330 "Alist of pairs that should be used regardless of major mode." 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'."
331 :version "24.1" 339 :version "24.1"
332 :type '(repeat (cons character character))) 340 :type '(repeat (cons character character)))
333 341
334(defcustom electric-pair-skip-self t 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
335 "If non-nil, skip char instead of inserting a second closing paren. 353 "If non-nil, skip char instead of inserting a second closing paren.
354
336When inserting a closing paren character right before the same character, 355When inserting a closing paren character right before the same character,
337just skip that character instead, so that hitting ( followed by ) results 356just skip that character instead, so that hitting ( followed by ) results
338in \"()\" rather than \"())\". 357in \"()\" rather than \"())\".
339This can be convenient for people who find it easier to hit ) than C-f." 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."
340 :version "24.1" 364 :version "24.1"
341 :type 'boolean) 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))
342 370
343(defcustom electric-pair-inhibit-predicate 371(defcustom electric-pair-inhibit-predicate
344 #'electric-pair-default-inhibit 372 #'electric-pair-default-inhibit
345 "Predicate to prevent insertion of a matching pair. 373 "Predicate to prevent insertion of a matching pair.
374
346The function is called with a single char (the opening char just inserted). 375The function is called with a single char (the opening char just inserted).
347If it returns non-nil, then `electric-pair-mode' will not insert a matching 376If it returns non-nil, then `electric-pair-mode' will not insert a matching
348closer." 377closer."
349 :version "24.4" 378 :version "24.4"
350 :type '(choice 379 :type '(choice
351 (const :tag "Default" electric-pair-default-inhibit) 380 (const :tag "Conservative" electric-pair-conservative-inhibit)
381 (const :tag "Help balance" electric-pair-default-inhibit)
352 (const :tag "Always pair" ignore) 382 (const :tag "Always pair" ignore)
353 function)) 383 function))
354 384
355(defun electric-pair-default-inhibit (char) 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)
356 (or 489 (or
357 ;; I find it more often preferable not to pair when the 490 ;; I find it more often preferable not to pair when the
358 ;; same char is next. 491 ;; same char is next.
@@ -363,14 +496,40 @@ closer."
363 ;; I also find it often preferable not to pair next to a word. 496 ;; I also find it often preferable not to pair next to a word.
364 (eq (char-syntax (following-char)) ?w))) 497 (eq (char-syntax (following-char)) ?w)))
365 498
366(defun electric-pair-syntax (command-event) 499(defun electric-pair-syntax-info (command-event)
367 (let ((x (assq command-event electric-pair-pairs))) 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)))
368 (cond 525 (cond
369 (x (if (eq (car x) (cdr x)) ?\" ?\()) 526 ((memq (car table-syntax-and-pair)
370 ((rassq command-event electric-pair-pairs) ?\)) 527 '(?\" ?\( ?\) ?\$))
371 ((nth 8 (syntax-ppss)) 528 (append table-syntax-and-pair (list nil string-or-comment)))
372 (with-syntax-table text-mode-syntax-table (char-syntax command-event))) 529 (direct (if (eq (car direct) (cdr direct))
373 (t (char-syntax command-event))))) 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)))))
374 533
375(defun electric-pair--insert (char) 534(defun electric-pair--insert (char)
376 (let ((last-command-event char) 535 (let ((last-command-event char)
@@ -378,56 +537,297 @@ closer."
378 (electric-pair-mode nil)) 537 (electric-pair-mode nil))
379 (self-insert-command 1))) 538 (self-insert-command 1)))
380 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
381(defun electric-pair-post-self-insert-function () 741(defun electric-pair-post-self-insert-function ()
382 (let* ((pos (and electric-pair-mode (electric--after-char-pos))) 742 (let* ((pos (and electric-pair-mode (electric--after-char-pos)))
383 (syntax (and pos (electric-pair-syntax last-command-event))) 743 (skip-whitespace-info))
384 (closer (if (eq syntax ?\() 744 (pcase (electric-pair-syntax-info last-command-event)
385 (cdr (or (assq last-command-event electric-pair-pairs) 745 (`(,syntax ,pair ,unconditional ,_)
386 (aref (syntax-table) last-command-event))) 746 (cond
387 last-command-event))) 747 ((null pos) nil)
388 (cond 748 ;; Wrap a pair around the active region.
389 ((null pos) nil) 749 ;;
390 ;; Wrap a pair around the active region. 750 ((and (memq syntax '(?\( ?\) ?\" ?\$)) (use-region-p))
391 ((and (memq syntax '(?\( ?\" ?\$)) (use-region-p)) 751 ;; FIXME: To do this right, we'd need a post-self-insert-function
392 ;; 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
393 ;; so we could add-function around it and insert the closer after 753 ;; all the rest of the hook has run.
394 ;; all the rest of the hook has run. 754 (if (or (eq syntax ?\")
395 (if (>= (mark) (point)) 755 (and (eq syntax ?\))
396 (goto-char (mark)) 756 (>= (point) (mark)))
397 ;; We already inserted the open-paren but at the end of the 757 (and (not (eq syntax ?\)))
398 ;; region, so we have to remove it and start over. 758 (>= (mark) (point))))
399 (delete-region (1- pos) (point)) 759 (save-excursion
400 (save-excursion 760 (goto-char (mark))
401 (goto-char (mark)) 761 (electric-pair--insert pair))
402 (electric-pair--insert last-command-event))) 762 (delete-region pos (1- pos))
403 ;; Since we're right after the closer now, we could tell the rest of 763 (electric-pair--insert pair)
404 ;; post-self-insert-hook that we inserted `closer', but then we'd get 764 (goto-char (mark))
405 ;; blink-paren to kick in, which is annoying. 765 (electric-pair--insert last-command-event)))
406 ;;(setq last-command-event closer) 766 ;; Backslash-escaped: no pairing, no skipping.
407 (insert closer)) 767 ((save-excursion
408 ;; Backslash-escaped: no pairing, no skipping. 768 (goto-char (1- pos))
409 ((save-excursion 769 (not (zerop (% (skip-syntax-backward "\\") 2))))
410 (goto-char (1- pos)) 770 nil)
411 (not (zerop (% (skip-syntax-backward "\\") 2)))) 771 ;; Skip self.
412 nil) 772 ((and (memq syntax '(?\) ?\" ?\$))
413 ;; Skip self. 773 (and (or unconditional
414 ((and (memq syntax '(?\) ?\" ?\$)) 774 (if (functionp electric-pair-skip-self)
415 electric-pair-skip-self 775 (funcall electric-pair-skip-self last-command-event)
416 (eq (char-after pos) last-command-event)) 776 electric-pair-skip-self))
417 ;; This is too late: rather than insert&delete we'd want to only skip (or 777 (save-excursion
418 ;; insert in overwrite mode). The difference is in what goes in the 778 (when (setq skip-whitespace-info
419 ;; undo-log and in the intermediate state which might be visible to other 779 (if (functionp electric-pair-skip-whitespace)
420 ;; post-self-insert-hook. We'll just have to live with it for now. 780 (funcall electric-pair-skip-whitespace)
421 (delete-char 1)) 781 electric-pair-skip-whitespace))
422 ;; Insert matching pair. 782 (electric-pair--skip-whitespace))
423 ((not (or (not (memq syntax `(?\( ?\" ?\$))) 783 (eq (char-after) last-command-event))))
424 overwrite-mode 784 ;; This is too late: rather than insert&delete we'd want to only
425 (funcall electric-pair-inhibit-predicate last-command-event))) 785 ;; skip (or insert in overwrite mode). The difference is in what
426 (save-excursion (electric-pair--insert closer)))))) 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)
427 815
428(defun electric-pair-will-use-region () 816(defun electric-pair-will-use-region ()
429 (and (use-region-p) 817 (and (use-region-p)
430 (memq (electric-pair-syntax last-command-event) '(?\( ?\" ?\$)))) 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'.")
431 831
432;;;###autoload 832;;;###autoload
433(define-minor-mode electric-pair-mode 833(define-minor-mode electric-pair-mode
@@ -438,29 +838,33 @@ the mode if ARG is omitted or nil.
438 838
439Electric Pair mode is a global minor mode. When enabled, typing 839Electric Pair mode is a global minor mode. When enabled, typing
440an open parenthesis automatically inserts the corresponding 840an open parenthesis automatically inserts the corresponding
441closing parenthesis. \(Likewise for brackets, etc.) 841closing parenthesis. \(Likewise for brackets, etc.)."
442
443See options `electric-pair-pairs' and `electric-pair-skip-self'."
444 :global t :group 'electricity 842 :global t :group 'electricity
445 (if electric-pair-mode 843 (if electric-pair-mode
446 (progn 844 (progn
447 (add-hook 'post-self-insert-hook 845 (add-hook 'post-self-insert-hook
448 #'electric-pair-post-self-insert-function) 846 #'electric-pair-post-self-insert-function)
847 (electric--sort-post-self-insertion-hook)
449 (add-hook 'self-insert-uses-region-functions 848 (add-hook 'self-insert-uses-region-functions
450 #'electric-pair-will-use-region)) 849 #'electric-pair-will-use-region))
451 (remove-hook 'post-self-insert-hook 850 (remove-hook 'post-self-insert-hook
452 #'electric-pair-post-self-insert-function) 851 #'electric-pair-post-self-insert-function)
453 (remove-hook 'self-insert-uses-region-functions 852 (remove-hook 'self-insert-uses-region-functions
454 #'electric-pair-will-use-region))) 853 #'electric-pair-will-use-region)))
455 854
456;;; Electric newlines after/before/around some chars. 855;;; Electric newlines after/before/around some chars.
457 856
458(defvar electric-layout-rules '() 857(defvar electric-layout-rules nil
459 "List of rules saying where to automatically insert newlines. 858 "List of rules saying where to automatically insert newlines.
460Each rule has the form (CHAR . WHERE) where CHAR is the char 859
461that was just inserted and WHERE specifies where to insert newlines 860Each rule has the form (CHAR . WHERE) where CHAR is the char that
462and can be: nil, `before', `after', `around', or a function of no 861was just inserted and WHERE specifies where to insert newlines
463arguments that returns one of those symbols.") 862and can be: nil, `before', `after', `around', `after-stay', or a
863function of no arguments that returns one of those symbols.
864
865The symbols specify where in relation to CHAR the newline
866character(s) should be inserted. `after-stay' means insert a
867newline after CHAR but stay in the same place.")
464 868
465(defun electric-layout-post-self-insert-function () 869(defun electric-layout-post-self-insert-function ()
466 (let* ((rule (cdr (assq last-command-event electric-layout-rules))) 870 (let* ((rule (cdr (assq last-command-event electric-layout-rules)))
@@ -469,23 +873,32 @@ arguments that returns one of those symbols.")
469 (setq pos (electric--after-char-pos)) 873 (setq pos (electric--after-char-pos))
470 ;; Not in a string or comment. 874 ;; Not in a string or comment.
471 (not (nth 8 (save-excursion (syntax-ppss pos))))) 875 (not (nth 8 (save-excursion (syntax-ppss pos)))))
472 (let ((end (copy-marker (point) t))) 876 (let ((end (copy-marker (point)))
877 (sym (if (functionp rule) (funcall rule) rule)))
878 (set-marker-insertion-type end (not (eq sym 'after-stay)))
473 (goto-char pos) 879 (goto-char pos)
474 (pcase (if (functionp rule) (funcall rule) rule) 880 (pcase sym
475 ;; FIXME: we used `newline' down here which called 881 ;; FIXME: we used `newline' down here which called
476 ;; self-insert-command and ran post-self-insert-hook recursively. 882 ;; self-insert-command and ran post-self-insert-hook recursively.
477 ;; It happened to make electric-indent-mode work automatically with 883 ;; It happened to make electric-indent-mode work automatically with
478 ;; electric-layout-mode (at the cost of re-indenting lines 884 ;; electric-layout-mode (at the cost of re-indenting lines
479 ;; multiple times), but I'm not sure it's what we want. 885 ;; multiple times), but I'm not sure it's what we want.
886 ;;
887 ;; FIXME: check eolp before inserting \n?
480 (`before (goto-char (1- pos)) (skip-chars-backward " \t") 888 (`before (goto-char (1- pos)) (skip-chars-backward " \t")
481 (unless (bolp) (insert "\n"))) 889 (unless (bolp) (insert "\n")))
482 (`after (insert "\n")) ; FIXME: check eolp before inserting \n? 890 (`after (insert "\n"))
891 (`after-stay (save-excursion
892 (let ((electric-layout-rules nil))
893 (newline 1 t))))
483 (`around (save-excursion 894 (`around (save-excursion
484 (goto-char (1- pos)) (skip-chars-backward " \t") 895 (goto-char (1- pos)) (skip-chars-backward " \t")
485 (unless (bolp) (insert "\n"))) 896 (unless (bolp) (insert "\n")))
486 (insert "\n"))) ; FIXME: check eolp before inserting \n? 897 (insert "\n"))) ; FIXME: check eolp before inserting \n?
487 (goto-char end))))) 898 (goto-char end)))))
488 899
900(put 'electric-layout-post-self-insert-function 'priority 40)
901
489;;;###autoload 902;;;###autoload
490(define-minor-mode electric-layout-mode 903(define-minor-mode electric-layout-mode
491 "Automatically insert newlines around some chars. 904 "Automatically insert newlines around some chars.
@@ -494,11 +907,13 @@ positive, and disable it otherwise. If called from Lisp, enable
494the mode if ARG is omitted or nil. 907the mode if ARG is omitted or nil.
495The variable `electric-layout-rules' says when and how to insert newlines." 908The variable `electric-layout-rules' says when and how to insert newlines."
496 :global t :group 'electricity 909 :global t :group 'electricity
497 (if electric-layout-mode 910 (cond (electric-layout-mode
498 (add-hook 'post-self-insert-hook 911 (add-hook 'post-self-insert-hook
499 #'electric-layout-post-self-insert-function) 912 #'electric-layout-post-self-insert-function)
500 (remove-hook 'post-self-insert-hook 913 (electric--sort-post-self-insertion-hook))
501 #'electric-layout-post-self-insert-function))) 914 (t
915 (remove-hook 'post-self-insert-hook
916 #'electric-layout-post-self-insert-function))))
502 917
503(provide 'electric) 918(provide 'electric)
504 919
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index b7bd33f628f..f1eae18c507 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -472,7 +472,13 @@ font-lock keywords will not be case sensitive."
472 (font-lock-mark-block-function . mark-defun) 472 (font-lock-mark-block-function . mark-defun)
473 (font-lock-syntactic-face-function 473 (font-lock-syntactic-face-function
474 . lisp-font-lock-syntactic-face-function))) 474 . lisp-font-lock-syntactic-face-function)))
475 (setq-local prettify-symbols-alist lisp--prettify-symbols-alist)) 475 (setq-local prettify-symbols-alist lisp--prettify-symbols-alist)
476 ;; electric
477 (when elisp
478 (setq-local electric-pair-text-pairs
479 (cons '(?\` . ?\') electric-pair-text-pairs)))
480 (setq-local electric-pair-skip-whitespace 'chomp)
481 (setq-local electric-pair-open-newline-between-pairs nil))
476 482
477(defun lisp-outline-level () 483(defun lisp-outline-level ()
478 "Lisp mode `outline-level' function." 484 "Lisp mode `outline-level' function."
diff --git a/lisp/simple.el b/lisp/simple.el
index a6543516a9c..624d87fd655 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -610,7 +610,7 @@ In some text modes, where TAB inserts a tab, this command indents to the
610column specified by the function `current-left-margin'." 610column specified by the function `current-left-margin'."
611 (interactive "*") 611 (interactive "*")
612 (delete-horizontal-space t) 612 (delete-horizontal-space t)
613 (newline) 613 (newline 1 t)
614 (indent-according-to-mode)) 614 (indent-according-to-mode))
615 615
616(defun reindent-then-newline-and-indent () 616(defun reindent-then-newline-and-indent ()
@@ -6448,10 +6448,14 @@ More precisely, a char with closeparen syntax is self-inserted.")
6448 (point)))))) 6448 (point))))))
6449 (funcall blink-paren-function))) 6449 (funcall blink-paren-function)))
6450 6450
6451(put 'blink-paren-post-self-insert-function 'priority 100)
6452
6451(add-hook 'post-self-insert-hook #'blink-paren-post-self-insert-function 6453(add-hook 'post-self-insert-hook #'blink-paren-post-self-insert-function
6452 ;; Most likely, this hook is nil, so this arg doesn't matter, 6454 ;; Most likely, this hook is nil, so this arg doesn't matter,
6453 ;; but I use it as a reminder that this function usually 6455 ;; but I use it as a reminder that this function usually
6454 ;; likes to be run after others since it does `sit-for'. 6456 ;; likes to be run after others since it does
6457 ;; `sit-for'. That's also the reason it get a `priority' prop
6458 ;; of 100.
6455 'append) 6459 'append)
6456 6460
6457;; This executes C-g typed while Emacs is waiting for a command. 6461;; This executes C-g typed while Emacs is waiting for a command.