>From eb392195ffdb108228c981f92ca8b5766afdcff9 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 13 May 2015 00:10:00 -0700 Subject: [PATCH] Support curved quotes in doc strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emacs's traditional doc string style has been to quote symbols `like this'. This worked well on now-obsolete terminals where ` and ' were symmetric quotes, but nowadays curved quotes ‘like this’ look better. Support quoting the new way too. (Bug#20385) * doc/lispref/tips.texi (Documentation Tips): Symbols can be quoted ‘like-this’ as well as `like-this'. * etc/NEWS: Mention this. * lisp/cedet/srecode/texi.el (srecode-texi-texify-docstring): * lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine): * lisp/emacs-lisp/lisp-mode.el (lisp-el-font-lock-keywords-2) (lisp-cl-font-lock-keywords-2): * lisp/finder.el (finder-font-lock-keywords): * lisp/gnus/gnus-art.el (gnus-button-alist): * lisp/help-mode.el (help-xref-symbol-regexp) (help-xref-info-regexp, help-xref-url-regexp): * lisp/international/mule-cmds.el (help-xref-mule-regexp-template): * lisp/progmodes/elisp-mode.el (emacs-lisp-mode): Add "‘" and "’" to electric-pair-text-pairs. (elisp--form-quoted-p): Also allow "‘" as a quoting char. (elisp-completion-at-point, elisp--preceding-sexp): Also treat "‘" and "’" as quoting chars. * lisp/wid-edit.el (widget-documentation-link-regexp): Parse symbols quoted ‘like-this’ as well as `like-this'. --- doc/lispref/tips.texi | 33 ++++++++++++++++++--------------- etc/NEWS | 4 ++++ lisp/cedet/srecode/texi.el | 2 +- lisp/emacs-lisp/checkdoc.el | 5 +++-- lisp/emacs-lisp/lisp-mode.el | 8 ++++---- lisp/finder.el | 2 +- lisp/gnus/gnus-art.el | 8 ++++---- lisp/help-mode.el | 7 ++++--- lisp/international/mule-cmds.el | 2 +- lisp/progmodes/elisp-mode.el | 24 +++++++++++++----------- lisp/wid-edit.el | 2 +- 11 files changed, 54 insertions(+), 43 deletions(-) diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi index cc1f0e4..912d746 100644 --- a/doc/lispref/tips.texi +++ b/doc/lispref/tips.texi @@ -658,17 +658,20 @@ starting double-quote is not part of the string! @anchor{Docstring hyperlinks} @item When a documentation string refers to a Lisp symbol, write it as it -would be printed (which usually means in lower case), with a grave -accent @samp{`} before and apostrophe @samp{'} after it. There are +would be printed (which usually means in lower case), with surrounding +it with curved single quotes (@samp{‘} and @samp{’}). There are two exceptions: write @code{t} and @code{nil} without surrounding -punctuation. For example: @samp{CODE can be `lambda', nil, or t.} -(In this manual, we use a different convention, with single-quotes -around symbols.) +punctuation. For example: @samp{CODE can be ‘lambda’, nil, or t.} + +Documentation strings can also use an older single-quoting convention, +which quotes symbols with grave accent @samp{`} and apostrophe +@samp{'}: @samp{`like-this'} rather than @samp{‘like-this’}. This +older convention was designed for now-obsolete displays in which grave +accent and apostrophe were mirror images. @cindex hyperlinks in documentation strings Help mode automatically creates a hyperlink when a documentation string -uses a symbol name between grave accent and apostrophe, if the symbol -has either a +uses a single-quoted symbol name, if the symbol has either a function or a variable definition. You do not need to do anything special to make use of this feature. However, when a symbol has both a function definition and a variable definition, and you want to refer to @@ -678,7 +681,7 @@ immediately before the symbol name. (Case makes no difference in recognizing these indicator words.) For example, if you write @example -This function sets the variable `buffer-file-name'. +This function sets the variable ‘buffer-file-name’. @end example @noindent @@ -691,7 +694,7 @@ you can write the words @samp{symbol} or @samp{program} before the symbol name to prevent making any hyperlink. For example, @example -If the argument KIND-OF-RESULT is the symbol `list', +If the argument KIND-OF-RESULT is the symbol ‘list’, this function returns a list of all the objects that satisfy the criterion. @end example @@ -710,21 +713,21 @@ followed by the word @samp{face}. In that case, only the face documentation will be shown, even if the symbol is also defined as a variable or as a function. -To make a hyperlink to Info documentation, write the name of the Info -node (or anchor) between grave accent and apostrophe, preceded by +To make a hyperlink to Info documentation, write the single-quoted +name of the Info node (or anchor), preceded by @samp{info node}, @samp{Info node}, @samp{info anchor} or @samp{Info anchor}. The Info file name defaults to @samp{emacs}. For example, @smallexample -See Info node `Font Lock' and Info node `(elisp)Font Lock Basics'. +See Info node ‘Font Lock’ and Info node ‘(elisp)Font Lock Basics’. @end smallexample -Finally, to create a hyperlink to URLs, write the URL between grave -accent and apostrophe, preceded by @samp{URL}. For example, +Finally, to create a hyperlink to URLs, write the single-quoted URL, +preceded by @samp{URL}. For example, @smallexample The home page for the GNU project has more information (see URL -`http://www.gnu.org/'). +‘http://www.gnu.org/’). @end smallexample @item diff --git a/etc/NEWS b/etc/NEWS index 3f907db..817330f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -858,6 +858,10 @@ directory at point. *** New macros `thread-first' and `thread-last' allow threading a form as the first or last argument of subsequent forms. +** Documentation strings now support quoting with curved single quotes +‘like-this’ in addition to the old style with grave accent and +apostrophe `like-this'. The new style looks better on today's displays. + +++ ** Time-related changes: diff --git a/lisp/cedet/srecode/texi.el b/lisp/cedet/srecode/texi.el index 5c3f21c..5068b2a 100644 --- a/lisp/cedet/srecode/texi.el +++ b/lisp/cedet/srecode/texi.el @@ -253,7 +253,7 @@ that class. [ stuff ] => @code{[ stuff ]} Key => @kbd{Key} (key is C\\-h, M\\-h, SPC, RET, TAB and the like) ... => @dots{}" - (while (string-match "`\\([-a-zA-Z0-9<>.]+\\)'" string) + (while (string-match "[`‘]\\([-a-zA-Z0-9<>.]+\\)['’]" string) (let* ((vs (substring string (match-beginning 1) (match-end 1))) (v (intern-soft vs))) (setq string diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el index 777fed0..d6a4c7b 100644 --- a/lisp/emacs-lisp/checkdoc.el +++ b/lisp/emacs-lisp/checkdoc.el @@ -1554,7 +1554,8 @@ mouse-[0-3]\\)\\)\\>")) (save-excursion (let ((case-fold-search t) (ret nil) mb me) - (while (and (re-search-forward "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'" e t) + (while (and (re-search-forward + "[`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]" e t) (not ret)) (let* ((ms1 (match-string 1)) (sym (intern-soft ms1))) @@ -1824,7 +1825,7 @@ Replace with \"%s\"? " original replace) nil))) ;; t and nil case (save-excursion - (if (re-search-forward "\\(`\\(t\\|nil\\)'\\)" e t) + (if (re-search-forward "\\([`‘]\\(t\\|nil\\)['’]\\)" e t) (if (checkdoc-autofix-ask-replace (match-beginning 1) (match-end 1) (format "%s should not appear in quotes. Remove? " diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index 108d5cc..476125d 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -405,8 +405,8 @@ ;; Words inside \\[] tend to be for `substitute-command-keys'. ("\\\\\\\\\\[\\(\\(?:\\sw\\|\\s_\\)+\\)\\]" (1 font-lock-constant-face prepend)) - ;; Words inside `' tend to be symbol names. - ("`\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)'" + ;; Words inside ‘’ and `' tend to be symbol names. + ("[`‘]\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)['’]" (1 font-lock-constant-face prepend)) ;; Constant values. ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face) @@ -454,8 +454,8 @@ ;; Erroneous structures. (,(concat "(" cl-errs-re "\\_>") (1 font-lock-warning-face)) - ;; Words inside `' tend to be symbol names. - ("`\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)'" + ;; Words inside ‘’ and `' tend to be symbol names. + ("[`‘]\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)['’]" (1 font-lock-constant-face prepend)) ;; Constant values. ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face) diff --git a/lisp/finder.el b/lisp/finder.el index 47fab3c..306f2e2 100644 --- a/lisp/finder.el +++ b/lisp/finder.el @@ -115,7 +115,7 @@ Each element has the form (KEYWORD . DESCRIPTION).") "Syntax table used while in `finder-mode'.") (defvar finder-font-lock-keywords - '(("`\\([^'`]+\\)'" 1 font-lock-constant-face prepend)) + '(("[`‘]\\([^'`‘’]+\\)['’]" 1 font-lock-constant-face prepend)) "Font-lock keywords for Finder mode.") (defvar finder-headmark nil diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el index 989a424..fea89a8 100644 --- a/lisp/gnus/gnus-art.el +++ b/lisp/gnus/gnus-art.el @@ -7827,11 +7827,11 @@ positives are possible." ("/\\([a-z][-a-z0-9]+\\.el\\)\\>[^.?]" ;; Exclude [.?] for URLs in gmane.emacs.cvs 1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1) - ("`\\([a-z][-a-z0-9]+\\.el\\)'" + ("[`‘]\\([a-z][-a-z0-9]+\\.el\\)['’]" 1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1) - ("`\\([a-z][a-z0-9]+-[a-z0-9]+-[-a-z0-9]*[a-z]\\|\\(gnus\\|message\\)-[-a-z]+\\)'" + ("[`‘]\\([a-z][a-z0-9]+-[a-z0-9]+-[-a-z0-9]*[a-z]\\|\\(gnus\\|message\\)-[-a-z]+\\)['’]" 0 (>= gnus-button-emacs-level 8) gnus-button-handle-symbol 1) - ("`\\([a-z][a-z0-9]+-[a-z]+\\)'" + ("[`‘]\\([a-z][a-z0-9]+-[a-z]+\\)['’]" 0 (>= gnus-button-emacs-level 9) gnus-button-handle-symbol 1) ("(setq[ \t\n]+\\([a-z][a-z0-9]+-[-a-z0-9]+\\)[ \t\n]+.+)" 1 (>= gnus-button-emacs-level 7) gnus-button-handle-describe-variable 1) @@ -7841,7 +7841,7 @@ positives are possible." 0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-function 2) ("\\b\\(C-h\\|?\\)[ \t\n]+v[ \t\n]+\\([^ \t\n]+\\)[ \t\n]+RET\\>" 0 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-variable 2) - ("`\\(\\(C-h\\|?\\)[ \t\n]+k[ \t\n]+\\([^']+\\)\\)'" + ("[`‘]\\(\\(C-h\\|?\\)[ \t\n]+k[ \t\n]+\\([^'’]+\\)\\)['’]" ;; Unlike the other regexps we really have to require quoting ;; here to determine where it ends. 1 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-key 3) diff --git a/lisp/help-mode.el b/lisp/help-mode.el index d6679e9..cf8ec0c 100644 --- a/lisp/help-mode.el +++ b/lisp/help-mode.el @@ -322,7 +322,7 @@ Commands: "\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)" "[ \t\n]+\\)?" ;; Note starting with word-syntax character: - "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'")) + "[`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]")) "Regexp matching doc string references to symbols. The words preceding the quoted symbol can be used in doc strings to @@ -337,11 +337,12 @@ when help commands related to multilingual environment (e.g., (defconst help-xref-info-regexp - (purecopy "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+`\\([^']+\\)'") + (purecopy + "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+[`‘]\\([^'’]+\\)['’]") "Regexp matching doc string references to an Info node.") (defconst help-xref-url-regexp - (purecopy "\\<[Uu][Rr][Ll][ \t\n]+`\\([^']+\\)'") + (purecopy "\\<[Uu][Rr][Ll][ \t\n]+[`‘]\\([^'’]+\\)['’]") "Regexp matching doc string references to a URL.") ;;;###autoload diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el index fd892aa..a49e293 100644 --- a/lisp/international/mule-cmds.el +++ b/lisp/international/mule-cmds.el @@ -177,7 +177,7 @@ "\\(charset\\)" "\\)\\s-+\\)?" ;; Note starting with word-syntax character: - "`\\(\\sw\\(\\sw\\|\\s_\\)+\\)'"))) + "[`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]"))) (defun coding-system-change-eol-conversion (coding-system eol-type) "Return a coding system which differs from CODING-SYSTEM in EOL conversion. diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index e06b920..b070029 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -231,7 +231,7 @@ 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)) + (append '((?\` . ?\') (?‘ . ?’)) electric-pair-text-pairs)) (setq imenu-case-fold-search nil) (add-function :before-until (local 'eldoc-documentation-function) #'elisp-eldoc-documentation-function) @@ -394,7 +394,7 @@ It can be quoted, or be inside a quoted form." ((or (eq (char-after) ?\[) (progn (skip-chars-backward " ") - (memq (char-before) '(?' ?`)))) + (memq (char-before) '(?' ?` ?‘)))) (setq res t)) ((eq (char-before) ?,) (setq nesting nil)))) @@ -459,7 +459,7 @@ It can be quoted, or be inside a quoted form." (beg (condition-case nil (save-excursion (backward-sexp 1) - (skip-syntax-forward "'") + (skip-chars-forward "`',‘") (point)) (scan-error pos))) (end @@ -470,7 +470,7 @@ It can be quoted, or be inside a quoted form." (save-excursion (goto-char beg) (forward-sexp 1) - (skip-chars-backward "'") + (skip-chars-backward "'’") (when (>= (point) pos) (point))) (scan-error pos)))) @@ -478,7 +478,7 @@ It can be quoted, or be inside a quoted form." (funpos (eq (char-before beg) ?\()) (quoted (elisp--form-quoted-p beg))) (when (and end (or (not (nth 8 (syntax-ppss))) - (eq (char-before beg) ?`))) + (memq (char-before beg) '(?` ?‘)))) (let ((table-etc (if (or (not funpos) quoted) ;; FIXME: We could look at the first element of the list and @@ -901,15 +901,17 @@ If CHAR is not a character, return nil." (defun elisp--preceding-sexp () "Return sexp before the point." (let ((opoint (point)) - ignore-quotes + (left-quote ?‘) expr) (save-excursion (with-syntax-table emacs-lisp-mode-syntax-table - ;; If this sexp appears to be enclosed in `...' + ;; If this sexp appears to be enclosed in `...' or ‘...’ ;; then ignore the surrounding quotes. - (setq ignore-quotes - (or (eq (following-char) ?\') - (eq (preceding-char) ?\'))) + (cond ((eq (preceding-char) ?’) + (progn (forward-char -1) (setq opoint (point)))) + ((or (eq (following-char) ?\') + (eq (preceding-char) ?\')) + (setq left-quote ?\`))) (forward-sexp -1) ;; If we were after `?\e' (or similar case), ;; use the whole thing, not just the `e'. @@ -933,7 +935,7 @@ If CHAR is not a character, return nil." (forward-sexp -1)))) (save-restriction - (if (and ignore-quotes (eq (following-char) ?`)) + (if (eq (following-char) left-quote) ;; vladimir@cs.ualberta.ca 30-Jul-1997: Skip ` in `variable' so ;; that the value is returned, not the name. (forward-char)) diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 0a95783..dac3b1e 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el @@ -2863,7 +2863,7 @@ The following properties have special meanings for this widget: :type 'boolean :group 'widget-documentation) -(defcustom widget-documentation-link-regexp "`\\([^\n`' ]+\\)'" +(defcustom widget-documentation-link-regexp "[`‘]\\([^\n `'‘’]+\\)['’]" "Regexp for matching potential links in documentation strings. The first group should be the link itself." :type 'regexp -- 2.1.0