aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2015-06-19 00:35:43 -0700
committerPaul Eggert2015-06-19 00:38:45 -0700
commitc4151ebe15479de4c2e511b068cdf9af6a4576cf (patch)
tree14933519830d5da23b6962cdaff705081eb85313
parentaad7ea32c57c7b9673a8d429524e050dac2d210c (diff)
downloademacs-c4151ebe15479de4c2e511b068cdf9af6a4576cf.tar.gz
emacs-c4151ebe15479de4c2e511b068cdf9af6a4576cf.zip
Improve the optional translation of quotes
Fix several problems with the recently-added custom variable help-quote-translation where the code would quote inconsistently in help buffers. Add support for quoting 'like this', which is common in other GNU programs in ASCII environments. Change help-quote-translation to use more mnemonic values: values are now the initial quoting char, e.g., (setq help-quote-translation ?`) gets the traditional Emacs help-buffer quoting style `like this'. Change the default behavior of substitute-command-keys to match what's done in set-locale-environment, i.e., quote ‘like this’ if displayable, 'like this' otherwise. * doc/lispref/help.texi (Keys in Documentation): Document new behavior of substitute-command-keys, and document help-quote-translation. * doc/lispref/tips.texi (Documentation Tips): Mention the effect of help-quote-translation. * etc/NEWS: Mention new behavior of substitute-command-keys, and merge help-quote-translation news into it. When talking about doc strings, mention new ways to type quotes. * lisp/cedet/mode-local.el (overload-docstring-extension): Revert my recent change to this function, which shouldn't be needed as the result is a doc string. * lisp/cedet/mode-local.el (mode-local-print-binding) (mode-local-describe-bindings-2): * lisp/cedet/srecode/srt-mode.el (srecode-macro-help): * lisp/cus-theme.el (describe-theme-1): * lisp/descr-text.el (describe-text-properties-1, describe-char): * lisp/emacs-lisp/cl-generic.el (cl--generic-describe): * lisp/emacs-lisp/eieio-opt.el (eieio-help-class) (eieio-help-constructor): * lisp/emacs-lisp/package.el (describe-package-1): * lisp/faces.el (describe-face): * lisp/help-fns.el (help-fns--key-bindings) (help-fns--compiler-macro, help-fns--parent-mode) (help-fns--obsolete, help-fns--interactive-only) (describe-function-1, describe-variable): * lisp/help.el (describe-mode): Use substitute-command-keys to ensure a more-consistent quoting style in help buffers. * lisp/cus-start.el (standard): Document new help-quote-translation behavior. * lisp/emacs-lisp/lisp-mode.el (lisp-fdefs): * 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/wid-edit.el (widget-documentation-link-regexp): Also match 'foo', in case we're in a help buffer generated when help-quote-translation is ?'. * src/doc.c: Include disptab.h, for DISP_CHAR_VECTOR. (LEFT_SINGLE_QUOTATION_MARK, uLSQM0, uLSQM1, uLSQM2, uRSQM0) (uRSQM1, uRSQM2, LSQM, RSQM): New constants. (Fsubstitute_command_keys): Document and implement new behavior. (Vhelp_quote_translation): Document new behavior.
-rw-r--r--doc/lispref/help.texi29
-rw-r--r--doc/lispref/tips.texi8
-rw-r--r--etc/NEWS23
-rw-r--r--lisp/cedet/mode-local.el18
-rw-r--r--lisp/cedet/srecode/srt-mode.el4
-rw-r--r--lisp/cus-start.el7
-rw-r--r--lisp/cus-theme.el4
-rw-r--r--lisp/descr-text.el12
-rw-r--r--lisp/emacs-lisp/cl-generic.el4
-rw-r--r--lisp/emacs-lisp/eieio-opt.el20
-rw-r--r--lisp/emacs-lisp/lisp-mode.el8
-rw-r--r--lisp/emacs-lisp/package.el7
-rw-r--r--lisp/faces.el13
-rw-r--r--lisp/help-fns.el71
-rw-r--r--lisp/help-mode.el6
-rw-r--r--lisp/help.el8
-rw-r--r--lisp/international/mule-cmds.el2
-rw-r--r--lisp/wid-edit.el2
-rw-r--r--src/doc.c89
19 files changed, 213 insertions, 122 deletions
diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi
index ce29f3f5bc3..44a680c4a22 100644
--- a/doc/lispref/help.texi
+++ b/doc/lispref/help.texi
@@ -319,10 +319,22 @@ specifies @var{mapvar}'s value as the keymap for any following
319@samp{\[@var{command}]} sequences in this documentation string. 319@samp{\[@var{command}]} sequences in this documentation string.
320 320
321@item ` 321@item `
322(grave accent) stands for a left single quotation mark (@samp{‘}). 322(grave accent) stands for a left quote, and alters the interpretation
323of the next unmatched apostrophe.
323 324
324@item ' 325@item '
325(apostrophe) stands for a right single quotation mark (@samp{’}) if 326(apostrophe) stands for a right quote if preceded by grave accent and
327there are no intervening apostrophes. Otherwise, apostrophe stands
328for itself.
329
330@item ‘
331(left single quotation mark) stands for a left quote.
332
333@item ’
334(right single quotation mark) stands for a right quote.
335
336@item '
337(apostrophe) stands for a right quote if
326preceded by grave accent and there are no intervening apostrophes. 338preceded by grave accent and there are no intervening apostrophes.
327Otherwise, apostrophe stands for itself. 339Otherwise, apostrophe stands for itself.
328 340
@@ -335,6 +347,19 @@ and @samp{\=\=} puts @samp{\=} into the output.
335@strong{Please note:} Each @samp{\} must be doubled when written in a 347@strong{Please note:} Each @samp{\} must be doubled when written in a
336string in Emacs Lisp. 348string in Emacs Lisp.
337 349
350@defvar help-quote-translation
351@cindex curved quotes
352The value of this variable specifies the style
353@code{substitute-command-keys} uses when generating left and right
354quotes. If the variable's value is @code{?‘} (U+2018 LEFT SINGLE
355QUOTATION MARK), the style is @t{‘like this’} with curved single
356quotes. If the value is @code{?'} (apostrophe), the style is @t{'like
357this'} with apostrophes. If the value is @code{?`} (grave accent),
358the style is @t{`like this'} with grave accent and apostrophe. The
359default value @code{nil} means to use curved single quotes if
360displayable and apostrophes otherwise.
361@end defvar
362
338@defun substitute-command-keys string 363@defun substitute-command-keys string
339This function scans @var{string} for the above special sequences and 364This function scans @var{string} for the above special sequences and
340replaces them by what they stand for, returning the result as a string. 365replaces them by what they stand for, returning the result as a string.
diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi
index 9144497d5f1..7107bb45872 100644
--- a/doc/lispref/tips.texi
+++ b/doc/lispref/tips.texi
@@ -671,9 +671,11 @@ Documentation strings can also use an older single-quoting convention,
671which quotes symbols with grave accent @t{`} and apostrophe 671which quotes symbols with grave accent @t{`} and apostrophe
672@t{'}: @t{`like-this'} rather than @t{‘like-this’}. This 672@t{'}: @t{`like-this'} rather than @t{‘like-this’}. This
673older convention was designed for now-obsolete displays in which grave 673older convention was designed for now-obsolete displays in which grave
674accent and apostrophe were mirror images. Documentation in this older 674accent and apostrophe were mirror images.
675convention is converted to the standard convention when it is copied 675
676into a help buffer. @xref{Keys in Documentation}. 676Documentation using either convention is converted to the user's
677preferred format when it is copied into a help buffer. @xref{Keys in
678Documentation}.
677 679
678@cindex hyperlinks in documentation strings 680@cindex hyperlinks in documentation strings
679Help mode automatically creates a hyperlink when a documentation string 681Help mode automatically creates a hyperlink when a documentation string
diff --git a/etc/NEWS b/etc/NEWS
index 1611c7a7926..bab1b41e759 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -845,11 +845,16 @@ when signaling a file error. For example, it now reports "Permission
845denied" instead of "permission denied". The old behavior was problematic 845denied" instead of "permission denied". The old behavior was problematic
846in languages like German where downcasing rules depend on grammar. 846in languages like German where downcasing rules depend on grammar.
847 847
848** (substitute-command-keys "`foo'") now returns "‘foo’". 848** substitute-command-keys now replaces quotes.
849That is, it replaces grave accents by left single quotation marks, and 849That is, it replaces left single quotation marks (‘) by left quotes
850apostrophes that match grave accents by right single quotation marks. 850and right single quotation marks (’) by right quotes. It also
851As before, isolated apostrophes and characters preceded by \= are 851replaces grave accents by left quotes, and apostrophes that match
852output as-is. 852grave accents by right quotes. As before, isolated apostrophes and
853characters preceded by \= are output as-is. Left and right quotes are
854determined by new custom variable ‘help-quote-translation’. ?‘ means
855quote ‘like this’, ?' means quote 'like this', ?` means quote `like
856this', and nil (default) means quote ‘like this’ if displayable and
857'like this' otherwise.
853 858
854+++ 859+++
855** The character classes [:alpha:] and [:alnum:] in regular expressions 860** The character classes [:alpha:] and [:alnum:] in regular expressions
@@ -956,10 +961,10 @@ directory at point.
956** Documentation strings now support quoting with curved single quotes 961** Documentation strings now support quoting with curved single quotes
957‘like-this’ in addition to the old style with grave accent and 962‘like-this’ in addition to the old style with grave accent and
958apostrophe `like-this'. The new style looks better on today's displays. 963apostrophe `like-this'. The new style looks better on today's displays.
959When an old-style string is copied to a help buffer it is converted to 964In the new Electric Quote mode, you can enter curved single quotes
960the new style. 965into documentation by typing ` and '. Outside Electric Quote mode,
961 966you can enter them by typing ‘C-x 8 [’ and ‘C-x 8 ]’, or (if your Alt
962** New option `help-quote-translation'. 967key works) by typing ‘A-[’ and ‘A-]’.
963 968
964+++ 969+++
965** Time-related changes: 970** Time-related changes:
diff --git a/lisp/cedet/mode-local.el b/lisp/cedet/mode-local.el
index 35363337aee..3bdc3ea6155 100644
--- a/lisp/cedet/mode-local.el
+++ b/lisp/cedet/mode-local.el
@@ -598,16 +598,15 @@ PROMPT, INITIAL, HIST, and DEFAULT are the same as for `completing-read'."
598(defun overload-docstring-extension (overload) 598(defun overload-docstring-extension (overload)
599 "Return the doc string that augments the description of OVERLOAD." 599 "Return the doc string that augments the description of OVERLOAD."
600 (let ((doc "\n\This function can be overloaded\ 600 (let ((doc "\n\This function can be overloaded\
601 with define-mode-local-override.") 601 with `define-mode-local-override'.")
602 (sym (overload-obsoleted-by overload))) 602 (sym (overload-obsoleted-by overload)))
603 (when sym 603 (when sym
604 (setq doc (format "%s\nIt has made the overload %s obsolete since %s." 604 (setq doc (format "%s\nIt has made the overload `%s' obsolete since %s."
605 doc sym (get sym 'overload-obsoleted-since)))) 605 doc sym (get sym 'overload-obsoleted-since))))
606 (setq sym (overload-that-obsolete overload)) 606 (setq sym (overload-that-obsolete overload))
607 (when sym 607 (when sym
608 (setq doc (format 608 (setq doc (format "%s\nThis overload is obsolete since %s;\nUse `%s' instead."
609 "%s\nThis overload is obsolete since %s;\nuse ‘%s’ instead." 609 doc (get overload 'overload-obsoleted-since) sym)))
610 doc (get overload 'overload-obsoleted-since) sym)))
611 doc)) 610 doc))
612 611
613(defun mode-local-augment-function-help (symbol) 612(defun mode-local-augment-function-help (symbol)
@@ -630,9 +629,10 @@ SYMBOL is a function that can be overridden."
630(defun mode-local-print-binding (symbol) 629(defun mode-local-print-binding (symbol)
631 "Print the SYMBOL binding." 630 "Print the SYMBOL binding."
632 (let ((value (symbol-value symbol))) 631 (let ((value (symbol-value symbol)))
633 (princ (format "\n ‘%s’ value is\n " symbol)) 632 (princ (format (substitute-command-keys "\n ‘%s’ value is\n ")
633 symbol))
634 (if (and value (symbolp value)) 634 (if (and value (symbolp value))
635 (princ (format "‘%s’" value)) 635 (princ (format (substitute-command-keys "‘%s’") value))
636 (let ((pt (point))) 636 (let ((pt (point)))
637 (pp value) 637 (pp value)
638 (save-excursion 638 (save-excursion
@@ -690,7 +690,7 @@ SYMBOL is a function that can be overridden."
690 ) 690 )
691 ((symbolp buffer-or-mode) 691 ((symbolp buffer-or-mode)
692 (setq mode buffer-or-mode) 692 (setq mode buffer-or-mode)
693 (princ (format "‘%s’\n" buffer-or-mode)) 693 (princ (format (substitute-command-keys "‘%s’\n") buffer-or-mode))
694 ) 694 )
695 ((signal 'wrong-type-argument 695 ((signal 'wrong-type-argument
696 (list 'buffer-or-mode buffer-or-mode)))) 696 (list 'buffer-or-mode buffer-or-mode))))
@@ -700,7 +700,7 @@ SYMBOL is a function that can be overridden."
700 (while mode 700 (while mode
701 (setq table (get mode 'mode-local-symbol-table)) 701 (setq table (get mode 'mode-local-symbol-table))
702 (when table 702 (when table
703 (princ (format "\n- From ‘%s’\n" mode)) 703 (princ (format (substitute-command-keys "\n- From ‘%s’\n") mode))
704 (mode-local-print-bindings table)) 704 (mode-local-print-bindings table))
705 (setq mode (get-mode-local-parent mode))))) 705 (setq mode (get-mode-local-parent mode)))))
706 706
diff --git a/lisp/cedet/srecode/srt-mode.el b/lisp/cedet/srecode/srt-mode.el
index fbc56357b1c..48f055561ea 100644
--- a/lisp/cedet/srecode/srt-mode.el
+++ b/lisp/cedet/srecode/srt-mode.el
@@ -258,9 +258,9 @@ we can tell font lock about them.")
258 (when (class-abstract-p C) 258 (when (class-abstract-p C)
259 (throw 'skip nil)) 259 (throw 'skip nil))
260 260
261 (princ "‘") 261 (princ (substitute-command-keys "‘"))
262 (princ name) 262 (princ name)
263 (princ "’") 263 (princ (substitute-command-keys "’"))
264 (when (slot-exists-p C 'key) 264 (when (slot-exists-p C 'key)
265 (when key 265 (when key
266 (princ " - Character Key: ") 266 (princ " - Character Key: ")
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 12def4c4148..7cf5ce736bd 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -223,9 +223,10 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
223 ;; doc.c 223 ;; doc.c
224 (help-quote-translation help 224 (help-quote-translation help
225 (choice 225 (choice
226 (const :tag "No translation" nil) 226 (character :tag "Quote ‘like this’" :value ?‘)
227 (const :tag "Translate curly single quotes to ASCII" traditional) 227 (character :tag "Quote 'like this'" :value ?\')
228 (const :tag "Translate ASCII single quotes to curly" prefer-unicode)) 228 (character :tag "Quote `like this'" :value ?\`)
229 (const :tag "Quote ‘like this’ if displyable, 'like this' otherwise" nil))
229 "25.1") 230 "25.1")
230 ;; dosfns.c 231 ;; dosfns.c
231 (dos-display-scancodes display boolean) 232 (dos-display-scancodes display boolean)
diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 1321fbc4b7e..bc221e17c4b 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -492,10 +492,10 @@ It includes all faces in list FACES."
492 '("" "c"))) 492 '("" "c")))
493 doc) 493 doc)
494 (when fn 494 (when fn
495 (princ " in ‘") 495 (princ (substitute-command-keys " in ‘"))
496 (help-insert-xref-button (file-name-nondirectory fn) 496 (help-insert-xref-button (file-name-nondirectory fn)
497 'help-theme-def fn) 497 'help-theme-def fn)
498 (princ "’")) 498 (princ (substitute-command-keys "’")))
499 (princ ".\n") 499 (princ ".\n")
500 (if (custom-theme-p theme) 500 (if (custom-theme-p theme)
501 (progn 501 (progn
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index c8641aed8bb..a0b9ddfe2c9 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -161,8 +161,11 @@ otherwise."
161 ;; Buttons 161 ;; Buttons
162 (when (and button (not (widgetp wid-button))) 162 (when (and button (not (widgetp wid-button)))
163 (newline) 163 (newline)
164 (insert "Here is a ‘" (format "%S" button-type) 164 (insert (substitute-command-keys "Here is a ‘")
165 "’ button labeled ‘" button-label "’.\n\n")) 165 (format "%S" button-type)
166 (substitute-command-keys "’ button labeled ‘")
167 button-label
168 (substitute-command-keys "’.\n\n")))
166 ;; Overlays 169 ;; Overlays
167 (when overlays 170 (when overlays
168 (newline) 171 (newline)
@@ -738,8 +741,9 @@ relevant to POS."
738 (when face 741 (when face
739 (insert (propertize " " 'display '(space :align-to 5)) 742 (insert (propertize " " 'display '(space :align-to 5))
740 "face: ") 743 "face: ")
741 (insert (concat "‘" (symbol-name face) "’")) 744 (insert (substitute-command-keys "‘")
742 (insert "\n"))))) 745 (symbol-name face)
746 (substitute-command-keys "’\n"))))))
743 (insert "these terminal codes:\n") 747 (insert "these terminal codes:\n")
744 (dotimes (i (length disp-vector)) 748 (dotimes (i (length disp-vector))
745 (insert (car (aref disp-vector i)) 749 (insert (car (aref disp-vector i))
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 96b86aa21cc..5923e4db996 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -876,11 +876,11 @@ Can only be used from within the lexical body of a primary or around method."
876 (cl--generic-method-specializers method))) 876 (cl--generic-method-specializers method)))
877 (file (find-lisp-object-file-name met-name 'cl-defmethod))) 877 (file (find-lisp-object-file-name met-name 'cl-defmethod)))
878 (when file 878 (when file
879 (insert " in ‘") 879 (insert (substitute-command-keys " in ‘"))
880 (help-insert-xref-button (help-fns-short-filename file) 880 (help-insert-xref-button (help-fns-short-filename file)
881 'help-function-def met-name file 881 'help-function-def met-name file
882 'cl-defmethod) 882 'cl-defmethod)
883 (insert "’.\n"))) 883 (insert (substitute-command-keys "’.\n"))))
884 (insert "\n" (or (nth 2 info) "Undocumented") "\n\n"))))))) 884 (insert "\n" (or (nth 2 info) "Undocumented") "\n\n")))))))
885 885
886;;; Support for (head <val>) specializers. 886;;; Support for (head <val>) specializers.
diff --git a/lisp/emacs-lisp/eieio-opt.el b/lisp/emacs-lisp/eieio-opt.el
index 11d99849a97..6cd6813956a 100644
--- a/lisp/emacs-lisp/eieio-opt.el
+++ b/lisp/emacs-lisp/eieio-opt.el
@@ -90,11 +90,11 @@ If CLASS is actually an object, then also display current values of that object.
90 " class") 90 " class")
91 (let ((location (find-lisp-object-file-name class 'eieio-defclass))) 91 (let ((location (find-lisp-object-file-name class 'eieio-defclass)))
92 (when location 92 (when location
93 (insert " in ‘") 93 (insert (substitute-command-keys " in ‘"))
94 (help-insert-xref-button 94 (help-insert-xref-button
95 (help-fns-short-filename location) 95 (help-fns-short-filename location)
96 'eieio-class-def class location 'eieio-defclass) 96 'eieio-class-def class location 'eieio-defclass)
97 (insert "’"))) 97 (insert (substitute-command-keys "’"))))
98 (insert ".\n") 98 (insert ".\n")
99 ;; Parents 99 ;; Parents
100 (let ((pl (eieio-class-parents class)) 100 (let ((pl (eieio-class-parents class))
@@ -103,10 +103,10 @@ If CLASS is actually an object, then also display current values of that object.
103 (insert " Inherits from ") 103 (insert " Inherits from ")
104 (while (setq cur (pop pl)) 104 (while (setq cur (pop pl))
105 (setq cur (eieio--class-name cur)) 105 (setq cur (eieio--class-name cur))
106 (insert "‘") 106 (insert (substitute-command-keys "‘"))
107 (help-insert-xref-button (symbol-name cur) 107 (help-insert-xref-button (symbol-name cur)
108 'help-function cur) 108 'help-function cur)
109 (insert (if pl "’, " "’"))) 109 (insert (substitute-command-keys (if pl "’, " "’"))))
110 (insert ".\n"))) 110 (insert ".\n")))
111 ;; Children 111 ;; Children
112 (let ((ch (eieio-class-children class)) 112 (let ((ch (eieio-class-children class))
@@ -114,10 +114,10 @@ If CLASS is actually an object, then also display current values of that object.
114 (when ch 114 (when ch
115 (insert " Children ") 115 (insert " Children ")
116 (while (setq cur (pop ch)) 116 (while (setq cur (pop ch))
117 (insert "‘") 117 (insert (substitute-command-keys "‘"))
118 (help-insert-xref-button (symbol-name cur) 118 (help-insert-xref-button (symbol-name cur)
119 'help-function cur) 119 'help-function cur)
120 (insert (if ch "’, " "’"))) 120 (insert (substitute-command-keys (if ch "’, " "’"))))
121 (insert ".\n"))) 121 (insert ".\n")))
122 ;; System documentation 122 ;; System documentation
123 (let ((doc (documentation-property class 'variable-documentation))) 123 (let ((doc (documentation-property class 'variable-documentation)))
@@ -130,9 +130,9 @@ If CLASS is actually an object, then also display current values of that object.
130 (when generics 130 (when generics
131 (insert (propertize "Specialized Methods:\n\n" 'face 'bold)) 131 (insert (propertize "Specialized Methods:\n\n" 'face 'bold))
132 (dolist (generic generics) 132 (dolist (generic generics)
133 (insert "‘") 133 (insert (substitute-command-keys "‘"))
134 (help-insert-xref-button (symbol-name generic) 'help-function generic) 134 (help-insert-xref-button (symbol-name generic) 'help-function generic)
135 (insert "’") 135 (insert (substitute-command-keys "’"))
136 (pcase-dolist (`(,qualifiers ,args ,doc) 136 (pcase-dolist (`(,qualifiers ,args ,doc)
137 (eieio-method-documentation generic class)) 137 (eieio-method-documentation generic class))
138 (insert (format " %s%S\n" qualifiers args) 138 (insert (format " %s%S\n" qualifiers args)
@@ -245,11 +245,11 @@ are not abstract."
245 (setq location 245 (setq location
246 (find-lisp-object-file-name ctr def))) 246 (find-lisp-object-file-name ctr def)))
247 (when location 247 (when location
248 (insert " in ‘") 248 (insert (substitute-command-keys " in ‘"))
249 (help-insert-xref-button 249 (help-insert-xref-button
250 (help-fns-short-filename location) 250 (help-fns-short-filename location)
251 'eieio-class-def ctr location 'eieio-defclass) 251 'eieio-class-def ctr location 'eieio-defclass)
252 (insert "’")) 252 (insert (substitute-command-keys "’")))
253 (insert ".\nCreates an object of class " (symbol-name ctr) ".") 253 (insert ".\nCreates an object of class " (symbol-name ctr) ".")
254 (goto-char (point-max)) 254 (goto-char (point-max))
255 (if (autoloadp def) 255 (if (autoloadp def)
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index ab01a109b7a..72a23cfdfc6 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -403,8 +403,8 @@
403 ;; Words inside \\[] tend to be for `substitute-command-keys'. 403 ;; Words inside \\[] tend to be for `substitute-command-keys'.
404 ("\\\\\\\\\\[\\(\\(?:\\sw\\|\\s_\\)+\\)\\]" 404 ("\\\\\\\\\\[\\(\\(?:\\sw\\|\\s_\\)+\\)\\]"
405 (1 font-lock-constant-face prepend)) 405 (1 font-lock-constant-face prepend))
406 ;; Words inside ‘’ and `' tend to be symbol names. 406 ;; Words inside ‘’ and '' and `' tend to be symbol names.
407 ("[`‘]\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)['’]" 407 ("['`‘]\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)['’]"
408 (1 font-lock-constant-face prepend)) 408 (1 font-lock-constant-face prepend))
409 ;; Constant values. 409 ;; Constant values.
410 ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face) 410 ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face)
@@ -452,8 +452,8 @@
452 ;; Erroneous structures. 452 ;; Erroneous structures.
453 (,(concat "(" cl-errs-re "\\_>") 453 (,(concat "(" cl-errs-re "\\_>")
454 (1 font-lock-warning-face)) 454 (1 font-lock-warning-face))
455 ;; Words inside ‘’ and `' tend to be symbol names. 455 ;; Words inside ‘’ and '' and `' tend to be symbol names.
456 ("[`‘]\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)['’]" 456 ("['`‘]\\(\\(?:\\sw\\|\\s_\\)\\(?:\\sw\\|\\s_\\)+\\)['’]"
457 (1 font-lock-constant-face prepend)) 457 (1 font-lock-constant-face prepend))
458 ;; Constant values. 458 ;; Constant values.
459 ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face) 459 ("\\_<:\\(?:\\sw\\|\\s_\\)+\\_>" 0 font-lock-builtin-face)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 074d3e8dda3..62900e08360 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -2173,17 +2173,18 @@ will be deleted."
2173 "Installed" 2173 "Installed"
2174 (capitalize status)) ;FIXME: Why comment-face? 2174 (capitalize status)) ;FIXME: Why comment-face?
2175 'font-lock-face 'font-lock-comment-face)) 2175 'font-lock-face 'font-lock-comment-face))
2176 (insert " in ‘") 2176 (insert (substitute-command-keys " in ‘"))
2177 ;; Todo: Add button for uninstalling. 2177 ;; Todo: Add button for uninstalling.
2178 (help-insert-xref-button (abbreviate-file-name 2178 (help-insert-xref-button (abbreviate-file-name
2179 (file-name-as-directory pkg-dir)) 2179 (file-name-as-directory pkg-dir))
2180 'help-package-def pkg-dir) 2180 'help-package-def pkg-dir)
2181 (if (and (package-built-in-p name) 2181 (if (and (package-built-in-p name)
2182 (not (package-built-in-p name version))) 2182 (not (package-built-in-p name version)))
2183 (insert "’,\n shadowing a " 2183 (insert (substitute-command-keys
2184 "’,\n shadowing a ")
2184 (propertize "built-in package" 2185 (propertize "built-in package"
2185 'font-lock-face 'font-lock-builtin-face)) 2186 'font-lock-face 'font-lock-builtin-face))
2186 (insert "’")) 2187 (insert (substitute-command-keys "’")))
2187 (if signed 2188 (if signed
2188 (insert ".") 2189 (insert ".")
2189 (insert " (unsigned).")) 2190 (insert " (unsigned)."))
diff --git a/lisp/faces.el b/lisp/faces.el
index 4366c0b9f23..ac6486ee46c 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1428,10 +1428,12 @@ If FRAME is omitted or nil, use the selected frame."
1428 (when alias 1428 (when alias
1429 (setq face alias) 1429 (setq face alias)
1430 (insert 1430 (insert
1431 (format "\n %s is an alias for the face ‘%s’.\n%s" 1431 (format (substitute-command-keys
1432 "\n %s is an alias for the face ‘%s’.\n%s")
1432 f alias 1433 f alias
1433 (if (setq obsolete (get f 'obsolete-face)) 1434 (if (setq obsolete (get f 'obsolete-face))
1434 (format " This face is obsolete%s; use ‘%s’ instead.\n" 1435 (format (substitute-command-keys
1436 " This face is obsolete%s; use ‘%s’ instead.\n")
1435 (if (stringp obsolete) 1437 (if (stringp obsolete)
1436 (format " since %s" obsolete) 1438 (format " since %s" obsolete)
1437 "") 1439 "")
@@ -1449,12 +1451,13 @@ If FRAME is omitted or nil, use the selected frame."
1449 (help-xref-button 1 'help-customize-face f))) 1451 (help-xref-button 1 'help-customize-face f)))
1450 (setq file-name (find-lisp-object-file-name f 'defface)) 1452 (setq file-name (find-lisp-object-file-name f 'defface))
1451 (when file-name 1453 (when file-name
1452 (princ "Defined in ‘") 1454 (princ (substitute-command-keys "Defined in ‘"))
1453 (princ (file-name-nondirectory file-name)) 1455 (princ (file-name-nondirectory file-name))
1454 (princ "’") 1456 (princ (substitute-command-keys "’"))
1455 ;; Make a hyperlink to the library. 1457 ;; Make a hyperlink to the library.
1456 (save-excursion 1458 (save-excursion
1457 (re-search-backward "‘\\([^‘’]+\\)’" nil t) 1459 (re-search-backward
1460 (substitute-command-keys "‘\\([^‘’]+\\)’") nil t)
1458 (help-xref-button 1 'help-face-def f file-name)) 1461 (help-xref-button 1 'help-face-def f file-name))
1459 (princ ".") 1462 (princ ".")
1460 (terpri) 1463 (terpri)
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 80f30e88fa4..9541d4797b4 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -306,7 +306,9 @@ suitable file is found, return nil."
306 (when remapped 306 (when remapped
307 (princ "Its keys are remapped to ") 307 (princ "Its keys are remapped to ")
308 (princ (if (symbolp remapped) 308 (princ (if (symbolp remapped)
309 (concat "‘" (symbol-name remapped) "’") 309 (concat (substitute-command-keys "‘")
310 (symbol-name remapped)
311 (substitute-command-keys "’"))
310 "an anonymous command")) 312 "an anonymous command"))
311 (princ ".\n")) 313 (princ ".\n"))
312 314
@@ -340,16 +342,18 @@ suitable file is found, return nil."
340 (insert "\nThis function has a compiler macro") 342 (insert "\nThis function has a compiler macro")
341 (if (symbolp handler) 343 (if (symbolp handler)
342 (progn 344 (progn
343 (insert (format " ‘%s’" handler)) 345 (insert (format (substitute-command-keys " ‘%s’") handler))
344 (save-excursion 346 (save-excursion
345 (re-search-backward "‘\\([^‘’]+\\)’" nil t) 347 (re-search-backward (substitute-command-keys "‘\\([^‘’]+\\)’")
348 nil t)
346 (help-xref-button 1 'help-function handler))) 349 (help-xref-button 1 'help-function handler)))
347 ;; FIXME: Obsolete since 24.4. 350 ;; FIXME: Obsolete since 24.4.
348 (let ((lib (get function 'compiler-macro-file))) 351 (let ((lib (get function 'compiler-macro-file)))
349 (when (stringp lib) 352 (when (stringp lib)
350 (insert (format " in ‘%s’" lib)) 353 (insert (format (substitute-command-keys " in ‘%s’") lib))
351 (save-excursion 354 (save-excursion
352 (re-search-backward "‘\\([^‘’]+\\)’" nil t) 355 (re-search-backward (substitute-command-keys "‘\\([^‘’]+\\)’")
356 nil t)
353 (help-xref-button 1 'help-function-cmacro function lib))))) 357 (help-xref-button 1 'help-function-cmacro function lib)))))
354 (insert ".\n")))) 358 (insert ".\n"))))
355 359
@@ -404,13 +408,13 @@ suitable file is found, return nil."
404 (get function 408 (get function
405 'derived-mode-parent)))) 409 'derived-mode-parent))))
406 (when parent-mode 410 (when parent-mode
407 (insert "\nParent mode: ‘") 411 (insert (substitute-command-keys "\nParent mode: ‘"))
408 (let ((beg (point))) 412 (let ((beg (point)))
409 (insert (format "%s" parent-mode)) 413 (insert (format "%s" parent-mode))
410 (make-text-button beg (point) 414 (make-text-button beg (point)
411 'type 'help-function 415 'type 'help-function
412 'help-args (list parent-mode))) 416 'help-args (list parent-mode)))
413 (insert "’.\n")))) 417 (insert (substitute-command-keys "’.\n")))))
414 418
415(defun help-fns--obsolete (function) 419(defun help-fns--obsolete (function)
416 ;; Ignore lambda constructs, keyboard macros, etc. 420 ;; Ignore lambda constructs, keyboard macros, etc.
@@ -426,7 +430,9 @@ suitable file is found, return nil."
426 (when (nth 2 obsolete) 430 (when (nth 2 obsolete)
427 (insert (format " since %s" (nth 2 obsolete)))) 431 (insert (format " since %s" (nth 2 obsolete))))
428 (insert (cond ((stringp use) (concat ";\n" use)) 432 (insert (cond ((stringp use) (concat ";\n" use))
429 (use (format ";\nuse ‘%s’ instead." use)) 433 (use (format (substitute-command-keys
434 ";\nuse ‘%s’ instead.")
435 use))
430 (t ".")) 436 (t "."))
431 "\n")))) 437 "\n"))))
432 438
@@ -462,7 +468,8 @@ FILE is the file where FUNCTION was probably defined."
462 (format ";\nin Lisp code %s" interactive-only)) 468 (format ";\nin Lisp code %s" interactive-only))
463 ((and (symbolp 'interactive-only) 469 ((and (symbolp 'interactive-only)
464 (not (eq interactive-only t))) 470 (not (eq interactive-only t)))
465 (format ";\nin Lisp code use ‘%s’ instead." 471 (format (substitute-command-keys
472 ";\nin Lisp code use ‘%s’ instead.")
466 interactive-only)) 473 interactive-only))
467 (t ".")) 474 (t "."))
468 "\n"))))) 475 "\n")))))
@@ -531,7 +538,8 @@ FILE is the file where FUNCTION was probably defined."
531 ;; Aliases are Lisp functions, so we need to check 538 ;; Aliases are Lisp functions, so we need to check
532 ;; aliases before functions. 539 ;; aliases before functions.
533 (aliased 540 (aliased
534 (format "an alias for ‘%s’" real-def)) 541 (format (substitute-command-keys "an alias for ‘%s’")
542 real-def))
535 ((autoloadp def) 543 ((autoloadp def)
536 (format "%s autoloaded %s" 544 (format "%s autoloaded %s"
537 (if (commandp def) "an interactive" "an") 545 (if (commandp def) "an interactive" "an")
@@ -565,21 +573,24 @@ FILE is the file where FUNCTION was probably defined."
565 (with-current-buffer standard-output 573 (with-current-buffer standard-output
566 (save-excursion 574 (save-excursion
567 (save-match-data 575 (save-match-data
568 (when (re-search-backward "alias for ‘\\([^‘’]+\\)’" nil t) 576 (when (re-search-backward (substitute-command-keys
577 "alias for ‘\\([^‘’]+\\)’")
578 nil t)
569 (help-xref-button 1 'help-function real-def))))) 579 (help-xref-button 1 'help-function real-def)))))
570 580
571 (when file-name 581 (when file-name
572 (princ " in ‘") 582 (princ (substitute-command-keys " in ‘"))
573 ;; We used to add .el to the file name, 583 ;; We used to add .el to the file name,
574 ;; but that's completely wrong when the user used load-file. 584 ;; but that's completely wrong when the user used load-file.
575 (princ (if (eq file-name 'C-source) 585 (princ (if (eq file-name 'C-source)
576 "C source code" 586 "C source code"
577 (help-fns-short-filename file-name))) 587 (help-fns-short-filename file-name)))
578 (princ "’") 588 (princ (substitute-command-keys "’"))
579 ;; Make a hyperlink to the library. 589 ;; Make a hyperlink to the library.
580 (with-current-buffer standard-output 590 (with-current-buffer standard-output
581 (save-excursion 591 (save-excursion
582 (re-search-backward "‘\\([^‘’]+\\)’" nil t) 592 (re-search-backward (substitute-command-keys "‘\\([^‘’]+\\)’")
593 nil t)
583 (help-xref-button 1 'help-function-def function file-name)))) 594 (help-xref-button 1 'help-function-def function file-name))))
584 (princ ".") 595 (princ ".")
585 (with-current-buffer (help-buffer) 596 (with-current-buffer (help-buffer)
@@ -712,14 +723,17 @@ it is displayed along with the global value."
712 723
713 (if file-name 724 (if file-name
714 (progn 725 (progn
715 (princ " is a variable defined in ‘") 726 (princ (substitute-command-keys
727 " is a variable defined in ‘"))
716 (princ (if (eq file-name 'C-source) 728 (princ (if (eq file-name 'C-source)
717 "C source code" 729 "C source code"
718 (file-name-nondirectory file-name))) 730 (file-name-nondirectory file-name)))
719 (princ "’.\n") 731 (princ (substitute-command-keys "’.\n"))
720 (with-current-buffer standard-output 732 (with-current-buffer standard-output
721 (save-excursion 733 (save-excursion
722 (re-search-backward "‘\\([^‘’]+\\)’" nil t) 734 (re-search-backward (substitute-command-keys
735 "‘\\([^‘’]+\\)’")
736 nil t)
723 (help-xref-button 1 'help-variable-def 737 (help-xref-button 1 'help-variable-def
724 variable file-name))) 738 variable file-name)))
725 (if valvoid 739 (if valvoid
@@ -849,7 +863,8 @@ if it is given a local binding.\n")))
849 ;; Mention if it's an alias. 863 ;; Mention if it's an alias.
850 (unless (eq alias variable) 864 (unless (eq alias variable)
851 (setq extra-line t) 865 (setq extra-line t)
852 (princ (format " This variable is an alias for ‘%s’.\n" 866 (princ (format (substitute-command-keys
867 " This variable is an alias for ‘%s’.\n")
853 alias))) 868 alias)))
854 869
855 (when obsolete 870 (when obsolete
@@ -858,7 +873,8 @@ if it is given a local binding.\n")))
858 (if (nth 2 obsolete) 873 (if (nth 2 obsolete)
859 (princ (format " since %s" (nth 2 obsolete)))) 874 (princ (format " since %s" (nth 2 obsolete))))
860 (princ (cond ((stringp use) (concat ";\n " use)) 875 (princ (cond ((stringp use) (concat ";\n " use))
861 (use (format ";\n use ‘%s’ instead." 876 (use (format (substitute-command-keys
877 ";\n use ‘%s’ instead.")
862 (car obsolete))) 878 (car obsolete)))
863 (t "."))) 879 (t ".")))
864 (terpri)) 880 (terpri))
@@ -889,14 +905,15 @@ if it is given a local binding.\n")))
889 ;; Otherwise, assume it was set directly. 905 ;; Otherwise, assume it was set directly.
890 (setq file (car file) 906 (setq file (car file)
891 dir-file nil))) 907 dir-file nil)))
892 (princ (if dir-file 908 (princ (substitute-command-keys
893 "by the file\n ‘" 909 (if dir-file
894 "for the directory\n ‘")) 910 "by the file\n ‘"
911 "for the directory\n ‘")))
895 (with-current-buffer standard-output 912 (with-current-buffer standard-output
896 (insert-text-button 913 (insert-text-button
897 file 'type 'help-dir-local-var-def 914 file 'type 'help-dir-local-var-def
898 'help-args (list variable file))) 915 'help-args (list variable file)))
899 (princ "’.\n"))) 916 (princ (substitute-command-keys "’.\n"))))
900 (princ " This variable's value is file-local.\n"))) 917 (princ " This variable's value is file-local.\n")))
901 918
902 (when (memq variable ignored-local-variables) 919 (when (memq variable ignored-local-variables)
@@ -910,8 +927,9 @@ variable.\n"))
910 (princ " This variable may be risky if used as a \ 927 (princ " This variable may be risky if used as a \
911file-local variable.\n") 928file-local variable.\n")
912 (when (assq variable safe-local-variable-values) 929 (when (assq variable safe-local-variable-values)
913 (princ " However, you have added it to \ 930 (princ (substitute-command-keys
914‘safe-local-variable-values’.\n"))) 931 " However, you have added it to \
932‘safe-local-variable-values’.\n"))))
915 933
916 (when safe-var 934 (when safe-var
917 (setq extra-line t) 935 (setq extra-line t)
@@ -919,7 +937,8 @@ file-local variable.\n")
919 (princ "if its value\n satisfies the predicate ") 937 (princ "if its value\n satisfies the predicate ")
920 (princ (if (byte-code-function-p safe-var) 938 (princ (if (byte-code-function-p safe-var)
921 "which is a byte-compiled expression.\n" 939 "which is a byte-compiled expression.\n"
922 (format "‘%s’.\n" safe-var)))) 940 (format (substitute-command-keys "‘%s’.\n")
941 safe-var))))
923 942
924 (if extra-line (terpri)) 943 (if extra-line (terpri))
925 (princ "Documentation:\n") 944 (princ "Documentation:\n")
diff --git a/lisp/help-mode.el b/lisp/help-mode.el
index 3fc0ad2b403..6454eed27bd 100644
--- a/lisp/help-mode.el
+++ b/lisp/help-mode.el
@@ -322,7 +322,7 @@ Commands:
322 "\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)" 322 "\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)"
323 "[ \t\n]+\\)?" 323 "[ \t\n]+\\)?"
324 ;; Note starting with word-syntax character: 324 ;; Note starting with word-syntax character:
325 "[`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]")) 325 "['`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]"))
326 "Regexp matching doc string references to symbols. 326 "Regexp matching doc string references to symbols.
327 327
328The words preceding the quoted symbol can be used in doc strings to 328The words preceding the quoted symbol can be used in doc strings to
@@ -338,11 +338,11 @@ when help commands related to multilingual environment (e.g.,
338 338
339(defconst help-xref-info-regexp 339(defconst help-xref-info-regexp
340 (purecopy 340 (purecopy
341 "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+[`‘]\\([^'’]+\\)['’]") 341 "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+['`‘]\\([^'’]+\\)['’]")
342 "Regexp matching doc string references to an Info node.") 342 "Regexp matching doc string references to an Info node.")
343 343
344(defconst help-xref-url-regexp 344(defconst help-xref-url-regexp
345 (purecopy "\\<[Uu][Rr][Ll][ \t\n]+[`‘]\\([^'’]+\\)['’]") 345 (purecopy "\\<[Uu][Rr][Ll][ \t\n]+['`‘]\\([^'’]+\\)['’]")
346 "Regexp matching doc string references to a URL.") 346 "Regexp matching doc string references to a URL.")
347 347
348;;;###autoload 348;;;###autoload
diff --git a/lisp/help.el b/lisp/help.el
index 2bf53c09b05..7a3460c1b3d 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -964,12 +964,14 @@ documentation for the major and minor modes of that buffer."
964 (let* ((mode major-mode) 964 (let* ((mode major-mode)
965 (file-name (find-lisp-object-file-name mode nil))) 965 (file-name (find-lisp-object-file-name mode nil)))
966 (when file-name 966 (when file-name
967 (princ (concat " defined in ‘" (file-name-nondirectory file-name) 967 (princ (concat (substitute-command-keys " defined in ‘")
968 "’")) 968 (file-name-nondirectory file-name)
969 (substitute-command-keys "’")))
969 ;; Make a hyperlink to the library. 970 ;; Make a hyperlink to the library.
970 (with-current-buffer standard-output 971 (with-current-buffer standard-output
971 (save-excursion 972 (save-excursion
972 (re-search-backward "‘\\([^‘’]+\\)’" nil t) 973 (re-search-backward (substitute-command-keys "‘\\([^‘’]+\\)’")
974 nil t)
973 (help-xref-button 1 'help-function-def mode file-name))))) 975 (help-xref-button 1 'help-function-def mode file-name)))))
974 (princ ":\n") 976 (princ ":\n")
975 (princ (documentation major-mode))))) 977 (princ (documentation major-mode)))))
diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el
index e56fcebfc26..16c1003960a 100644
--- a/lisp/international/mule-cmds.el
+++ b/lisp/international/mule-cmds.el
@@ -177,7 +177,7 @@
177 "\\(charset\\)" 177 "\\(charset\\)"
178 "\\)\\s-+\\)?" 178 "\\)\\s-+\\)?"
179 ;; Note starting with word-syntax character: 179 ;; Note starting with word-syntax character:
180 "[`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]"))) 180 "['`‘]\\(\\sw\\(\\sw\\|\\s_\\)+\\)['’]")))
181 181
182(defun coding-system-change-eol-conversion (coding-system eol-type) 182(defun coding-system-change-eol-conversion (coding-system eol-type)
183 "Return a coding system which differs from CODING-SYSTEM in EOL conversion. 183 "Return a coding system which differs from CODING-SYSTEM in EOL conversion.
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 295e2aada2a..f7d8964c9fc 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -2863,7 +2863,7 @@ The following properties have special meanings for this widget:
2863 :type 'boolean 2863 :type 'boolean
2864 :group 'widget-documentation) 2864 :group 'widget-documentation)
2865 2865
2866(defcustom widget-documentation-link-regexp "[`‘]\\([^\n `'‘’]+\\)['’]" 2866(defcustom widget-documentation-link-regexp "['`‘]\\([^\n `'‘’]+\\)['’]"
2867 "Regexp for matching potential links in documentation strings. 2867 "Regexp for matching potential links in documentation strings.
2868The first group should be the link itself." 2868The first group should be the link itself."
2869 :type 'regexp 2869 :type 'regexp
diff --git a/src/doc.c b/src/doc.c
index 81b1354668f..2ea416f3a2b 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
32#include "lisp.h" 32#include "lisp.h"
33#include "character.h" 33#include "character.h"
34#include "buffer.h" 34#include "buffer.h"
35#include "disptab.h"
35#include "keyboard.h" 36#include "keyboard.h"
36#include "keymap.h" 37#include "keymap.h"
37 38
@@ -683,6 +684,18 @@ the same file name is found in the `doc-directory'. */)
683 return unbind_to (count, Qnil); 684 return unbind_to (count, Qnil);
684} 685}
685 686
687/* Declare named constants for U+2018 LEFT SINGLE QUOTATION MARK and
688 U+2019 RIGHT SINGLE QUOTATION MARK, which have UTF-8 encodings
689 "\xE2\x80\x98" and "\xE2\x80\x99", respectively. */
690enum
691 {
692 LEFT_SINGLE_QUOTATION_MARK = 0x2018,
693 uLSQM0 = 0xE2, uLSQM1 = 0x80, uLSQM2 = 0x98,
694 uRSQM0 = 0xE2, uRSQM1 = 0x80, uRSQM2 = 0x99,
695 };
696static unsigned char const LSQM[] = { uLSQM0, uLSQM1, uLSQM2 };
697static unsigned char const RSQM[] = { uRSQM0, uRSQM1, uRSQM2 };
698
686DEFUN ("substitute-command-keys", Fsubstitute_command_keys, 699DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
687 Ssubstitute_command_keys, 1, 1, 0, 700 Ssubstitute_command_keys, 1, 1, 0,
688 doc: /* Substitute key descriptions for command names in STRING. 701 doc: /* Substitute key descriptions for command names in STRING.
@@ -699,8 +712,10 @@ summary).
699Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR 712Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR
700as the keymap for future \\=\\[COMMAND] substrings. 713as the keymap for future \\=\\[COMMAND] substrings.
701 714
702Each \\=` is replaced by ‘. Each ' preceded by \\=` and without 715Each \\=‘ and \\=’ are replaced by left and right quote. Each \\=` is
703intervening ' is replaced by ’. 716replaced by left quote, and each ' preceded by \\=` and without
717intervening ' is replaced by right quote. Left and right quote
718characters are specified by ‘help-quote-translation’.
704 719
705\\=\\= quotes the following character and is discarded; thus, 720\\=\\= quotes the following character and is discarded; thus,
706\\=\\=\\=\\= puts \\=\\= into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and 721\\=\\=\\=\\= puts \\=\\= into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and
@@ -719,7 +734,7 @@ Otherwise, return a new string. */)
719 ptrdiff_t bsize; 734 ptrdiff_t bsize;
720 Lisp_Object tem; 735 Lisp_Object tem;
721 Lisp_Object keymap; 736 Lisp_Object keymap;
722 unsigned char *start; 737 unsigned char const *start;
723 ptrdiff_t length, length_byte; 738 ptrdiff_t length, length_byte;
724 Lisp_Object name; 739 Lisp_Object name;
725 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; 740 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
@@ -735,6 +750,21 @@ Otherwise, return a new string. */)
735 name = Qnil; 750 name = Qnil;
736 GCPRO4 (string, tem, keymap, name); 751 GCPRO4 (string, tem, keymap, name);
737 752
753 enum { unicode, grave_accent, apostrophe } quote_translation = unicode;
754 if (EQ (Vhelp_quote_translation, make_number ('`')))
755 quote_translation = grave_accent;
756 else if (EQ (Vhelp_quote_translation, make_number ('\'')))
757 quote_translation = apostrophe;
758 else if (NILP (Vhelp_quote_translation)
759 && DISP_TABLE_P (Vstandard_display_table))
760 {
761 Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table),
762 LEFT_SINGLE_QUOTATION_MARK);
763 if (VECTORP (dv) && ASIZE (dv) == 1
764 && EQ (AREF (dv, 0), make_number ('\'')))
765 quote_translation = apostrophe;
766 }
767
738 multibyte = STRING_MULTIBYTE (string); 768 multibyte = STRING_MULTIBYTE (string);
739 nchars = 0; 769 nchars = 0;
740 770
@@ -932,38 +962,39 @@ Otherwise, return a new string. */)
932 strp = SDATA (string) + idx; 962 strp = SDATA (string) + idx;
933 } 963 }
934 } 964 }
935 else if (EQ (Vhelp_quote_translation, Qprefer_unicode) 965 else if (strp[0] == '`' && quote_translation == unicode)
936 && (strp[0] == '`'))
937 { 966 {
938 in_quote = true; 967 in_quote = true;
939 start = (unsigned char *) "\xE2\x80\x98"; /* ‘ */ 968 start = LSQM;
940 subst_quote: 969 subst_quote:
941 length = 1; 970 length = 1;
942 length_byte = 3; 971 length_byte = 3;
943 idx = strp - SDATA (string) + 1; 972 idx = strp - SDATA (string) + 1;
944 goto subst; 973 goto subst;
945 } 974 }
946 else if (EQ (Vhelp_quote_translation, Qprefer_unicode) 975 else if (strp[0] == '`' && quote_translation == apostrophe)
947 && (strp[0] == '\'' && in_quote)) 976 {
977 *bufp++ = '\'';
978 strp++;
979 nchars++;
980 changed = true;
981 }
982 else if (strp[0] == '\'' && in_quote)
948 { 983 {
949 in_quote = false; 984 in_quote = false;
950 start = (unsigned char *) "\xE2\x80\x99"; /* ’ */ 985 start = RSQM;
951 goto subst_quote; 986 goto subst_quote;
952 } 987 }
953 988 else if (strp[0] == uLSQM0 && strp[1] == uLSQM1
954 else if (EQ (Vhelp_quote_translation, Qtraditional) 989 && (strp[2] == uLSQM2 || strp[2] == uRSQM2)
955 && (strp[0] == 0xE2) 990 && quote_translation != unicode)
956 && (strp[1] == 0x80)
957 && ((strp[2] == 0x98) /* curly opening quote */
958 || (strp[2] == 0x99))) /* curly closing quote */
959 { 991 {
960 start = (strp[2] == 0x98) ? "`" : "'"; 992 *bufp++ = (strp[2] == uLSQM2 && quote_translation == grave_accent
961 length = 1; 993 ? '`' : '\'');
962 length_byte = 1; 994 strp += 3;
963 idx = strp - SDATA (string) + 3; 995 nchars++;
964 goto subst; 996 changed = true;
965 } 997 }
966
967 else if (! multibyte) /* just copy other chars */ 998 else if (! multibyte) /* just copy other chars */
968 *bufp++ = *strp++, nchars++; 999 *bufp++ = *strp++, nchars++;
969 else 1000 else
@@ -1005,15 +1036,13 @@ syms_of_doc (void)
1005 Vbuild_files = Qnil; 1036 Vbuild_files = Qnil;
1006 1037
1007 DEFVAR_LISP ("help-quote-translation", Vhelp_quote_translation, 1038 DEFVAR_LISP ("help-quote-translation", Vhelp_quote_translation,
1008 doc: /* How to translate quotes for display in *Help*. 1039 doc: /* Style to use for single quotes in help.
1009If the value is nil (default), no translation is done. 1040The value is a left single quote character of some style.
1010If it's the symbol `traditional', any occurrences of the curly quotes 1041Quote \\=‘like this\\=’ if the value is ?\\=‘ (left single quotation mark).
1011are translated to their ASCII "equivalents", GRAVE and APOSTROPHE. 1042Quote 'like this' if the value is ?' (apostrophe).
1012If it's the symbol `prefer-unicode', any matched pairs of GRAVE and 1043Quote \\=`like this' if the value is ?\\=` (grave accent).
1013APOSTROPHE will get translated into the "equivalent" curly quotes. 1044The default value is nil, which means quote with left single quotation mark
1014 1045if displayable, and with apostrophe otherwise. */);
1015Note that any translation done is done in a fresh copy of the doc
1016string, and doesn't overwrite the original characters. */);
1017 Vhelp_quote_translation = Qnil; 1046 Vhelp_quote_translation = Qnil;
1018 1047
1019 defsubr (&Sdocumentation); 1048 defsubr (&Sdocumentation);