Commit 73512b8c authored by Paul Eggert's avatar Paul Eggert
Browse files

New minor mode Electric Quote

This lets you easily insert quotes ‘like this’ by typing
quotes `like this', and similarly you can easily insert
quotes “like this” by typing quotes ``like this'' (Bug#20545).
* doc/emacs/basic.texi (Inserting Text):
* doc/emacs/modes.texi (Minor Modes):
* etc/NEWS: Document it.
* doc/emacs/text.texi (Quotation Marks): New section.
* lisp/electric.el (electric-quote-comment)
(electric-quote-string, electric-quote-paragraph):
New custom vars.
(electric--insertable-p)
(electric-quote-post-self-insert-function): New functions.
(electric-quote-mode, electric-quote-local-mode): New minor modes.
* lisp/progmodes/elisp-mode.el (emacs-lisp-mode):
Add curved single quotes to electric-pair-text-pairs.
Set electric-quote-string in this buffer.
parent 4643f6c2
......@@ -127,6 +127,12 @@ sign (Unicode code-point @code{U+221E}):
A numeric argument to @kbd{C-q} or @kbd{C-x 8 @key{RET}} specifies
how many copies of the character to insert (@pxref{Arguments}).
In some contexts, if you type a quotation using grave accent and
apostrophe @t{`like this'}, it is converted to a form @t{‘like this’}
using single quotation marks. Similarly, typing a quotation @t{``like
this''} using double grave accent and apostrophe converts it to a form
@t{“like this”} using double quotation marks. @xref{Quotation Marks}.
@node Moving Point
@section Changing the Location of Point
......
......@@ -199,6 +199,12 @@ becoming too long. @xref{Filling}.
Auto Save mode saves the buffer contents periodically to reduce the
amount of work you can lose in case of a crash. @xref{Auto Save}.
@item
Electric Quote mode automatically converts quotation marks. For
example, it requotes text typed @t{`like this'} to text @t{‘like
this’}. You can control what kind of text it operates in, and you can
disable it entirely in individual buffers. @xref{Quotation Marks}.
@item
Enriched mode enables editing and saving of formatted text.
@xref{Enriched Text}.
......
......@@ -69,6 +69,7 @@ for editing such pictures.
* Sentences:: Moving over and killing sentences.
* Paragraphs:: Moving over paragraphs.
* Pages:: Moving over pages.
* Quotation Marks:: Inserting quotation marks.
* Filling:: Filling or justifying text.
* Case:: Changing the case of text.
* Text Mode:: The major modes for editing text files.
......@@ -404,6 +405,47 @@ that separates pages (@pxref{Regexps}). The normal value of this
variable is @code{"^\f"}, which matches a formfeed character at the
beginning of a line.
@node Quotation Marks
@section Quotation Marks
@cindex Quotation marks
@cindex Electric Quote mode
@cindex mode, Electric Quote
@findex electric-quote-mode
One common way to quote is the typewriter convention, which quotes
using straight apostrophes @t{'like this'} or double-quotes @t{"like
this"}. Another common way is the curved quote convention, which uses
left and right single or double quotation marks @t{‘like this’} or
@t{“like this”}. Typewriter quotes are simple and portable; curved
quotes are less ambiguous and typically look nicer.
Electric Quote mode makes it easier to type curved quotes. It
optionally converts a quotation's grave accent and apostrophe @t{`like
this'} to single quotation marks @t{‘like this’}. Similarly, it
converts a quotation's double grave accent and double apostrophe
@t{``like this''} to double quotation marks @t{“like this”}. These
conversions are suppressed in buffers whose coding systems cannot
represent curved quote characters.
@vindex electric-quote-paragraph
@vindex electric-quote-comment
@vindex electric-quote-string
You can customize the behavior of Electric Quote mode by customizing
variables that control where it is active. It is active in text
paragraphs if @code{electric-quote-paragraph} is non-@code{nil}, in
programming-language comments if @code{electric-quote-comment} is
non-@code{nil}, and in programming-language strings if
@code{electric-quote-string} is non-@code{nil}. The default is
@code{nil} for @code{electric-quote-string} and @code{t} for the other
variables.
Electric Quote mode is disabled by default. To toggle it, type
@kbd{M-x electric-quote-mode}. To toggle it in a single buffer, use
@kbd{M-x electric-quote-local-mode}. To suppress it for a single use,
type @kbd{C-q `} or @kbd{C-q '} instead of @kbd{`} or @kbd{'}. To
insert a curved quote even when Electric Quote is disabled or
inactive, use @kbd{C-x 8 @key{RET}} (@code{insert-char}).
@xref{Inserting Text}.
@node Filling
@section Filling Text
@cindex filling text
......
......@@ -226,6 +226,8 @@ successive char insertions.
** C-x 8 now has shorthands for these chars:
. As before, you can type C-x 8 C-h to list shorthands.
** New minor mode electric-quote-mode for quoting like this and like this.
** New minor mode global-eldoc-mode is enabled by default.
** Emacs now supports "bracketed paste mode" when running on a terminal
......
......@@ -413,6 +413,114 @@ The variable `electric-layout-rules' says when and how to insert newlines."
(remove-hook 'post-self-insert-hook
#'electric-layout-post-self-insert-function))))
;;; Electric quoting.
(defcustom electric-quote-comment t
"Non-nil means to use electric quoting in program comments."
:type 'boolean :safe 'booleanp :group 'electricity)
(defcustom electric-quote-string nil
"Non-nil means to use electric quoting in program strings."
:type 'boolean :safe 'booleanp :group 'electricity)
(defcustom electric-quote-paragraph t
"Non-nil means to use electric quoting in text paragraphs."
:type 'boolean :safe 'booleanp :group 'electricity)
(defun electric--insertable-p (string)
(not (unencodable-char-position nil nil buffer-file-coding-system
nil string)))
(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 '(?\' ?\`)))
(let ((start
(if comment-start
(when (or electric-quote-comment electric-quote-string)
(let ((syntax (syntax-ppss)))
(and (or (and electric-quote-comment (nth 4 syntax))
(and electric-quote-string (nth 3 syntax)))
(nth 8 syntax))))
(and electric-quote-paragraph
(derived-mode-p 'text-mode)
(or (eq last-command-event ?\`)
(save-excursion (backward-paragraph) (point)))))))
(when start
(save-excursion
(if (eq last-command-event ?\`)
(cond ((and (electric--insertable-p "“")
(re-search-backward "[`‘]`" (- (point) 2) t))
(replace-match "“")
(when (and electric-pair-mode
(eq (cdr-safe
(assq ? electric-pair-text-pairs))
(char-after)))
(delete-char 1))
(setq last-command-event ?))
((and (electric--insertable-p "‘")
(search-backward "`" (1- (point)) t))
(replace-match "‘")
(setq last-command-event ?)))
(let ((pos (point)))
(if (memq (char-before (1- (point))) '(?\' ?))
(when (and (search-backward "“" start t)
(eq pos (re-search-forward
"“\\(\\([^‘”]\\|‘[^‘’”]*’\\)*\\)['’]'"
pos t)))
(replace-match "“\\1”")
(setq last-command-event ?))
(when (and (search-backward "‘" start t)
(eq pos (re-search-forward
"‘\\([^’]*\\)'" pos t)))
(replace-match "‘\\1’")
(setq last-command-event ?))))))))))
(put 'electric-quote-post-self-insert-function 'priority 10)
;;;###autoload
(define-minor-mode electric-quote-mode
"Toggle on-the-fly requoting (Electric Quote mode).
With a prefix argument ARG, enable Electric Quote mode if
ARG is positive, and disable it otherwise. If called from Lisp,
enable the mode if ARG is omitted or nil.
When enabled, this replaces \\=`foo bar' with ‘foo bar’ and replaces
\\=`\\=`foo bar'' with “foo bar” as you type. This occurs only in
comments, strings, and text paragraphs, and these are selectively
controlled with ‘electric-quote-comment’,
‘electric-quote-string’, and ‘electric-quote-paragraph’.
This is a global minor mode. To toggle the mode in a single buffer,
use ‘electric-quote-local-mode’."
:global t :group 'electricity
:initialize 'custom-initialize-delay
:init-value nil
(if (not electric-quote-mode)
(unless (catch 'found
(dolist (buf (buffer-list))
(with-current-buffer buf
(if electric-quote-mode (throw 'found t)))))
(remove-hook 'post-self-insert-hook
#'electric-quote-post-self-insert-function))
(add-hook 'post-self-insert-hook
#'electric-quote-post-self-insert-function)
(electric--sort-post-self-insertion-hook)))
;;;###autoload
(define-minor-mode electric-quote-local-mode
"Toggle ‘electric-quote-mode’ only in this buffer."
:variable (buffer-local-value 'electric-quote-mode (current-buffer))
(cond
((eq electric-quote-mode (default-value 'electric-quote-mode))
(kill-local-variable 'electric-quote-mode))
((not (default-value 'electric-quote-mode))
;; Locally enabled, but globally disabled.
(electric-quote-mode 1) ; Setup the hooks.
(setq-default electric-quote-mode nil) ; But keep it globally disabled.
)))
(provide 'electric)
;;; electric.el ends here
......@@ -232,6 +232,7 @@ Blank lines separate paragraphs. Semicolons start comments.
(add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers)
(setq-local electric-pair-text-pairs
(append '((?\` . ?\') (? . ?)) electric-pair-text-pairs))
(setq-local electric-quote-string t)
(setq imenu-case-fold-search nil)
(add-function :before-until (local 'eldoc-documentation-function)
#'elisp-eldoc-documentation-function)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment