From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Paul Eggert Newsgroups: gmane.emacs.bugs Subject: bug#20545: New minor mode Electric Quote Date: Tue, 26 May 2015 04:24:12 -0700 Organization: UCLA Computer Science Department Message-ID: <556457DC.5050301@cs.ucla.edu> References: <554FEFFE.7000303@cs.ucla.edu> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------040500010803080906040702" X-Trace: ger.gmane.org 1432639536 11657 80.91.229.3 (26 May 2015 11:25:36 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 26 May 2015 11:25:36 +0000 (UTC) Cc: Artur Malabarba To: 20545@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Tue May 26 13:25:24 2015 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1YxCyv-0007he-Pn for geb-bug-gnu-emacs@m.gmane.org; Tue, 26 May 2015 13:25:14 +0200 Original-Received: from localhost ([::1]:47193 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YxCyv-0004LM-3x for geb-bug-gnu-emacs@m.gmane.org; Tue, 26 May 2015 07:25:13 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:49849) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YxCyo-0004EE-U2 for bug-gnu-emacs@gnu.org; Tue, 26 May 2015 07:25:08 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YxCyl-0007IR-Jb for bug-gnu-emacs@gnu.org; Tue, 26 May 2015 07:25:06 -0400 Original-Received: from debbugs.gnu.org ([140.186.70.43]:46341) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YxCyl-0007Hl-F7 for bug-gnu-emacs@gnu.org; Tue, 26 May 2015 07:25:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.80) (envelope-from ) id 1YxCyl-0004RV-0D for bug-gnu-emacs@gnu.org; Tue, 26 May 2015 07:25:03 -0400 X-Loop: help-debbugs@gnu.org In-Reply-To: <554FEFFE.7000303@cs.ucla.edu> Resent-From: Paul Eggert Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 26 May 2015 11:25:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 20545 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 20545-submit@debbugs.gnu.org id=B20545.143263946617028 (code B ref 20545); Tue, 26 May 2015 11:25:02 +0000 Original-Received: (at 20545) by debbugs.gnu.org; 26 May 2015 11:24:26 +0000 Original-Received: from localhost ([127.0.0.1]:56316 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1YxCy8-0004QY-Np for submit@debbugs.gnu.org; Tue, 26 May 2015 07:24:26 -0400 Original-Received: from smtp.cs.ucla.edu ([131.179.128.62]:33526) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1YxCy4-0004QH-MN for 20545@debbugs.gnu.org; Tue, 26 May 2015 07:24:22 -0400 Original-Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp.cs.ucla.edu (Postfix) with ESMTP id B0E82A6000C; Tue, 26 May 2015 04:24:13 -0700 (PDT) X-Virus-Scanned: amavisd-new at smtp.cs.ucla.edu Original-Received: from smtp.cs.ucla.edu ([127.0.0.1]) by localhost (smtp.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 84-gu6u6tQIb; Tue, 26 May 2015 04:24:12 -0700 (PDT) Original-Received: from [192.168.1.9] (pool-100-32-155-148.lsanca.fios.verizon.net [100.32.155.148]) by smtp.cs.ucla.edu (Postfix) with ESMTPSA id 3421EA60004; Tue, 26 May 2015 04:24:12 -0700 (PDT) User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.15 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:103182 Archived-At: This is a multi-part message in MIME format. --------------040500010803080906040702 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Attached is a revised patch that should address the comments raised: * The new minor mode is now disabled by default. * The patch doesn't affect .dir-locals.el. * The new minor mode is now (less ambitiously) called Electric Quote mode, not Electric Punct mode. * Electric Quote mode combines well with Electric Pair mode's pairings of ` and ', turning them into electric ‘ and ’. I did not implement the electric quote pairing of “ and ”, as it would be trickier to add and anyway any such pairing is considerably lower priority for Elisp. Plus another issue I found while testing: * Electric quoting is now inactive in buffers whose coding systems can't represent curved quotes. --------------040500010803080906040702 Content-Type: text/x-patch; name="0001-New-minor-mode-Electric-Quote.patch" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0001-New-minor-mode-Electric-Quote.patch" >From f3f584027819837c26adc311a936e7a897c92f44 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 26 May 2015 03:53:50 -0700 Subject: [PATCH] New minor mode Electric Quote MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- doc/emacs/basic.texi | 6 +++ doc/emacs/modes.texi | 9 ++++ doc/emacs/text.texi | 38 +++++++++++++++ etc/NEWS | 2 + lisp/electric.el | 109 +++++++++++++++++++++++++++++++++++++++++++ lisp/progmodes/elisp-mode.el | 3 +- 6 files changed, 166 insertions(+), 1 deletion(-) diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index be45856..cc9602e 100644 --- a/doc/emacs/basic.texi +++ b/doc/emacs/basic.texi @@ -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 diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi index 0e8f46a..b4538db 100644 --- a/doc/emacs/modes.texi +++ b/doc/emacs/modes.texi @@ -200,6 +200,15 @@ 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 +@cindex Electric Quote mode +@cindex mode, Electric Quote +@findex electric-quote-mode +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}. diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 9bc5ade..f243095 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -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,43 @@ 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 + 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 unambiguous 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. + + 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 diff --git a/etc/NEWS b/etc/NEWS index 1cccc31..3c0b2cf 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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 diff --git a/lisp/electric.el b/lisp/electric.el index dd7767f..a1fd6e9 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -413,6 +413,115 @@ 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." + ;; (check-coding-systems-region "‘’“”" nil (list buffer-file-coding-system))) + (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 diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index e06b920..22f66a9 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -231,7 +231,8 @@ Blank lines separate paragraphs. Semicolons start comments. (lisp-mode-variables nil nil 'elisp) (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) (setq-local electric-pair-text-pairs - (cons '(?\` . ?\') electric-pair-text-pairs)) + `((?‘ . ?’) (?\` . ?\') ,@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) -- 2.1.0 --------------040500010803080906040702--