Commit 11b2744f authored by Paul Eggert's avatar Paul Eggert

substitute-command-keys now curves quotes

So, for example, it turns "`abc'" into "‘abc’" (Bug#20385).
* doc/lispref/help.texi (Keys in Documentation):
* etc/NEWS: Document this.
* src/doc.c (Fsubstitute_command_keys): Implement it.
parent 2363d498
......@@ -318,10 +318,18 @@ stands for no text itself. It is used only for a side effect: it
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
......@@ -354,8 +362,8 @@ specifies a key binding that the command does not actually have.
@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
......@@ -376,8 +384,8 @@ C-g abort-recursive-edit
@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
......
......@@ -805,6 +805,12 @@ when signaling a file error. For example, it now reports "Permission
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.
......
......@@ -693,15 +693,21 @@ summary).
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;
......@@ -734,6 +740,12 @@ Otherwise, return a new string. */)
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);
......@@ -743,7 +755,7 @@ Otherwise, return a new string. */)
{
/* \= quotes the next character;
thus, to put in \[ without its special meaning, use \=\[. */
changed = 1;
changed = true;
strp += 2;
if (multibyte)
{
......@@ -766,7 +778,6 @@ Otherwise, return a new string. */)
ptrdiff_t start_idx;
bool follow_remap = 1;
changed = 1;
strp += 2; /* skip \[ */
start = strp;
start_idx = start - SDATA (string);
......@@ -833,7 +844,6 @@ Otherwise, return a new string. */)
Lisp_Object earlier_maps;
ptrdiff_t count = SPECPDL_INDEX ();
changed = 1;
strp += 2; /* skip \{ or \< */
start = strp;
start_idx = start - SDATA (string);
......@@ -903,6 +913,7 @@ Otherwise, return a new string. */)
length = SCHARS (tem);
length_byte = SBYTES (tem);
subst:
changed = true;
{
ptrdiff_t offset = bufp - buf;
if (STRING_BYTES_BOUND - length_byte < bsize)
......@@ -916,6 +927,22 @@ Otherwise, return a new string. */)
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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment