specifies @var{mapvar}'s value as the keymap for any following
@samp{\[@var{command}]} sequences in this documentation string.
+@item `
+(grave accent) stands for a left single quotation mark (@samp{‘}).
+
+@item '
+(apostrophe) stands for a right single quotation mark (@samp{’}) if
+preceded by grave accent and there are no intervening apostrophes.
+Otherwise, apostrophe stands for itself.
+
@item \=
-quotes the following character and is discarded; thus, @samp{\=\[} puts
-@samp{\[} into the output, and @samp{\=\=} puts @samp{\=} into the
-output.
+quotes the following character and is discarded; thus, @samp{\=`} puts
+@samp{`} into the output, @samp{\=\[} puts @samp{\[} into the output,
+and @samp{\=\=} puts @samp{\=} into the output.
@end table
@strong{Please note:} Each @samp{\} must be doubled when written in a
@smallexample
@group
(substitute-command-keys
- "To abort recursive edit, type: \\[abort-recursive-edit]")
-@result{} "To abort recursive edit, type: C-]"
+ "To abort recursive edit, type ‘\\[abort-recursive-edit]’.")
+@result{} "To abort recursive edit, type ‘C-]’."
@end group
@group
@group
(substitute-command-keys
"To abort a recursive edit from the minibuffer, type\
-\\<minibuffer-local-must-match-map>\\[abort-recursive-edit].")
-@result{} "To abort a recursive edit from the minibuffer, type C-g."
+`\\<minibuffer-local-must-match-map>\\[abort-recursive-edit]'.")
+@result{} "To abort a recursive edit from the minibuffer, type ‘C-g’."
@end group
@end smallexample
denied" instead of "permission denied". The old behavior was problematic
in languages like German where downcasing rules depend on grammar.
+** (substitute-command-keys "`foo'") now returns "‘foo’".
+That is, it replaces grave accents by left single quotation marks, and
+apostrophes that match grave accents by right single quotation marks.
+As before, isolated apostrophes and characters preceded by \= are
+output as-is.
+
+++
** The character classes [:alpha:] and [:alnum:] in regular expressions
now match multibyte characters using Unicode character properties.
Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR
as the keymap for future \\=\\[COMMAND] substrings.
-\\=\\= quotes the following character and is discarded;
-thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
+
+Each \\=` is replaced by ‘. Each ' preceded by \\=` and without
+intervening ' is replaced by ’.
+
+\\=\\= quotes the following character and is discarded; thus,
+\\=\\=\\=\\= puts \\=\\= into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and
+\\=\\=\\=` puts \\=` into the output.
Return the original STRING if no substitutions are made.
Otherwise, return a new string. */)
(Lisp_Object string)
{
char *buf;
- bool changed = 0;
+ bool changed = false;
+ bool in_quote = false;
unsigned char *strp;
char *bufp;
ptrdiff_t idx;
keymap = Voverriding_local_map;
bsize = SBYTES (string);
+
+ /* Add some room for expansion due to quote replacement. */
+ enum { EXTRA_ROOM = 20 };
+ if (bsize <= STRING_BYTES_BOUND - EXTRA_ROOM)
+ bsize += EXTRA_ROOM;
+
bufp = buf = xmalloc (bsize);
strp = SDATA (string);
{
/* \= quotes the next character;
thus, to put in \[ without its special meaning, use \=\[. */
- changed = 1;
+ changed = true;
strp += 2;
if (multibyte)
{
ptrdiff_t start_idx;
bool follow_remap = 1;
- changed = 1;
strp += 2; /* skip \[ */
start = strp;
start_idx = start - SDATA (string);
Lisp_Object earlier_maps;
ptrdiff_t count = SPECPDL_INDEX ();
- changed = 1;
strp += 2; /* skip \{ or \< */
start = strp;
start_idx = start - SDATA (string);
length = SCHARS (tem);
length_byte = SBYTES (tem);
subst:
+ changed = true;
{
ptrdiff_t offset = bufp - buf;
if (STRING_BYTES_BOUND - length_byte < bsize)
strp = SDATA (string) + idx;
}
}
+ else if (strp[0] == '`')
+ {
+ in_quote = true;
+ start = (unsigned char *) "\xE2\x80\x98"; /* ‘ */
+ subst_quote:
+ length = 1;
+ length_byte = 3;
+ idx = strp - SDATA (string) + 1;
+ goto subst;
+ }
+ else if (strp[0] == '\'' && in_quote)
+ {
+ in_quote = false;
+ start = (unsigned char *) "\xE2\x80\x99"; /* ’ */
+ goto subst_quote;
+ }
else if (! multibyte) /* just copy other chars */
*bufp++ = *strp++, nchars++;
else