From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Michal Nazarewicz Newsgroups: gmane.emacs.devel Subject: Electric punctuation mode Date: Tue, 02 Feb 2016 17:37:44 +0100 Organization: Google Inc Message-ID: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: ger.gmane.org 1454431099 25321 80.91.229.3 (2 Feb 2016 16:38:19 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 2 Feb 2016 16:38:19 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Feb 02 17:38:18 2016 Return-path: Envelope-to: ged-emacs-devel@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 1aQdy5-00087t-Dx for ged-emacs-devel@m.gmane.org; Tue, 02 Feb 2016 17:38:17 +0100 Original-Received: from localhost ([::1]:58041 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQdy1-0001A1-Cd for ged-emacs-devel@m.gmane.org; Tue, 02 Feb 2016 11:38:13 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:59607) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQdxg-00019X-J3 for emacs-devel@gnu.org; Tue, 02 Feb 2016 11:37:57 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aQdxc-0002Se-0N for emacs-devel@gnu.org; Tue, 02 Feb 2016 11:37:52 -0500 Original-Received: from mail-wm0-x236.google.com ([2a00:1450:400c:c09::236]:35701) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aQdxb-0002SS-Dh for emacs-devel@gnu.org; Tue, 02 Feb 2016 11:37:47 -0500 Original-Received: by mail-wm0-x236.google.com with SMTP id r129so126467817wmr.0 for ; Tue, 02 Feb 2016 08:37:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:from:to:subject:organization:user-agent:face:date:message-id :mime-version:content-type:content-transfer-encoding; bh=mH2b6pk6OxgMpV5RkGx/6iCDraxfTY2byScybPn4Hpo=; b=fAA0TnkHe145+KkjB//MJ0Y5ugvmeeEoVV/5Uq8mEgtZ5XGTMqKov0emPZpRZNWUIg FXc+ja/LOTHheY1xyRr9HZ2pKZQwSgHX8woAHa9+YVxLnr5wSspJSXEIOYZ7KYOE4FIY nQ3KnQ70nzuPLFfPBIgEi48nXWsWlu+9WphNqUfHEPFP+5bMfS8a2gyCi2HE0lDnPFgt aGzgCdnqcm7WMRfzKuU7uuhMRD6mMrozxmb2VnF5ORhTj5yXqo+WRuqyZ3P9J2gjgmqj FsZ6Jc0FaKipjie2eBXg18NzLZEkZa1kUMVSJjbtPKQy0yQGFBZIKto28l0bZPg1xSfL HphA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:subject:organization:user-agent :face:date:message-id:mime-version:content-type :content-transfer-encoding; bh=mH2b6pk6OxgMpV5RkGx/6iCDraxfTY2byScybPn4Hpo=; b=Of0fgWMXAL+gF29MC2NvCCNdtTdca+mw1VKoCC4jsumz89mPFxizq2ybbd/L/8oGau gHRs311hlehCpAXryGJAC245UN1K4eRTGaZt+Q2g0gZ9gtPNPrz3ErBYJgpq5asuxBxk mToM2pODdQO3mh3y+IVvHawq5V7IuJh/TZuJ8sdeqCvUOsRSvEJEOnkBlqvsHxsNjnCF lmAsbhnK/eq+AtOsOP2cYXVF8LBE0PSpOQsFgkn95EfOMcznQXsCCtHDZ76rcTTfPEps 4IPVUX+xNumzg3lQjv4YnMLESZSRSRKzmWd5axGsKvp0MJKGG9+V2LdONG5ZDSIESyiF lB9Q== X-Gm-Message-State: AG10YOS6KB3MOIVxxnZjCSUBioo585keu7Jp2gsMsHu3JysQkgharVOh5YPKU+gL1RvG9X2G X-Received: by 10.194.89.72 with SMTP id bm8mr28952578wjb.60.1454431066354; Tue, 02 Feb 2016 08:37:46 -0800 (PST) Original-Received: from mpn-glaptop ([2620:0:105f:310:148:794b:3b2:788a]) by smtp.gmail.com with ESMTPSA id l194sm17403126wmb.14.2016.02.02.08.37.45 for (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 02 Feb 2016 08:37:45 -0800 (PST) User-Agent: Notmuch/0.19+53~g2e63a09 (http://notmuchmail.org) Emacs/25.1.50.1 (x86_64-unknown-linux-gnu) Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAJFBMVEWbfGlUPDDHgE57V0jUupKjgIObY0PLrom9mH4dFRK4gmjPs41MxjOgAAACP0lEQVQ4T23Sv2vbQBQHcBk1xE6WyALX107VUEgmn6+ouUwpEQQ6uRjttkWP4CkBg2M0BQLBdPFZYPsyFYo7qEtKDQ7on+t7+nF2Ux8ahD587717OmNYrOvycHsZ+o2r051wHTHysAvGb8ygvgu4QWT0sCmkgZCIEnlV2X8BtyraazFGDuxhmKSQJMlwHQ7v5MHSNxmz78rfElwAa3ieVD9e+hBhjaPDDG6NgFo2f4wBMNIo5YmRtF0RyDgFjJjlMIWbnuM4x9MMfABGTlN4qgIQB4A1DEyA1BHWtfeWNUMwiVJKoqh97KrkOO+qzgluVYLvFCUKAX73nONeBr7BGMdM6Sg0kuep03VywLaIzRiVr+GAzKlpQIsAFnWAG2e6DT5WmWDiudZMIc6hYrMOmeMQK9WX0B+/RfjzL9DI7Y9/Iayn29Ci0r2i4f9gMimMSZLCDMalgQGU5hnUtqAN0OGvEmO1Wnl0C0wWSCEHnuHBqmygxdxA8oWXwbipoc1EoNR9DqOpBpOJrnr0criQab9ZT4LL+wI+K7GBQH30CrhUruilgP9DRTrhVWZCiAyILP+wiuLeCKGTD6r/nc8LOJcAwR6IBTUs+7CASw3QFZ0MdA2PI3zNziH4ZKVhXCRMBjeZ1DWMekKwDCASwExy+NQ86TaykaDAFHO4aP48y4 fIcDM5yOG8GcTLbOyp8A8azjJI93JFd1EA6yN8sSxMQJWoABqniRZVykYgRXErzrdqExAoUrRb0xfRp8p2A/4XmfilTtkDZ4cAAAAASUVORK5CYII= X-Face: -TR8(rDTHy/(xl?SfWd1|3:TTgDIatE^t'vop%*gVg[kn$t{EpK(P"VQ=~T2#ysNmJKN$"yTRLB4YQs$4{[.]Fc1)*O]3+XO^oXM>Q#b^ix, O)Zbn)q[y06$`e3?C)`CwR9y5riE=fv^X@x$y?D:XO6L&x4f-}}I4=VRNwiA^t1-ZrVK^07.Pi/57c_du'& X-PGP: 50751FF4 X-PGP-FP: AC1F 5F5C D418 88F8 CC84 5858 2060 4012 5075 1FF4 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::236 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:199172 Archived-At: Hi guys, For quite a while now I=E2=80=99ve been testing =E2=80=98electric-punc-mode= =E2=80=99 attached below. The idea behind it is to write Unicode characters using nothing but ASCII. For example, as one types =E2=80=98...=E2=80=99, it gets replaced w= ith an ellipsis, =E2=80=98<<=E2=80=99 is replaced by =E2=80=98=C2=AB=E2=80=99, =E2= =80=98<=3D=E2=80=99 becomes =E2=80=98=E2=89=A4=E2=80=99 and so forth. It=E2=80=99s actually a superset of electric-quote-mode so perhaps it would= make sense to have it merged and implement electric-quote-mode as special case of electric-punct-mode? --=20 Best regards Liege of Serenely Enlightened Majesty of Computer Science, =E3=83=9F=E3=83=8F=E3=82=A6 =E2=80=9Cmina86=E2=80=9D =E3=83=8A=E3=82=B6=E3= =83=AC=E3=83=B4=E3=82=A4=E3=83=84 ---- >8 ---------------------------------------------------------------- ;;; electric-punct.el --- Makes entering Unicode punctuation characters eas= ier. -*- lexical-binding: t; coding: utf-8 -*- ;; Copyright 2014 Google Inc. ;; Author: Michal Nazarewicz ;; Maintainer: Michal Nazarewicz ;; Version: 0.3 ;; Keywords: text, unicode, punctuation, convenience ;; This file is not part of GNU Emacs. ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; INTRODUCTION ;; ;; Helps insert Unicode punctuation and space characters by just typing ;; ASCII characters. This is done by inspecting context of inserted ;; character and replacing ordinary sequences of ASCII characters by ;; Unicode characters. ;; ;; For example=C2=A0=E2=80=93=C2=A0if one types minus sign twice, it is= converted to an ;; en-dash (just like I've done after =E2=80=9CFor example=E2=80=9D at = the beginning of ;; the sentence), and pressing minus sign again converts the character = to ;; an em-dash, and one more press on minus further converts the dash to ;; a horizontal bar. Space characters around the dash is also affected= to ;; be typographically more correct. ;; DEFAULT RULES ;; ;; The set of expansion rules defined in the default set is as follows: ;; * Space typed after a Unicode space converts it to a regular space. ;; * Space typed after minus sign, en-dash, em-dash or horizontal bar ;; inserts space character preceding the dash character or an ;; appropriate for given dash (customisable). ;; * A minus sign typed after a minus sign, en-dash or em-dash convert = the ;; dash before point into en-dash, em-dash or horizontal bar ;; respectively and if the dash is proceeded by a space character ;; converts it to space appropriate for given dash. ;; * A =E2=80=9C=E2=80=9D sequence is conver= ted to ;; =E2=80=9C=E2=80=9D which works better fo= r thousands ;; separator is customisable). ;; * A thin space is inserted between two consecutive quotes characters, ;; for example in =E2=80=9Cnever say =E2=80=98never=E2=80=99=E2=80=89= =E2=80=9D a thin space is added between ;; closing quotes; This works even if the second closing quote is ;; entered using two apostrophes (see below). ;; * The following sequences are converted into Unicode characters: ;; Sequence Becames ;; ... =E2=80=A6 ellipsis ;; ,, =E2=80=9E double low-9 quotation mark ;; '' =E2=80=9D right double quotation mark ;; `` =E2=80=9C left double quotation mark ;; << =C2=AB left-pointing double angle quotation mark ;; <<< =E2=89=AA much less-than ;; >> =C2=BB right-pointing double angle quotation mark ;; >>> =E2=89=AB much greater-than ;; >=3D =E2=89=A5 greater-than or equal to ;; <=3D =E2=89=A4 less-than or equal to ;; <- =E2=86=90 leftwards arrow ;; -> =E2=86=92 rightwards arrow ;; !=3D =E2=89=A0 not equal to ;; /=3D =E2=89=A0 not equal to ;; !~ =E2=89=81 not tilde ;; /~ =E2=89=81 not tilde ;; !~=3D =E2=89=84 not asymptotically equal to ;; /~=3D =E2=89=84 not asymptotically equal to ;; !=3D=3D =E2=89=87 neither approximately nor actually eq= ual to ;; /=3D=3D =E2=89=87 neither approximately nor actually eq= ual to ;; ~=3D =E2=89=88 almost equal to ;; <=3D=3D =E2=87=90 leftwards double arrow ;; =3D> =E2=87=92 rightwards double arrow ;; <=3D> =E2=87=94 left right double arrow ;; * Furthermore in major modes for editing HTML, XML and SGML files, if ;; space is typed after an entity referencing a Unicode space ;; (e.g. =E2=80=9C =E2=80=9D or =E2=80=9C =E2=80=9D conve= rts the entity into a simple ASCII ;; space. ;; * And also in such modes, the following rules are applied (some of t= hem ;; overwrite the more general rules above): ;; Sequence Becames ;; << < ;; >> > ;; && & ;; "" " ;; USAGE ;; ;; The simplest way to enable `electric-punct-mode' is to call: ;; ;; M-x electric-punct-auto-mode RET ;; ;; It will determine whether current major mode is programming mode and= if ;; so enable `electric-punct-mode' only for comments and strings. If ;; current major mode is not a programming mode, `electric-punct-mode' ;; will be enabled throughout the buffer. ;; ;; The mode can also be enabled globally by: ;; ;; M-x global-electric-punct-mode RET ;; ;; To keep the mode enabled across Emacs restarts, add the following to ;; the init file: ;; ;; (global-electric-punct-mode 1) ;; CUSTOMISATION ;; ;; The mode is customised via `electric-punct' customise group which ;; contains the following variables: ;; * electric-punct-treat-dash-spacing=C2=A0=E2=80=93=C2=A0enables spac= ing manipulation ;; around dashes; if non-nil, the following variables take effect: ;; - electric-punct-en-dash-space=C2=A0=E2=80=93=C2=A0space to use ar= ound an en-dash ;; - electric-punct-em-dash-space=C2=A0=E2=80=93=C2=A0space to use ar= ound an em-dash ;; - electric-punct-horizontal-bar-space=C2=A0=E2=80=93=C2=A0space to= use around ;; a horizontal bar. ;; * electric-punct-thousands-separator=C2=A0=E2=80=93=C2=A0space to us= e as thousands ;; separator; setting to nil disables the feature. ;; * electric-punct-quotes-space=C2=A0=E2=80=93=C2=A0space to use betwe= en consequtive quote ;; characters; setting to nil disables the feature. ;; * electric-punct-handle-backspace=C2=A0=E2=80=93=C2=A0enables specia= l handler for ;; backspace key. ;; * electric-punct-auto-list=C2=A0=E2=80=93=C2=A0allows automatic sett= ing of a predicate ;; which can disable electric behaviour in parts of the buffer. ;; ;; In addition the `electric-punct-rules' variable lists all the rules = an ;; can be modified as one sees fit. ;; ;; Some other variables that may be useful to customise: ;; * electric-punct-html-modes=C2=A0=E2=80=93=C2=A0a list of modes in w= hich HTML features ;; are enabled. ;; * electric-punct-blacklisted-modes=C2=A0=E2=80=93=C2=A0a list of mod= es for which ;; `electric-punct-auto-mode' function (and thus ;; `global-electric-punct-mode') will not enable `electric-punct-mode= '. ;; * electric-punct-prog-modes=C2=A0=E2=80=93=C2=A0a list of modes in a= ddition to any modes ;; derived from `prog-mode' for which `electric-punct-auto-mode' will ;; enable `electric-punct-prog-mode'. ;; * electric-punct-predicate=C2=A0=E2=80=93=C2=A0a function that must = return non-nil for ;; expansions to happen.. ;;; Code: ;;;;;;;;;;;;;;;;;;;; Customise ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;; (defgroup electric-punct () "Electric behaviour helping enter Unicode punctuation characters." :prefix "electric-punct-" :group 'electricity) (defcustom electric-punct-treat-dash-spacing t "Whether to convert spaces into special Unicode spaces in various situati= ons. At the moment those situations include spaces around dashes and between sequences of digits being part of the same number (i.e. space used as a thousands separator)." :type 'boolean :group 'electric-punct) (let* ((space-choices '((const :tag "Space" ?\s) (const :tag "No-break space" ?\u00A0) (const :tag "Narrow no-break space" ?\u202F) (const :tag "En quad" ?\u2000) (const :tag "Em quad" ?\u2001) (const :tag "En space" ?\u2002) (const :tag "Em space" ?\u2003) (const :tag "Three-per-em space" ?\u2004) (const :tag "Four-per-em space" ?\u2005) (const :tag "Six-per-em space" ?\u2006) (const :tag "Figure space" ?\u2007) (const :tag "Punctuation space" ?\u2008) (const :tag "Thin space" ?\u2009) (const :tag "Hair space" ?\u200A) (const :tag "Medium mathematical space" ?\u205F) (const :tag "Ideographic space" ?\u3000) (character :tag "Other"))) (space-type (cons 'choice space-choices)) (space-or-nil-type `(choice (const :tag "Disabled" ()) . ,space-choices))) (defcustom electric-punct-en-dash-space ?\u00A0 "A space character used around an en dash. A no-break space by default. With default rules, if space is pressed while point is just after an en-das= h, character specified by this variable will be inserted instead of a normal ASCII space. Also, when a minus sign is converted into an en-dash (when = =E2=80=9C-=E2=80=9D is pressed) and is proceeded by a single ASCII space character, that space character is converted into character specified by this variable. Ignored if `electric-punct-treat-dash-spacing' is nil." :type space-type :group 'electric-punct) (defcustom electric-punct-em-dash-space ?\u2009 "A space character used around an em dash. A thin space by default. With default rules, if space is pressed while point is just after an em-das= h, character specified by this variable will be inserted instead of a normal ASCII space. Also, when an en-dash is converted into an em-dash (when =E2= =80=9C-=E2=80=9D is pressed) and is proceeded by a single space character, that space charac= ter is converted into character specified by this variable. Note that `electric-punct-mode' will not add a space before an em-dash if it was not already proceeded by a space character. This gives a choice of whether em-dash should or should not be surrounded by spaces. Ignored if `electric-punct-treat-dash-spacing' is nil." :type space-type :group 'electric-punct) (defcustom electric-punct-horizontal-bar-space ?\u2009 "A space character used around horizontal bar (a.k.a. quotation dash). A thin space by default. With default rules, if space is pressed while point is just after a horizon= tal bar, character specified by this variable will be inserted instead of a nor= mal ASCII space. Also, when an em-dash is converted into a horizontal bar (when =E2=80=9C-=E2=80=9D is pressed) and is proceeded by a single space characte= r, that space character is converted into character specified by this variable. Note that `electric-punct-mode' will not add a space before a horizontal bar if it was not already proceeded by a space character. This gives a choice = of whether horizontal bar should or should not be surrounded by spaces. Ignored if `electric-punct-treat-dash-spacing' is nil." :type space-type :group 'electric-punct) (defcustom electric-punct-thousands-separator ?\u2009 "A space used as thousands separator, or nil to disable the feature. A thin space by default. With default rules, if this is non-nil, if a digit is typed and point is ju= st after a =E2=80=9C=E2=80=9D sequence, the ASCII space is= converted into a character specified by this variable." :type space-or-nil-type :group 'electric-punct) (defcustom electric-punct-quotes-space ?\u2009 "A space used between consecutive quote characters, or nil. A thin space by default. With default rules, if this is non-nil, if a quote character in inserted af= ter another quote characters (e.g. as in =E2=80=9Cnever say =E2=80=98never=E2= =80=99=E2=80=9D) character specified by this variable is inserted between the quote characters." :type space-or-nil-type :group 'electric-punct)) (defcustom electric-punct-handle-backspace t "Whether to install backspace character handlers. If non-nil, electric-punct will provide a custom binding for backspace key which attempts to undo the effects of the expansions. For instance, if backspace is pressed after an en-dash, instead of deleting that en-dash, it will be converted to a minus sign." :type 'boolean :group 'electric-punct) ;;;;;;;;;;;;;;;;;;;; Helper functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;; (defun electric-punct--is-Zs (character) "Check whether CHARACTER is in Zs Unicode general category." (and character (eq (get-char-code-property character 'general-category) 'Zs))) (defun electric-punct--set-match-data (start) "Set `match-data' to region from START to `point' in `current-buffer'." (set-match-data (list start (point) (current-buffer))) t) (defconst electric-punct--quote-chars '(?\u00AB ;; left-pointing double angle quotation mark ?\u00BB ;; right-pointing double angle quotation mark ?\u2018 ;; left single quotation mark ?\u2019 ;; right single quotation mark ?\u201A ;; single low-9 quotation mark ?\u201B ;; single high-reversed-9 quotation mark ?\u201C ;; left double quotation mark ?\u201D ;; right double quotation mark ?\u201E ;; double low-9 quotation mark ?\u201F ;; double high-reversed-9 quotation mark ?\u2039 ;; single left-pointing angle quotation mark ?\u203A) ;; single right-pointing angle quotation mark "A list of characters which act as a opening or closing quotation marks. Does not contain quotation mark or apostrophe.") ;;;;;;;;;;;;;;;;;;;; Matchers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;; (defvar electric-punct-html-modes '(html-mode xml-mode nxml-mode sgml-mode) "A list of major modes for HTML, XML or SGML formats.") (defun electric-punct-is-html () "Check whether major mode is HTML, XML or SGML mode. The check is done by checking whether `major-mode' is any of the modes in `electric-punct-html-modes' list." (member major-mode electric-punct-html-modes)) (put 'electric-punct-is-html 'electric-punct-bs-safe t) (defun electric-punct-looking-back-at-html-space () "Check whether there's a HTML space entity before point. Returns nil if `electric-punct-is-html' returns nil, otherwise checks wheth= er point is just after an HTML entity referencing a space character such as =E2=80=9C =E2=80=9D or numeric reference of a character with Unicode Z= s general category. Function modifies `match-data'." (and (electric-punct-is-html) (let (case-fold-search) (looking-back "&\\(?:nbsp\\|#\\(?:[xX]\\([0-9a-fA-F]+\\)\\|\\([0-9]+\\)\\)\\);" (max (point-min) (- (point) 10)))) (let ((hex (match-string 1)) (dec (match-string 2))) (or (not (or hex dec)) (electric-punct--is-Zs (string-to-number (or hex dec) (if hex 16 10))))))) (defconst electric-punct--space-for-dash-plist '(?- ?\s ?\u2013 electric-punct-en-dash-space ?\u2014 electric-punct-em-dash-space ?\u2015 electric-punct-horizontal-bar-space) "A plist of spacing appropriate for given dash. Maps a dash character (minus sign, en-dash, em-dash and horizontal bar) to a space character or a variable containing the appropriate space character = to use around that dash character. Used by `electric-punct--next-dash' and `electric-punct-treat-dash-space' to figure out spacing that should be used around a dash.") (defun electric-punct--next-dash (progression skip-one) "Convert dash before point into one specified by PROGRESSION list. PROGRESSION is a list of characters specifying characters that come one aft= er the other. For expanding dashes it would be for example (?- en-dash em-das= h) whereas for contracting dashes it would be for example (em-dash en-dash ?-). If character before point is not an PROGRESSION list or it's its last eleme= nt, return nil and do nothing. Otherwise replace that dash with the next one from PROGRESSION list, and if= it is proceeded by exactly one space character replace that by space specified= by `electric-punct-en-dash-space', `electric-punct-em-dash-space' or `electric-punct-horizontal-bar-space' or an ASCII space for a minus sign. Space is not affected if `electric-punct-treat-dash-spacing' is nil. If SKIP-ONE is non-nil, function operates on character two-characters before point, i.e. character just before point is skipped, and if substitution tak= es place that skipped character is removed." (let ((chr (cadr (member (char-before (- (point) (if skip-one 1 0))) progression)))) (when chr (delete-char (if skip-one -2 -1)) (when (and electric-punct-treat-dash-spacing (electric-punct--is-Zs (preceding-char)) (not (electric-punct--is-Zs (char-before (1- (point)))))) (delete-char -1) (let ((space (plist-get electric-punct--space-for-dash-plist chr))) (insert (if (symbolp space) (eval space) space)))) (insert chr) t))) (defun electric-punct-treat-dash () "Expand dash character two characters before point. See `electric-punct--next-dash' for more detailed description." (electric-punct--next-dash '(?- ?\u2013 ?\u2014 ?\u2015) t)) (defun electric-punct-untreat-dash () "Contract dash before point. See `electric-punct--next-dash' for more detailed description." (electric-punct--next-dash '(?\u2015 ?\u2014 ?\u2013 ?-) nil)) (defun electric-punct-treat-dash-space () "Convert space character into one correct for a dash proceeding the space. Do nothing if character two characters before point is not an en-dash, em-d= ash or horizontal bar. If the dash character is proceeded by a space character \(i.e. one in Zs Unicode general category), the character after the dash is converted into that space character. Otherwise the character after the dash is converted to space specified by by `electric-punct-en-dash-space', `electric-punct-em-dash-space' or `electric-punct-horizontal-bar-space' variable depending on the dash character before point." (let ((space (plist-get electric-punct--space-for-dash-plist (char-before (1- (point)))))) (when space (delete-char -1) (insert (if (electric-punct--is-Zs (preceding-char)) (buffer-substring (- (point) 2) (1- (point))) (eval space))) t))) ;; -- (defun electric-punct-treat-thousands-separator () "Convert space between digits to proper thousands separator. If point is before a =E2=80=9C=E2=80=9D sequence= , and `electric-punct-thousands-separator' is non-nil, convert the ASCII space into character specified by `electric-punct-thousands-separator' variable. Return t if that happens, nil otherwise. \(Actually, the function does not verify whether the ASCII space is really = an ASCII space and whether the character before point is a digit)." (let ((space (with-no-warnings electric-punct-thousands-separator))) (when (and space (<=3D ?0 (char-before (- (point) 2)) ?9)) (goto-char (1- (point))) (delete-char -1) (insert space) (goto-char (1+ (point)))))) (defun electric-punct-untreat-thousands-separator () "Convert \"\" sequence to \"\". The must actually be `electric-punct-thousands-separator', and denotes any character. Return whether function did the conversion. Do nothing if `electric-punct-quotes-space' is nil." (let ((space (with-no-warnings electric-punct-thousands-separator))) (and space (>=3D (- (point) 3) (point-min)) (eq space (char-before (1- (point)))) (<=3D ?0 (char-before (- (point) 2)) ?9) (progn (delete-char -2) (insert " ") t)))) (defun electric-punct-treat-quotes-space () "Convert space between two quote characters to proper narrow space. If `electric-punct-quotes-space' is non-nil, insert it before the character before point. Return t if that happens, nil otherwise." (let ((space (with-no-warnings electric-punct-quotes-space))) (when space (goto-char (1- (point))) (insert space) (goto-char (1+ (point)))))) (defun electric-punct-is-quote-space-quote () "Check whether point is before \"\" sequence. must be value in `electric-punct--quote-chars' and must be value of `electric-punct-quotes-space'. is any character. Do nothing = if `electric-punct-quotes-space' is nil." (let ((space (with-no-warnings electric-punct-quotes-space))) (and space (>=3D (- (point) 2) (point-min)) (eq space (char-before (1- (point)))) (member (char-before (- (point) 2)) electric-punct--quote-chars)))) ;;;;;;;;;;;;;;;;;;;; Rules ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;= ;;; (defvar electric-punct-rules (eval-when-compile `((sp-nop " ") (sp-html "; " electric-punct-looking-back-at-html-space " ") (dash-sp "- " electric-punct-treat-dash-space) (dash-sp "\u2013 " electric-punct-treat-dash-space) (dash-sp "\u2014 " electric-punct-treat-dash-space) (dash-sp "\u2015 " electric-punct-treat-dash-space) (tilde "~~" "\u00A0" :no-bs) (dash-nop "---") (dash-nop "