unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
@ 2016-10-16 17:19 Philipp Stephani
  2016-10-19 11:10 ` Alan Third
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Philipp Stephani @ 2016-10-16 17:19 UTC (permalink / raw)
  To: 24709


When editing a Markdown document with electric-quote-mode enabled, the
experience is not optimal because ` (backtick) in Markdown is a syntax
element (for introducing code spans and blocks), but is converted by
electric-quote-mode.  Also ` and ' inside code spans and blocks continue
to insert curly quotes where they shouldn't.  I propose the following:

- Provide an alternative behavior of electric-quote-mode where ` doesn't
  trigger replacement and ' can insert left or right curly quotes,
  depending on whether it follows a space or similar (newline, beginning
  of buffer, opening parenthesis).

- Provide a way to disable electric-quote-mode for certain regions,
  effectively the inverse of the existing electric-quote-string etc.
  This could be in the form of syntactic elements or text properties.


In GNU Emacs 26.0.50.4 (x86_64-apple-darwin16.0.0, NS appkit-1504.00 Version 10.12 (Build 16A323))
 of 2016-10-16 built on p
Repository revision: cf566b46a6cf85c6d54d0b0db80e32ed6ae8d1ca
Windowing system distributor 'Apple', version 10.3.1504
Recent messages:
For information about GNU Emacs and the GNU system, type C-h C-a.

Configured using:
 'configure --with-modules --enable-checking
 --enable-check-lisp-object-type --without-xml2'

Configured features:
RSVG IMAGEMAGICK DBUS NOTIFY ACL GNUTLS ZLIB TOOLKIT_SCROLL_BARS NS
MODULES

Important settings:
  value of $LANG: de_DE.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug message subr-x puny seq byte-opt gv
bytecomp byte-compile cl-extra help-mode cconv cl-loaddefs pcase cl-lib
dired dired-loaddefs format-spec rfc822 mml easymenu mml-sec
password-cache epa derived epg epg-config gnus-util rmail rmail-loaddefs
mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils
mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr
mail-utils time-date mule-util tooltip eldoc electric uniquify
ediff-hook vc-hooks lisp-float-type mwheel term/ns-win ns-win
ucs-normalize term/common-win tool-bar dnd fontset image regexp-opt
fringe tabulated-list newcomment elisp-mode lisp-mode prog-mode register
page menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock
font-lock syntax facemenu font-core term/tty-colors frame cl-generic
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese charscript case-table epa-hook
jka-cmpr-hook help simple abbrev obarray minibuffer cl-preloaded nadvice
loaddefs button faces cus-face macroexp files text-properties overlay
sha1 md5 base64 format env code-pages mule custom widget
hashtable-print-readable backquote dbusbind kqueue cocoa ns multi-tty
make-network-process emacs)

Memory information:
((conses 16 206733 10576)
 (symbols 48 20333 0)
 (miscs 40 43 151)
 (strings 32 18363 6592)
 (string-bytes 1 593794)
 (vectors 16 35285)
 (vector-slots 8 676063 5565)
 (floats 8 183 55)
 (intervals 56 207 0)
 (buffers 976 11))





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
  2016-10-16 17:19 bug#24709: 26.0.50; Support for Markdown in electric-quote-mode Philipp Stephani
@ 2016-10-19 11:10 ` Alan Third
  2017-06-28 21:59 ` Philipp Stephani
  2017-07-14 12:36 ` Paul Eggert
  2 siblings, 0 replies; 7+ messages in thread
From: Alan Third @ 2016-10-19 11:10 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: 24709

On Sun, Oct 16, 2016 at 07:19:12PM +0200, Philipp Stephani wrote:
> - Provide an alternative behavior of electric-quote-mode where ` doesn't
>   trigger replacement and ' can insert left or right curly quotes,
>   depending on whether it follows a space or similar (newline, beginning
>   of buffer, opening parenthesis).

I wrote a minor mode that does this, sort of. The defaults are probably
not what you want, but it should be easy to modify:

https://gist.github.com/alanthird/b758d3fb45b0e863f8a4

