1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

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.
This commit is contained in:
Philipp Stephani 2017-06-28 23:47:57 +02:00
parent d90b98a2a5
commit 34d4720f83
3 changed files with 179 additions and 19 deletions

View file

@ -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

View file

@ -443,11 +443,24 @@ quote, left double quote, and right double quote, respectively."
: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 @@ This requotes when a quoting key is typed."
(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? Its 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)

View file

@ -593,5 +593,121 @@ baz\"\""
: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