aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Stephani2017-07-23 21:58:49 +0200
committerPhilipp Stephani2017-10-01 00:20:36 +0200
commitd247e1d30abcb77665f829ca98a5bdef69ff4bc3 (patch)
treedb9c7b1127eaa1860fbc586c8eace53ea4e3c4f2
parentd88a0f6554888643854ddb2c1f49b77b0bf8904c (diff)
downloademacs-d247e1d30abcb77665f829ca98a5bdef69ff4bc3.tar.gz
emacs-d247e1d30abcb77665f829ca98a5bdef69ff4bc3.zip
Electric quote mode: Conditionally replace " (Bug#24710)
* lisp/electric.el (electric-quote-replace-double): New user option. (electric-quote-post-self-insert-function): Use it. * test/lisp/electric-tests.el (electric-quote-replace-double-disabled) (electric-quote-replace-double-bob) (electric-quote-replace-double-bol) (electric-quote-replace-double-after-space) (electric-quote-replace-double-after-letter) (electric-quote-replace-double-after-paren): New unit tests. * doc/emacs/text.texi (Quotation Marks): Document 'electric-quote-replace-double'.
-rw-r--r--doc/emacs/text.texi7
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/electric.el25
-rw-r--r--test/lisp/electric-tests.el41
4 files changed, 74 insertions, 4 deletions
diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi
index 496b43ce1e3..5aa0c77d34c 100644
--- a/doc/emacs/text.texi
+++ b/doc/emacs/text.texi
@@ -443,6 +443,13 @@ non-@code{nil}, and in programming-language strings if
443@code{nil} for @code{electric-quote-string} and @code{t} for the other 443@code{nil} for @code{electric-quote-string} and @code{t} for the other
444variables. 444variables.
445 445
446@vindex electric-quote-replace-double
447 You can also set the option @code{electric-quote-replace-double} to
448a non-@code{nil} value. Then, typing @t{"} insert an appropriate
449curved double quote depending on context: @t{“} at the beginning of
450the buffer or after a line break, whitespace, opening parenthesis, or
451quote character, and @t{”} otherwise.
452
446 Electric Quote mode is disabled by default. To toggle it, type 453 Electric Quote mode is disabled by default. To toggle it, type
447@kbd{M-x electric-quote-mode}. To toggle it in a single buffer, use 454@kbd{M-x electric-quote-mode}. To toggle it in a single buffer, use
448@kbd{M-x electric-quote-local-mode}. To suppress it for a single use, 455@kbd{M-x electric-quote-local-mode}. To suppress it for a single use,
diff --git a/etc/NEWS b/etc/NEWS
index 8fbc354fc06..42c1b048169 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -42,6 +42,11 @@ When you add a new item, use the appropriate mark if you are sure it applies,
42This controls how long Emacs will wait for updates to the graphical 42This controls how long Emacs will wait for updates to the graphical
43state to take effect (making a frame visible, for example). 43state to take effect (making a frame visible, for example).
44 44
45+++
46** The new user option 'electric-quote-replace-double' controls
47whether " is also replaced in 'electric-quote-mode'. If non-nil, " is
48replaced by a double typographic quote.
49
45 50
46* Changes in Specialized Modes and Packages in Emacs 27.1 51* Changes in Specialized Modes and Packages in Emacs 27.1
47 52
diff --git a/lisp/electric.el b/lisp/electric.el
index d7929945db2..65e36b7a63f 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -451,6 +451,14 @@ whitespace, opening parenthesis, or quote and leaves \\=` alone."
451 :version "26.1" 451 :version "26.1"
452 :type 'boolean :safe #'booleanp :group 'electricity) 452 :type 'boolean :safe #'booleanp :group 'electricity)
453 453
454(defcustom electric-quote-replace-double nil
455 "Non-nil means to replace \" with an electric double quote.
456Emacs replaces \" with an opening double quote after a line
457break, whitespace, opening parenthesis, or quote, and with a
458closing double quote otherwise."
459 :version "26.1"
460 :type 'boolean :safe #'booleanp :group 'electricity)
461
454(defvar electric-quote-inhibit-functions () 462(defvar electric-quote-inhibit-functions ()
455 "List of functions that should inhibit electric quoting. 463 "List of functions that should inhibit electric quoting.
456When the variable `electric-quote-mode' is non-nil, Emacs will 464When the variable `electric-quote-mode' is non-nil, Emacs will
@@ -467,7 +475,9 @@ This requotes when a quoting key is typed."
467 (when (and electric-quote-mode 475 (when (and electric-quote-mode
468 (or (eq last-command-event ?\') 476 (or (eq last-command-event ?\')
469 (and (not electric-quote-context-sensitive) 477 (and (not electric-quote-context-sensitive)
470 (eq last-command-event ?\`))) 478 (eq last-command-event ?\`))
479 (and electric-quote-replace-double
480 (eq last-command-event ?\")))
471 (not (run-hook-with-args-until-success 481 (not (run-hook-with-args-until-success
472 'electric-quote-inhibit-functions)) 482 'electric-quote-inhibit-functions))
473 (if (derived-mode-p 'text-mode) 483 (if (derived-mode-p 'text-mode)
@@ -488,7 +498,8 @@ This requotes when a quoting key is typed."
488 (save-excursion 498 (save-excursion
489 (let ((backtick ?\`)) 499 (let ((backtick ?\`))
490 (if (or (eq last-command-event ?\`) 500 (if (or (eq last-command-event ?\`)
491 (and electric-quote-context-sensitive 501 (and (or electric-quote-context-sensitive
502 electric-quote-replace-double)
492 (save-excursion 503 (save-excursion
493 (backward-char) 504 (backward-char)
494 (or (bobp) (bolp) 505 (or (bobp) (bolp)
@@ -506,13 +517,19 @@ This requotes when a quoting key is typed."
506 (setq last-command-event q<<)) 517 (setq last-command-event q<<))
507 ((search-backward (string backtick) (1- (point)) t) 518 ((search-backward (string backtick) (1- (point)) t)
508 (replace-match (string q<)) 519 (replace-match (string q<))
509 (setq last-command-event q<))) 520 (setq last-command-event q<))
521 ((search-backward "\"" (1- (point)) t)
522 (replace-match (string q<<))
523 (setq last-command-event q<<)))
510 (cond ((search-backward (string q> ?') (- (point) 2) t) 524 (cond ((search-backward (string q> ?') (- (point) 2) t)
511 (replace-match (string q>>)) 525 (replace-match (string q>>))
512 (setq last-command-event q>>)) 526 (setq last-command-event q>>))
513 ((search-backward "'" (1- (point)) t) 527 ((search-backward "'" (1- (point)) t)
514 (replace-match (string q>)) 528 (replace-match (string q>))
515 (setq last-command-event q>)))))))))) 529 (setq last-command-event q>))
530 ((search-backward "\"" (1- (point)) t)
531 (replace-match (string q>>))
532 (setq last-command-event q>>))))))))))
516 533
517(put 'electric-quote-post-self-insert-function 'priority 10) 534(put 'electric-quote-post-self-insert-function 'priority 10)
518 535
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index fc69919fbe1..7df2449b9eb 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -617,6 +617,12 @@ baz\"\""
617 :fixture-fn #'electric-quote-local-mode 617 :fixture-fn #'electric-quote-local-mode
618 :test-in-comments nil :test-in-strings nil) 618 :test-in-comments nil :test-in-strings nil)
619 619
620(define-electric-pair-test electric-quote-replace-double-disabled
621 "" "\"" :expected-string "\"" :expected-point 2
622 :modes '(text-mode)
623 :fixture-fn #'electric-quote-local-mode
624 :test-in-comments nil :test-in-strings nil)
625
620(define-electric-pair-test electric-quote-context-sensitive-backtick 626(define-electric-pair-test electric-quote-context-sensitive-backtick
621 "" "`" :expected-string "`" :expected-point 2 627 "" "`" :expected-string "`" :expected-point 2
622 :modes '(text-mode) 628 :modes '(text-mode)
@@ -638,6 +644,13 @@ baz\"\""
638 :bindings '((electric-quote-context-sensitive . t)) 644 :bindings '((electric-quote-context-sensitive . t))
639 :test-in-comments nil :test-in-strings nil) 645 :test-in-comments nil :test-in-strings nil)
640 646
647(define-electric-pair-test electric-quote-replace-double-bob
648 "" "\"" :expected-string "“" :expected-point 2
649 :modes '(text-mode)
650 :fixture-fn #'electric-quote-local-mode
651 :bindings '((electric-quote-replace-double . t))
652 :test-in-comments nil :test-in-strings nil)
653
641(define-electric-pair-test electric-quote-context-sensitive-bol-single 654(define-electric-pair-test electric-quote-context-sensitive-bol-single
642 "a\n" "--'" :expected-string "a\n‘" :expected-point 4 655 "a\n" "--'" :expected-string "a\n‘" :expected-point 4
643 :modes '(text-mode) 656 :modes '(text-mode)
@@ -652,6 +665,13 @@ baz\"\""
652 :bindings '((electric-quote-context-sensitive . t)) 665 :bindings '((electric-quote-context-sensitive . t))
653 :test-in-comments nil :test-in-strings nil) 666 :test-in-comments nil :test-in-strings nil)
654 667
668(define-electric-pair-test electric-quote-replace-double-bol
669 "a\n" "--\"" :expected-string "a\n“" :expected-point 4
670 :modes '(text-mode)
671 :fixture-fn #'electric-quote-local-mode
672 :bindings '((electric-quote-replace-double . t))
673 :test-in-comments nil :test-in-strings nil)
674
655(define-electric-pair-test electric-quote-context-sensitive-after-space-single 675(define-electric-pair-test electric-quote-context-sensitive-after-space-single
656 " " "-'" :expected-string " ‘" :expected-point 3 676 " " "-'" :expected-string " ‘" :expected-point 3
657 :modes '(text-mode) 677 :modes '(text-mode)
@@ -666,6 +686,13 @@ baz\"\""
666 :bindings '((electric-quote-context-sensitive . t)) 686 :bindings '((electric-quote-context-sensitive . t))
667 :test-in-comments nil :test-in-strings nil) 687 :test-in-comments nil :test-in-strings nil)
668 688
689(define-electric-pair-test electric-quote-replace-double-after-space
690 " " "-\"" :expected-string " “" :expected-point 3
691 :modes '(text-mode)
692 :fixture-fn #'electric-quote-local-mode
693 :bindings '((electric-quote-replace-double . t))
694 :test-in-comments nil :test-in-strings nil)
695
669(define-electric-pair-test electric-quote-context-sensitive-after-letter-single 696(define-electric-pair-test electric-quote-context-sensitive-after-letter-single
670 "a" "-'" :expected-string "a’" :expected-point 3 697 "a" "-'" :expected-string "a’" :expected-point 3
671 :modes '(text-mode) 698 :modes '(text-mode)
@@ -680,6 +707,13 @@ baz\"\""
680 :bindings '((electric-quote-context-sensitive . t)) 707 :bindings '((electric-quote-context-sensitive . t))
681 :test-in-comments nil :test-in-strings nil) 708 :test-in-comments nil :test-in-strings nil)
682 709
710(define-electric-pair-test electric-quote-replace-double-after-letter
711 "a" "-\"" :expected-string "a”" :expected-point 3
712 :modes '(text-mode)
713 :fixture-fn #'electric-quote-local-mode
714 :bindings '((electric-quote-replace-double . t))
715 :test-in-comments nil :test-in-strings nil)
716
683(define-electric-pair-test electric-quote-context-sensitive-after-paren-single 717(define-electric-pair-test electric-quote-context-sensitive-after-paren-single
684 "(" "-'" :expected-string "(‘" :expected-point 3 718 "(" "-'" :expected-string "(‘" :expected-point 3
685 :modes '(text-mode) 719 :modes '(text-mode)
@@ -694,6 +728,13 @@ baz\"\""
694 :bindings '((electric-quote-context-sensitive . t)) 728 :bindings '((electric-quote-context-sensitive . t))
695 :test-in-comments nil :test-in-strings nil) 729 :test-in-comments nil :test-in-strings nil)
696 730
731(define-electric-pair-test electric-quote-replace-double-after-paren
732 "(" "-\"" :expected-string "(“" :expected-point 3
733 :modes '(text-mode)
734 :fixture-fn #'electric-quote-local-mode
735 :bindings '((electric-quote-replace-double . t))
736 :test-in-comments nil :test-in-strings nil)
737
697;; Simulate ‘markdown-mode’: it sets both ‘comment-start’ and 738;; Simulate ‘markdown-mode’: it sets both ‘comment-start’ and
698;; ‘comment-use-syntax’, but derives from ‘text-mode’. 739;; ‘comment-use-syntax’, but derives from ‘text-mode’.
699(define-electric-pair-test electric-quote-markdown-in-text 740(define-electric-pair-test electric-quote-markdown-in-text