-- 
Alan Third





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
  2016-10-16 17:19 bug#24709: 26.0.50; Support for Markdown in electric-quote-mode Philipp Stephani
  2016-10-19 11:10 ` Alan Third
@ 2017-06-28 21:59 ` Philipp Stephani
  2017-07-02 15:49   ` Philipp Stephani
  2017-07-14 12:36 ` Paul Eggert
  2 siblings, 1 reply; 7+ messages in thread
From: Philipp Stephani @ 2017-06-28 21:59 UTC (permalink / raw)
  To: 24709


[-- Attachment #1.1: Type: text/plain, Size: 1053 bytes --]

Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 16. Okt. 2016 um
19:22 Uhr:

>
> When editing a Markdown document with electric-quote-mode enabled, the
> experience is not optimal because ` (backtick) in Markdown is a syntax
> element (for introducing code spans and blocks), but is converted by
> electric-quote-mode.  Also ` and ' inside code spans and blocks continue
> to insert curly quotes where they shouldn't.  I propose the following:
>
> - Provide an alternative behavior of electric-quote-mode where ` doesn't
>   trigger replacement and ' can insert left or right curly quotes,
>   depending on whether it follows a space or similar (newline, beginning
>   of buffer, opening parenthesis).
>
> - Provide a way to disable electric-quote-mode for certain regions,
>   effectively the inverse of the existing electric-quote-string etc.
>   This could be in the form of syntactic elements or text properties.
>
>
>
I've attached a patch. It doesn't cover all cases, though; e.g. an
unterminated Markdown code span is not supported yet.

[-- Attachment #1.2: Type: text/html, Size: 1411 bytes --]

[-- Attachment #2: 0001-Electric-quotes-Improve-support-for-Markdown-mode-Bug-.txt --]
[-- Type: text/plain, Size: 13187 bytes --]

From 126557c6998950c522baab9d344bb62629b7f9c0 Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Wed, 28 Jun 2017 23:47:57 +0200
Subject: [PATCH] Electric quotes: Improve support for Markdown mode
 (Bug#24709)

Introduce a new user option 'electric-quote-context-sensitive'.  If
non-nil, have ' insert an opening quote if sensible.

Also introduce a new variable 'electric-quote-code-faces'.  Major
modes such as 'markdown-mode' can add faces to this list to treat text
as inline code and disable electric quoting.

* lisp/electric.el (electric-quote-context-sensitive): New user
option.
(electric-quote-code-faces): New variable.
(electric-quote-post-self-insert-function): Treat ' as ` if
desired and applicable; disable electric quoting for given faces.

* test/lisp/electric-tests.el (electric-quote-opening-single)
(electric-quote-closing-single, electric-quote-opening-double)
(electric-quote-closing-double)
(electric-quote-context-sensitive-backtick)
(electric-quote-context-sensitive-bob-single)
(electric-quote-context-sensitive-bob-double)
(electric-quote-context-sensitive-bol-single)
(electric-quote-context-sensitive-bol-double)
(electric-quote-context-sensitive-after-space-single)
(electric-quote-context-sensitive-after-space-double)
(electric-quote-context-sensitive-after-letter-single)
(electric-quote-context-sensitive-after-letter-double)
(electric-quote-context-sensitive-after-paren-single)
(electric-quote-context-sensitive-after-paren-double)
(electric-quote-markdown-in-text)
(electric-quote-markdown-in-code): New unit tests.
---
 etc/NEWS                    |  16 ++++++
 lisp/electric.el            |  66 +++++++++++++++++--------
 test/lisp/electric-tests.el | 116 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 179 insertions(+), 19 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 5e10ca9cb6..b0bb5e1465 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -129,6 +129,22 @@ given file is on a case-insensitive filesystem.
 of curved quotes for 'electric-quote-mode', allowing user to choose
 the types of quotes to be used.
 
+** The new user option 'electric-quote-context-sensitive' makes
+'electric-quote-mode' context sensitive.  If it is non-nil, you can
+type an ASCII apostrophe to insert an opening or closing quote,
+depending on context.  Emacs will replace the apostrophe by an opening
+quote character at the beginning of the buffer, the beginning of a
+line, after a whitespace character, and after an opening parenthesis;
+and it will replace the apostrophe by a closing quote character in all
+other cases.
+
+** The new variable 'electric-quote-code-faces' controls when to
+disable electric quoting in text modes.  Major modes can add faces to
+this list; Emacs will temporarily disable 'electric-quote-mode'
+whenever point is before a character having such a face.  This is
+intended for major modes that derive from 'text-mode' but allow inline
+code segments, such as 'markdown-mode'.
+
 +++
 ** The new user variable 'dired-omit-case-fold' allows the user to
 customize the case-sensitivity of dired-omit-mode.  It defaults to
diff --git a/lisp/electric.el b/lisp/electric.el
index 4078ef8193..1564df5949 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -443,11 +443,24 @@ electric-quote-paragraph
   :version "25.1"
   :type 'boolean :safe 'booleanp :group 'electricity)
 
+(defcustom electric-quote-context-sensitive nil
+  "Non-nil means to replace \\=' with an electric quote depending on context.
+If `electric-quote-context-sensitive' is non-nil, Emacs replaces
+\\=' and \\='\\=' with an opening quote after a line break,
+whitespace, opening parenthesis, or quote and leaves \\=` alone."
+  :version "26.1"
+  :type 'boolean :safe #'booleanp :group 'electricity)
+
+(defvar electric-quote-code-faces ()
+  "List of faces to treat as inline code in `text-mode'.")
+
 (defun electric-quote-post-self-insert-function ()
   "Function that `electric-quote-mode' adds to `post-self-insert-hook'.
 This requotes when a quoting key is typed."
   (when (and electric-quote-mode
-             (memq last-command-event '(?\' ?\`)))
+             (or (eq last-command-event ?\')
+                 (and (not electric-quote-context-sensitive)
+                      (eq last-command-event ?\`))))
     (let ((start
            (if (and comment-start comment-use-syntax)
                (when (or electric-quote-comment electric-quote-string)
@@ -462,30 +475,45 @@ electric-quote-post-self-insert-function
                                          (syntax-ppss (1- (point)))))))))
              (and electric-quote-paragraph
                   (derived-mode-p 'text-mode)
+                  ;; FIXME: There should be a ‘cl-disjoint’ function.
+                  (null (cl-intersection (face-at-point nil 'multiple)
+                                         electric-quote-code-faces
+                                         :test #'eq))
+                  ;; FIXME: Why is the next form there?  It’s never
+                  ;; nil.
                   (or (eq last-command-event ?\`)
                       (save-excursion (backward-paragraph) (point)))))))
       (pcase electric-quote-chars
         (`(,q< ,q> ,q<< ,q>>)
          (when start
            (save-excursion
-             (if (eq last-command-event ?\`)
-                 (cond ((search-backward (string q< ?`) (- (point) 2) t)
-                        (replace-match (string q<<))
-                        (when (and electric-pair-mode
-                                   (eq (cdr-safe
-                                        (assq q< electric-pair-text-pairs))
-                                       (char-after)))
-                          (delete-char 1))
-                        (setq last-command-event q<<))
-                       ((search-backward "`" (1- (point)) t)
-                        (replace-match (string q<))
-                        (setq last-command-event q<)))
-               (cond ((search-backward (string q> ?') (- (point) 2) t)
-                      (replace-match (string q>>))
-                      (setq last-command-event q>>))
-                     ((search-backward "'" (1- (point)) t)
-                      (replace-match (string q>))
-                      (setq last-command-event q>)))))))))))
+             (let ((backtick ?\`))
+               (if (or (eq last-command-event ?\`)
+                       (and electric-quote-context-sensitive
+                            (save-excursion
+                              (backward-char)
+                              (or (bobp) (bolp)
+                                  (memq (char-before) (list q< q<<))
+                                  (memq (char-syntax (char-before))
+                                        '(?\s ?\())))
+                            (setq backtick ?\')))
+                   (cond ((search-backward (string q< backtick) (- (point) 2) t)
+                          (replace-match (string q<<))
+                          (when (and electric-pair-mode
+                                     (eq (cdr-safe
+                                          (assq q< electric-pair-text-pairs))
+                                         (char-after)))
+                            (delete-char 1))
+                          (setq last-command-event q<<))
+                         ((search-backward (string backtick) (1- (point)) t)
+                          (replace-match (string q<))
+                          (setq last-command-event q<)))
+                 (cond ((search-backward (string q> ?') (- (point) 2) t)
+                        (replace-match (string q>>))
+                        (setq last-command-event q>>))
+                       ((search-backward "'" (1- (point)) t)
+                        (replace-match (string q>))
+                        (setq last-command-event q>))))))))))))
 
 (put 'electric-quote-post-self-insert-function 'priority 10)
 
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index 78a3765061..6f63d30e75 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -593,5 +593,121 @@ electric-quote-string
   :bindings '((electric-quote-string . t))
   :test-in-comments nil :test-in-strings nil)
 
+(define-electric-pair-test electric-quote-opening-single
+  "" "`" :expected-string "‘" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-closing-single
+  "" "'" :expected-string "’" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-opening-double
+  "‘" "-`" :expected-string "“" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-closing-double
+  "’" "-'" :expected-string "”" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-backtick
+  "" "`" :expected-string "`" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-bob-single
+  "" "'" :expected-string "‘" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-bob-double
+  "‘" "-'" :expected-string "“" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-bol-single
+  "a\n" "--'" :expected-string "a\n‘" :expected-point 4
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-bol-double
+  "a\n‘" "---'" :expected-string "a\n“" :expected-point 4
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-after-space-single
+  " " "-'" :expected-string " ‘" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-after-space-double
+  " ‘" "--'" :expected-string " “" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-after-letter-single
+  "a" "-'" :expected-string "a’" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-after-letter-double
+  "a’" "--'" :expected-string "a”" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-after-paren-single
+  "(" "-'" :expected-string "(‘" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-context-sensitive-after-paren-double
+  "(‘" "--'" :expected-string "(“" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-context-sensitive . t))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-markdown-in-text
+  "" "'" :expected-string "’" :expected-point 2
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-code-faces font-lock-constant-face))
+  :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-markdown-in-code
+  #("`a`" 1 2 (face font-lock-constant-face)) "-'"
+  :expected-string "`'a`" :expected-point 3
+  :modes '(text-mode)
+  :fixture-fn #'electric-quote-local-mode
+  :bindings '((electric-quote-code-faces font-lock-constant-face))
+  :test-in-comments nil :test-in-strings nil)
+
 (provide 'electric-tests)
 ;;; electric-tests.el ends here
-- 
2.13.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
  2017-06-28 21:59 ` Philipp Stephani
@ 2017-07-02 15:49   ` Philipp Stephani
  2017-07-02 16:20     ` Philipp Stephani
  0 siblings, 1 reply; 7+ messages in thread
From: Philipp Stephani @ 2017-07-02 15:49 UTC (permalink / raw)
  To: 24709

[-- Attachment #1: Type: text/plain, Size: 1191 bytes --]

Philipp Stephani <p.stephani2@gmail.com> schrieb am Mi., 28. Juni 2017 um
23:59 Uhr:

> Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 16. Okt. 2016 um
> 19:22 Uhr:
>
>>
>> When editing a Markdown document with electric-quote-mode enabled, the
>> experience is not optimal because ` (backtick) in Markdown is a syntax
>> element (for introducing code spans and blocks), but is converted by
>> electric-quote-mode.  Also ` and ' inside code spans and blocks continue
>> to insert curly quotes where they shouldn't.  I propose the following:
>>
>> - Provide an alternative behavior of electric-quote-mode where ` doesn't
>>   trigger replacement and ' can insert left or right curly quotes,
>>   depending on whether it follows a space or similar (newline, beginning
>>   of buffer, opening parenthesis).
>>
>> - Provide a way to disable electric-quote-mode for certain regions,
>>   effectively the inverse of the existing electric-quote-string etc.
>>   This could be in the form of syntactic elements or text properties.
>>
>>
>>
> I've attached a patch. It doesn't cover all cases, though; e.g. an
> unterminated Markdown code span is not supported yet.
>

Pushed as 34d4720f83.

[-- Attachment #2: Type: text/html, Size: 1866 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
  2017-07-02 15:49   ` Philipp Stephani
@ 2017-07-02 16:20     ` Philipp Stephani
  2017-07-09 19:57       ` Philipp Stephani
  0 siblings, 1 reply; 7+ messages in thread
From: Philipp Stephani @ 2017-07-02 16:20 UTC (permalink / raw)
  To: 24709


[-- Attachment #1.1: Type: text/plain, Size: 1343 bytes --]

Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 2. Juli 2017 um
17:49 Uhr:

> Philipp Stephani <p.stephani2@gmail.com> schrieb am Mi., 28. Juni 2017 um
> 23:59 Uhr:
>
>> Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 16. Okt. 2016
>> um 19:22 Uhr:
>>
>>>
>>> When editing a Markdown document with electric-quote-mode enabled, the
>>> experience is not optimal because ` (backtick) in Markdown is a syntax
>>> element (for introducing code spans and blocks), but is converted by
>>> electric-quote-mode.  Also ` and ' inside code spans and blocks continue
>>> to insert curly quotes where they shouldn't.  I propose the following:
>>>
>>> - Provide an alternative behavior of electric-quote-mode where ` doesn't
>>>   trigger replacement and ' can insert left or right curly quotes,
>>>   depending on whether it follows a space or similar (newline, beginning
>>>   of buffer, opening parenthesis).
>>>
>>> - Provide a way to disable electric-quote-mode for certain regions,
>>>   effectively the inverse of the existing electric-quote-string etc.
>>>   This could be in the form of syntactic elements or text properties.
>>>
>>>
>>>
>> I've attached a patch. It doesn't cover all cases, though; e.g. an
>> unterminated Markdown code span is not supported yet.
>>
>
> Pushed as 34d4720f83.
>

Here are a couple more patches.

[-- Attachment #1.2: Type: text/html, Size: 2306 bytes --]

[-- Attachment #2: 0001-Refactor-electric-quote-mode.txt --]
[-- Type: text/plain, Size: 6763 bytes --]

From 7d9439e3096a37ba381a9fd03d63d1b5fcf4683a Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Sun, 2 Jul 2017 18:03:06 +0200
Subject: [PATCH 1/3] Refactor 'electric-quote-mode'

* lisp/electric.el (electric-quote-post-self-insert-function): Remove
local variable 'start', which was misnamed and only used once.
---
 lisp/electric.el | 106 +++++++++++++++++++++++++++----------------------------
 1 file changed, 52 insertions(+), 54 deletions(-)

diff --git a/lisp/electric.el b/lisp/electric.el
index 1564df5949..103f378ed3 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -460,60 +460,58 @@ electric-quote-post-self-insert-function
   (when (and electric-quote-mode
              (or (eq last-command-event ?\')
                  (and (not electric-quote-context-sensitive)
-                      (eq last-command-event ?\`))))
-    (let ((start
-           (if (and comment-start comment-use-syntax)
-               (when (or electric-quote-comment electric-quote-string)
-                 (let* ((syntax (syntax-ppss))
-                        (beg (nth 8 syntax)))
-                   (and beg
-                        (or (and electric-quote-comment (nth 4 syntax))
-                            (and electric-quote-string (nth 3 syntax)))
-                        ;; Do not requote a quote that starts or ends
-                        ;; a comment or string.
-                        (eq beg (nth 8 (save-excursion
-                                         (syntax-ppss (1- (point)))))))))
-             (and electric-quote-paragraph
-                  (derived-mode-p 'text-mode)
-                  ;; FIXME: There should be a ‘cl-disjoint’ function.
-                  (null (cl-intersection (face-at-point nil 'multiple)
-                                         electric-quote-code-faces
-                                         :test #'eq))
-                  ;; FIXME: Why is the next form there?  It’s never
-                  ;; nil.
-                  (or (eq last-command-event ?\`)
-                      (save-excursion (backward-paragraph) (point)))))))
-      (pcase electric-quote-chars
-        (`(,q< ,q> ,q<< ,q>>)
-         (when start
-           (save-excursion
-             (let ((backtick ?\`))
-               (if (or (eq last-command-event ?\`)
-                       (and electric-quote-context-sensitive
-                            (save-excursion
-                              (backward-char)
-                              (or (bobp) (bolp)
-                                  (memq (char-before) (list q< q<<))
-                                  (memq (char-syntax (char-before))
-                                        '(?\s ?\())))
-                            (setq backtick ?\')))
-                   (cond ((search-backward (string q< backtick) (- (point) 2) t)
-                          (replace-match (string q<<))
-                          (when (and electric-pair-mode
-                                     (eq (cdr-safe
-                                          (assq q< electric-pair-text-pairs))
-                                         (char-after)))
-                            (delete-char 1))
-                          (setq last-command-event q<<))
-                         ((search-backward (string backtick) (1- (point)) t)
-                          (replace-match (string q<))
-                          (setq last-command-event q<)))
-                 (cond ((search-backward (string q> ?') (- (point) 2) t)
-                        (replace-match (string q>>))
-                        (setq last-command-event q>>))
-                       ((search-backward "'" (1- (point)) t)
-                        (replace-match (string q>))
-                        (setq last-command-event q>))))))))))))
+                      (eq last-command-event ?\`)))
+             (if (and comment-start comment-use-syntax)
+                 (when (or electric-quote-comment electric-quote-string)
+                   (let* ((syntax (syntax-ppss))
+                          (beg (nth 8 syntax)))
+                     (and beg
+                          (or (and electric-quote-comment (nth 4 syntax))
+                              (and electric-quote-string (nth 3 syntax)))
+                          ;; Do not requote a quote that starts or ends
+                          ;; a comment or string.
+                          (eq beg (nth 8 (save-excursion
+                                           (syntax-ppss (1- (point)))))))))
+               (and electric-quote-paragraph
+                    (derived-mode-p 'text-mode)
+                    ;; FIXME: There should be a ‘cl-disjoint’ function.
+                    (null (cl-intersection (face-at-point nil 'multiple)
+                                           electric-quote-code-faces
+                                           :test #'eq))
+                    ;; FIXME: Why is the next form there?  It’s never
+                    ;; nil.
+                    (or (eq last-command-event ?\`)
+                        (save-excursion (backward-paragraph) (point))))))
+    (pcase electric-quote-chars
+      (`(,q< ,q> ,q<< ,q>>)
+       (save-excursion
+         (let ((backtick ?\`))
+           (if (or (eq last-command-event ?\`)
+                   (and electric-quote-context-sensitive
+                        (save-excursion
+                          (backward-char)
+                          (or (bobp) (bolp)
+                              (memq (char-before) (list q< q<<))
+                              (memq (char-syntax (char-before))
+                                    '(?\s ?\())))
+                        (setq backtick ?\')))
+               (cond ((search-backward (string q< backtick) (- (point) 2) t)
+                      (replace-match (string q<<))
+                      (when (and electric-pair-mode
+                                 (eq (cdr-safe
+                                      (assq q< electric-pair-text-pairs))
+                                     (char-after)))
+                        (delete-char 1))
+                      (setq last-command-event q<<))
+                     ((search-backward (string backtick) (1- (point)) t)
+                      (replace-match (string q<))
+                      (setq last-command-event q<)))
+             (cond ((search-backward (string q> ?') (- (point) 2) t)
+                    (replace-match (string q>>))
+                    (setq last-command-event q>>))
+                   ((search-backward "'" (1- (point)) t)
+                    (replace-match (string q>))
+                    (setq last-command-event q>))))))))))
 
 (put 'electric-quote-post-self-insert-function 'priority 10)
 
-- 
2.13.2


[-- Attachment #3: 0003-Further-improve-electric-quote-support-for-Markdown-Bu.txt --]
[-- Type: text/plain, Size: 4844 bytes --]

From 1a4d0ada2450f22246ad22d25e7c15d8da3c5249 Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Sun, 2 Jul 2017 18:14:21 +0200
Subject: [PATCH 3/3] Further improve electric quote support for Markdown
 (Bug#24709)

Markdown sets both 'comment-start' and 'comment-use-syntax' to non-nil
values.  Therefore 'electric-quote-mode' recognized it as a
programming mode.  Fix this by first checking whether the current
major mode is derived from 'text-mode'.

* lisp/electric.el (electric-quote-post-self-insert-function): Treat
'text-mode' as stronger signal than comment syntax.

* test/lisp/electric-tests.el (electric-quote-markdown-in-text)
(electric-quote-markdown-in-code): Adapt unit tests.
---
 lisp/electric.el            | 34 +++++++++++++++++-----------------
 test/lisp/electric-tests.el |  8 ++++++--
 2 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/lisp/electric.el b/lisp/electric.el
index a1e9079cb1..c335ae5d72 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -461,23 +461,23 @@ electric-quote-post-self-insert-function
              (or (eq last-command-event ?\')
                  (and (not electric-quote-context-sensitive)
                       (eq last-command-event ?\`)))
-             (if (and comment-start comment-use-syntax)
-                 (when (or electric-quote-comment electric-quote-string)
-                   (let* ((syntax (syntax-ppss))
-                          (beg (nth 8 syntax)))
-                     (and beg
-                          (or (and electric-quote-comment (nth 4 syntax))
-                              (and electric-quote-string (nth 3 syntax)))
-                          ;; Do not requote a quote that starts or ends
-                          ;; a comment or string.
-                          (eq beg (nth 8 (save-excursion
-                                           (syntax-ppss (1- (point)))))))))
-               (and electric-quote-paragraph
-                    (derived-mode-p 'text-mode)
-                    ;; FIXME: There should be a ‘cl-disjoint’ function.
-                    (null (cl-intersection (face-at-point nil 'multiple)
-                                           electric-quote-code-faces
-                                           :test #'eq)))))
+             (if (derived-mode-p 'text-mode)
+                 (and electric-quote-paragraph
+                      ;; FIXME: There should be a ‘cl-disjoint’ function.
+                      (null (cl-intersection (face-at-point nil 'multiple)
+                                             electric-quote-code-faces
+                                             :test #'eq)))
+               (and comment-start comment-use-syntax
+                    (or electric-quote-comment electric-quote-string)
+                    (let* ((syntax (syntax-ppss))
+                           (beg (nth 8 syntax)))
+                      (and beg
+                           (or (and electric-quote-comment (nth 4 syntax))
+                               (and electric-quote-string (nth 3 syntax)))
+                           ;; Do not requote a quote that starts or ends
+                           ;; a comment or string.
+                           (eq beg (nth 8 (save-excursion
+                                            (syntax-ppss (1- (point)))))))))))
     (pcase electric-quote-chars
       (`(,q< ,q> ,q<< ,q>>)
        (save-excursion
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index 6f63d30e75..4212198b0a 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -694,11 +694,14 @@ electric-quote-context-sensitive-after-paren-double
   :bindings '((electric-quote-context-sensitive . t))
   :test-in-comments nil :test-in-strings nil)
 
+;; Simulate ‘markdown-mode’: it sets both ‘comment-start’ and
+;; ‘comment-use-syntax’, but derives from ‘text-mode’.
 (define-electric-pair-test electric-quote-markdown-in-text
   "" "'" :expected-string "’" :expected-point 2
   :modes '(text-mode)
   :fixture-fn #'electric-quote-local-mode
-  :bindings '((electric-quote-code-faces font-lock-constant-face))
+  :bindings '((electric-quote-code-faces font-lock-constant-face)
+              (comment-start "<!--") (comment-use-syntax t))
   :test-in-comments nil :test-in-strings nil)
 
 (define-electric-pair-test electric-quote-markdown-in-code
@@ -706,7 +709,8 @@ electric-quote-markdown-in-code
   :expected-string "`'a`" :expected-point 3
   :modes '(text-mode)
   :fixture-fn #'electric-quote-local-mode
-  :bindings '((electric-quote-code-faces font-lock-constant-face))
+  :bindings '((electric-quote-code-faces font-lock-constant-face)
+              (comment-start "<!--") (comment-use-syntax t))
   :test-in-comments nil :test-in-strings nil)
 
 (provide 'electric-tests)
-- 
2.13.2


[-- Attachment #4: 0002-Remove-pointless-code-in-electric-quote-mode.txt --]
[-- Type: text/plain, Size: 1245 bytes --]

From 0acddd26f1bdb9b08dea9812af2883925e023557 Mon Sep 17 00:00:00 2001
From: Philipp Stephani <phst@google.com>
Date: Sun, 2 Jul 2017 18:04:38 +0200
Subject: [PATCH 2/3] Remove pointless code in 'electric-quote-mode'

* lisp/electric.el (electric-quote-post-self-insert-function): Remove
pointless form.
---
 lisp/electric.el | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/lisp/electric.el b/lisp/electric.el
index 103f378ed3..a1e9079cb1 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -477,11 +477,7 @@ electric-quote-post-self-insert-function
                     ;; FIXME: There should be a ‘cl-disjoint’ function.
                     (null (cl-intersection (face-at-point nil 'multiple)
                                            electric-quote-code-faces
-                                           :test #'eq))
-                    ;; FIXME: Why is the next form there?  It’s never
-                    ;; nil.
-                    (or (eq last-command-event ?\`)
-                        (save-excursion (backward-paragraph) (point))))))
+                                           :test #'eq)))))
     (pcase electric-quote-chars
       (`(,q< ,q> ,q<< ,q>>)
        (save-excursion
-- 
2.13.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
  2017-07-02 16:20     ` Philipp Stephani
@ 2017-07-09 19:57       ` Philipp Stephani
  0 siblings, 0 replies; 7+ messages in thread
From: Philipp Stephani @ 2017-07-09 19:57 UTC (permalink / raw)
  To: 24709

[-- Attachment #1: Type: text/plain, Size: 1481 bytes --]

Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 2. Juli 2017 um
18:19 Uhr:

> Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 2. Juli 2017 um
> 17:49 Uhr:
>
>> Philipp Stephani <p.stephani2@gmail.com> schrieb am Mi., 28. Juni 2017
>> um 23:59 Uhr:
>>
>>> Philipp Stephani <p.stephani2@gmail.com> schrieb am So., 16. Okt. 2016
>>> um 19:22 Uhr:
>>>
>>>>
>>>> When editing a Markdown document with electric-quote-mode enabled, the
>>>> experience is not optimal because ` (backtick) in Markdown is a syntax
>>>> element (for introducing code spans and blocks), but is converted by
>>>> electric-quote-mode.  Also ` and ' inside code spans and blocks continue
>>>> to insert curly quotes where they shouldn't.  I propose the following:
>>>>
>>>> - Provide an alternative behavior of electric-quote-mode where ` doesn't
>>>>   trigger replacement and ' can insert left or right curly quotes,
>>>>   depending on whether it follows a space or similar (newline, beginning
>>>>   of buffer, opening parenthesis).
>>>>
>>>> - Provide a way to disable electric-quote-mode for certain regions,
>>>>   effectively the inverse of the existing electric-quote-string etc.
>>>>   This could be in the form of syntactic elements or text properties.
>>>>
>>>>
>>>>
>>> I've attached a patch. It doesn't cover all cases, though; e.g. an
>>> unterminated Markdown code span is not supported yet.
>>>
>>
>> Pushed as 34d4720f83.
>>
>
> Here are a couple more patches.
>

All pushed.

[-- Attachment #2: Type: text/html, Size: 2738 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#24709: 26.0.50; Support for Markdown in electric-quote-mode
  2016-10-16 17:19 bug#24709: 26.0.50; Support for Markdown in electric-quote-mode Philipp Stephani
  2016-10-19 11:10 ` Alan Third
  2017-06-28 21:59 ` Philipp Stephani
@ 2017-07-14 12:36 ` Paul Eggert
  2 siblings, 0 replies; 7+ messages in thread
From: Paul Eggert @ 2017-07-14 12:36 UTC (permalink / raw)
  To: Philipp Stephani; +Cc: 24709-done

As the bug appears to be fixed, I'm taking the liberty of closing the bug report.





^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-07-14 12:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-16 17:19 bug#24709: 26.0.50; Support for Markdown in electric-quote-mode Philipp Stephani
2016-10-19 11:10 ` Alan Third
2017-06-28 21:59 ` Philipp Stephani
2017-07-02 15:49   ` Philipp Stephani
2017-07-02 16:20     ` Philipp Stephani
2017-07-09 19:57       ` Philipp Stephani
2017-07-14 12:36 ` Paul Eggert

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).