Subject: Re: bug#19356: electric-pair-mode painful quotes in latex-mode

From: [email-masked] (João Távora)
Date: Sat, 13 Dec 2014 15:47:32 +0000

[email-masked] (João Távora) writes:

>> Package: Emacs
>> Version: 24.4
>>
>>
>>    ./src/emacs -Q -f electric-pair-mode ~/tmp/foo.tex
>>
>> then type a word, go back to before this word and try:
>>
>>    C-M-SPC "
>>
>> this will not surround the word in quotes as electric-pair-mode should.
>
> What kind of surrounding should take place? Should it be
>
>   ``wordityped''

I went with this option, seemed the most sane. Here's my proposed fix
(for the two issues). Let me know if you find the nested ifs ugly and
I'll make a cond out of it.

If it seems OK, I'll add some tests and commit it to the emacs-24 branch
(someone else will cherry-pick it to the master, right?).

João

diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el
index 1993ff1..f2d8e66 100644
--- a/lisp/textmodes/tex-mode.el
+++ b/lisp/textmodes/tex-mode.el
@@ -1300,18 +1300,40 @@ Inserts the value of `tex-open-quote' (normally ``) or `tex-close-quote'
 \(normally '') depending on the context.  With prefix argument, always
 inserts \" characters."
   (interactive "*P")
-  (if (or arg (memq (char-syntax (preceding-char)) '(?/ ?\\))
-	  (eq (get-text-property (point) 'face) 'tex-verbatim)
-	  (save-excursion
-	    (backward-char (length tex-open-quote))
-	    (when (or (looking-at (regexp-quote tex-open-quote))
-		      (looking-at (regexp-quote tex-close-quote)))
-	      (delete-char (length tex-open-quote))
-	      t)))
-      (self-insert-command (prefix-numeric-value arg))
-    (insert (if (or (memq (char-syntax (preceding-char)) '(?\( ?> ?\s))
-                    (memq (preceding-char) '(?~)))
-		tex-open-quote tex-close-quote))))
+  (let ((morph-to-normal-p nil))
+    ;; Discover if we'll be inserting normal double quotes.
+    ;;
+    (if (or arg (memq (char-syntax (preceding-char)) '(?/ ?\\))
+            (eq (get-text-property (point) 'face) 'tex-verbatim)
+            ;; Discover if a preceding occurance of `tex-open-quote'
+            ;; should be morphed to a normal double quote. 
+            ;;
+            (and (>= (point) (+ (point-min) (length tex-open-quote)))
+                 (save-excursion
+                   (backward-char (length tex-open-quote))
+                   (when (or (looking-at (regexp-quote tex-open-quote))
+                             (looking-at (regexp-quote tex-close-quote)))
+                     (delete-char (length tex-open-quote))
+                     (setq morph-to-normal-p t)))))
+        ;; In case morphing occured, be sure to turn off
+        ;; `electric-pair-mode' iff it was on. Otherwise let it do
+        ;; its thing.
+        ;;
+        (let ((electric-pair-mode (and electric-pair-mode
+                                       (not morph-to-normal-p))))
+          (self-insert-command (prefix-numeric-value arg)))
+      ;; We'll be inserting fancy TeX quotes, but consider and
+      ;; imitate `electric-pair-mode''s region wrapping.
+      ;;
+      (if (and electric-pair-mode (use-region-p))
+          (let* ((saved (point-marker)))
+            (goto-char (mark))
+            (insert (if (> saved (mark)) tex-open-quote tex-close-quote))
+            (goto-char saved)
+            (insert (if (> saved (mark)) tex-close-quote tex-open-quote)))
+        (insert (if (or (memq (char-syntax (preceding-char)) '(?\( ?> ?\s))
+                        (memq (preceding-char) '(?~)))
+                    tex-open-quote tex-close-quote))))))
 
 (defun tex-validate-buffer ()
   "Check current buffer for paragraphs containing mismatched braces or $s.