summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2015-07-05 22:54:08 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2015-07-05 22:55:20 -0700
commitbe582b5e52180f4f25dbba73221d092e28ae68cc (patch)
treee7dae96f78572b5e60e0b7863bf7e702590f3896
parent0c26ac734b1ce48d9ced0d0528f1829de363f2a3 (diff)
downloademacs-scratch/quote-escaping.tar.gz
substitute-command-keys now marks escaped charsscratch/quote-escaping
* doc/lispref/help.texi (Keys in Documentation), etc/NEWS: Document this. * src/doc.c (Fsubstitute_command_keys): Give escaped characters the 'escaped' text property.
-rw-r--r--doc/lispref/help.texi5
-rw-r--r--etc/NEWS6
-rw-r--r--src/doc.c143
3 files changed, 75 insertions, 79 deletions
diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi
index 868d2843569..be4a6f7bc19 100644
--- a/doc/lispref/help.texi
+++ b/doc/lispref/help.texi
@@ -333,6 +333,11 @@ replaces them by what they stand for, returning the result as a string.
This permits display of documentation that refers accurately to the
user's own customized key bindings.
+In the returned string, replacement characters that should not be
+further transformed have the text property @code{escaped}. For
+example, when @samp{\=`} is replaced by @samp{`} in the output, the
+replacement character has the text property @code{escaped}.
+
@cindex advertised binding
If a command has multiple bindings, this function normally uses the
first one it finds. You can specify one particular key binding by
diff --git a/etc/NEWS b/etc/NEWS
index c4c9d774b5f..a298c76e333 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -781,6 +781,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 now indicates which characters are data.
+The string returned by substitute-command-keys now has the text
+property 'escaped' for characters that are part of data and should
+not be further transformed. For example, the character ` might be
+escaped to indicate that it is a grave accent and not an open quote.
+
+++
** The character classes [:alpha:] and [:alnum:] in regular expressions
now match multibyte characters using Unicode character properties.
diff --git a/src/doc.c b/src/doc.c
index dc159e1cac9..ed3b0b01d62 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -696,6 +696,10 @@ as the keymap for future \\=\\[COMMAND] substrings.
\\=\\= quotes the following character and is discarded;
thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
+Replacement characters that should not be further transformed have the
+text property `escaped'. For example, when \\=\\=\\=` is replaced by \\=` in
+the output, the replacement character has the text property `escaped'.
+
Return the original STRING if no substitutions are made.
Otherwise, return a new string. */)
(Lisp_Object string)
@@ -704,7 +708,6 @@ Otherwise, return a new string. */)
return Qnil;
CHECK_STRING (string);
- ptrdiff_t bsize = SBYTES (string);
bool changed = false;
Lisp_Object tem = Qnil;
Lisp_Object name = Qnil;
@@ -721,40 +724,52 @@ Otherwise, return a new string. */)
bool multibyte = STRING_MULTIBYTE (string);
ptrdiff_t nchars = 0;
- char *buf = xmalloc (bsize);
- char *bufp = buf;
+ ptrdiff_t count = SPECPDL_INDEX ();
+
+ /* Switch to a temp buffer. */
+ struct buffer *oldbuf = current_buffer;
+ set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
+ /* This is for an unusual case where some after-change
+ function uses 'format' or 'prin1' or something else that
+ will thrash Vprin1_to_string_buffer we are using. */
+ specbind (Qinhibit_modification_hooks, Qt);
unsigned char *strp = SDATA (string);
while (strp < SDATA (string) + SBYTES (string))
{
- bool m_x_prefix = false;
- ptrdiff_t idx;
- unsigned char *start;
- ptrdiff_t length, length_byte;
+ ptrdiff_t opoint = PT;
if (strp[0] == '\\' && strp[1] == '=')
{
/* \= quotes the next character;
thus, to put in \[ without its special meaning, use \=\[. */
strp += 2;
+ int len = 1;
+ if (multibyte)
+ STRING_CHAR_AND_LENGTH (strp, len);
+ insert_1_both ((char *) strp, 1, len, false, false, false);
+ strp += len;
+ nchars++;
+ Fput_text_property (make_number (opoint), make_number (opoint + 1),
+ Qescaped, Qt, Qnil);
changed = true;
}
else if (strp[0] == '\\' && strp[1] == '[')
{
strp += 2; /* skip \[ */
- start = strp;
+ unsigned char *start = strp;
ptrdiff_t start_idx = start - SDATA (string);
while ((strp - SDATA (string)
< SBYTES (string))
&& *strp != ']')
strp++;
- length_byte = strp - start;
+ ptrdiff_t length_byte = strp - start;
strp++; /* skip ] */
/* Save STRP in IDX. */
- idx = strp - SDATA (string);
+ ptrdiff_t idx = strp - SDATA (string);
name = Fintern (make_string ((char *) start, length_byte), Qnil);
tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
@@ -763,27 +778,34 @@ Otherwise, return a new string. */)
{
name = AREF (tem, 1);
tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
+ /* Fwhere_is_internal can GC, so we have to take
+ relocation of string contents into account. */
}
- /* Note the Fwhere_is_internal can GC, so we have to take
- relocation of string contents into account. */
- strp = SDATA (string) + idx;
- start = SDATA (string) + start_idx;
-
+ ptrdiff_t length;
if (NILP (tem)) /* but not on any keys */
{
+ insert_1_both ("M-x ", 4, 4, false, false, false);
+ strp = SDATA (string) + start_idx;
if (multibyte)
- length = multibyte_chars_in_text (start, length_byte);
+ length = multibyte_chars_in_text (strp, length_byte);
else
length = length_byte;
- m_x_prefix = true;
- goto subst;
+ insert_1_both ((char *) strp, length, length_byte,
+ false, false, false);
+ Fput_text_property (make_number (opoint), make_number (PT),
+ Qescaped, Qt, Qnil);
}
else
- { /* function is on a key */
+ {
+ /* FIXME: Fkey_description doesn't properly mark quote
+ characters that should be escaped. */
tem = Fkey_description (tem, Qnil);
- goto subst_string;
+ insert_from_string (tem, 0, 0, SCHARS (tem), SBYTES (tem), true);
}
+
+ strp = SDATA (string) + idx;
+ changed = true;
}
/* \{foo} is replaced with a summary of the keymap (symbol-value foo).
\<foo> just sets the keymap used for \[cmd]. */
@@ -791,21 +813,20 @@ Otherwise, return a new string. */)
{
/* This is for computing the SHADOWS arg for describe_map_tree. */
Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil);
- ptrdiff_t count = SPECPDL_INDEX ();
strp += 2; /* skip \{ or \< */
- start = strp;
+ unsigned char *start = strp;
ptrdiff_t start_idx = start - SDATA (string);
while ((strp - SDATA (string) < SBYTES (string))
&& *strp != '}' && *strp != '>')
strp++;
- length_byte = strp - start;
+ ptrdiff_t length_byte = strp - start;
strp++; /* skip } or > */
/* Save STRP in IDX. */
- idx = strp - SDATA (string);
+ ptrdiff_t idx = strp - SDATA (string);
/* Get the value of the keymap in TEM, or nil if undefined.
Do this while still in the user's current buffer
@@ -824,21 +845,16 @@ Otherwise, return a new string. */)
}
}
- /* Now switch to a temp buffer. */
- struct buffer *oldbuf = current_buffer;
- set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
- /* This is for an unusual case where some after-change
- function uses 'format' or 'prin1' or something else that
- will thrash Vprin1_to_string_buffer we are using. */
- specbind (Qinhibit_modification_hooks, Qt);
-
if (NILP (tem))
{
name = Fsymbol_name (name);
insert_string ("\nUses keymap `");
+ ptrdiff_t opoint = PT;
insert_from_string (name, 0, 0,
SCHARS (name),
SBYTES (name), 1);
+ Fput_text_property (make_number (opoint), make_number (PT),
+ Qescaped, Qt, Qnil);
insert_string ("', which is not currently defined.\n");
if (start[-1] == '<') keymap = Qnil;
}
@@ -853,66 +869,35 @@ Otherwise, return a new string. */)
describe_map_tree (tem, 1, Fnreverse (earlier_maps),
Qnil, 0, 1, 0, 0, 1);
}
- tem = Fbuffer_string ();
- Ferase_buffer ();
- set_buffer_internal (oldbuf);
- unbind_to (count, Qnil);
-
- subst_string:
- start = SDATA (tem);
- length = SCHARS (tem);
- length_byte = SBYTES (tem);
- subst:;
- ptrdiff_t stringtail_len = SBYTES (string) - idx;
- ptrdiff_t offset = bufp - buf;
- ptrdiff_t old_bufroom = bsize - offset;
- ptrdiff_t new_bufroom = old_bufroom - 4 * m_x_prefix - length_byte;
- if (new_bufroom < stringtail_len)
- {
- if (INT_SUBTRACT_OVERFLOW (stringtail_len, new_bufroom))
- string_overflow ();
- ptrdiff_t growth = max (bsize, stringtail_len - new_bufroom);
- if (STRING_BYTES_BOUND - bsize < growth)
- string_overflow ();
- buf = xrealloc (buf, bsize += growth);
- bufp = buf + offset;
- }
- if (m_x_prefix)
- {
- memcpy (bufp, "M-x ", 4);
- bufp += 4;
- nchars += 4;
- }
- memcpy (bufp, start, length_byte);
- bufp += length_byte;
- nchars += length;
- /* Check STRING again in case gc relocated it. */
- strp = SDATA (string) + idx;
changed = true;
- continue;
}
-
- /* Just copy one char. */
- int len = 1;
- if (multibyte)
- STRING_CHAR_AND_LENGTH (strp, len);
- memcpy (bufp, strp, len);
- strp += len;
- bufp += len;
- nchars++;
+ else
+ {
+ /* Just copy one char. */
+ int len = 1;
+ if (multibyte)
+ STRING_CHAR_AND_LENGTH (strp, len);
+ insert_1_both ((char *) strp, 1, len, false, false, false);
+ strp += len;
+ nchars++;
+ }
}
if (changed) /* don't bother if nothing substituted */
- tem = make_string_from_bytes (buf, nchars, bufp - buf);
+ tem = Fbuffer_string ();
else
tem = string;
- xfree (buf);
+
+ Ferase_buffer ();
+ set_buffer_internal (oldbuf);
+ unbind_to (count, Qnil);
RETURN_UNGCPRO (tem);
}
void
syms_of_doc (void)
{
+ DEFSYM (Qescaped, "escaped");
DEFSYM (Qfunction_documentation, "function-documentation");
DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name,