aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2015-07-05 22:54:08 -0700
committerPaul Eggert2015-07-05 22:55:20 -0700
commitbe582b5e52180f4f25dbba73221d092e28ae68cc (patch)
treee7dae96f78572b5e60e0b7863bf7e702590f3896
parent0c26ac734b1ce48d9ced0d0528f1829de363f2a3 (diff)
downloademacs-scratch/quote-escaping.tar.gz
emacs-scratch/quote-escaping.zip
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.
333This permits display of documentation that refers accurately to the 333This permits display of documentation that refers accurately to the
334user's own customized key bindings. 334user's own customized key bindings.
335 335
336In the returned string, replacement characters that should not be
337further transformed have the text property @code{escaped}. For
338example, when @samp{\=`} is replaced by @samp{`} in the output, the
339replacement character has the text property @code{escaped}.
340
336@cindex advertised binding 341@cindex advertised binding
337If a command has multiple bindings, this function normally uses the 342If a command has multiple bindings, this function normally uses the
338first one it finds. You can specify one particular key binding by 343first 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
781denied" instead of "permission denied". The old behavior was problematic 781denied" instead of "permission denied". The old behavior was problematic
782in languages like German where downcasing rules depend on grammar. 782in languages like German where downcasing rules depend on grammar.
783 783
784** substitute-command-keys now indicates which characters are data.
785The string returned by substitute-command-keys now has the text
786property 'escaped' for characters that are part of data and should
787not be further transformed. For example, the character ` might be
788escaped to indicate that it is a grave accent and not an open quote.
789
784+++ 790+++
785** The character classes [:alpha:] and [:alnum:] in regular expressions 791** The character classes [:alpha:] and [:alnum:] in regular expressions
786now match multibyte characters using Unicode character properties. 792now 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.
696\\=\\= quotes the following character and is discarded; 696\\=\\= quotes the following character and is discarded;
697thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output. 697thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
698 698
699Replacement characters that should not be further transformed have the
700text property `escaped'. For example, when \\=\\=\\=` is replaced by \\=` in
701the output, the replacement character has the text property `escaped'.
702
699Return the original STRING if no substitutions are made. 703Return the original STRING if no substitutions are made.
700Otherwise, return a new string. */) 704Otherwise, return a new string. */)
701 (Lisp_Object string) 705 (Lisp_Object string)
@@ -704,7 +708,6 @@ Otherwise, return a new string. */)
704 return Qnil; 708 return Qnil;
705 CHECK_STRING (string); 709 CHECK_STRING (string);
706 710
707 ptrdiff_t bsize = SBYTES (string);
708 bool changed = false; 711 bool changed = false;
709 Lisp_Object tem = Qnil; 712 Lisp_Object tem = Qnil;
710 Lisp_Object name = Qnil; 713 Lisp_Object name = Qnil;
@@ -721,40 +724,52 @@ Otherwise, return a new string. */)
721 bool multibyte = STRING_MULTIBYTE (string); 724 bool multibyte = STRING_MULTIBYTE (string);
722 ptrdiff_t nchars = 0; 725 ptrdiff_t nchars = 0;
723 726
724 char *buf = xmalloc (bsize); 727 ptrdiff_t count = SPECPDL_INDEX ();
725 char *bufp = buf; 728
729 /* Switch to a temp buffer. */
730 struct buffer *oldbuf = current_buffer;
731 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
732 /* This is for an unusual case where some after-change
733 function uses 'format' or 'prin1' or something else that
734 will thrash Vprin1_to_string_buffer we are using. */
735 specbind (Qinhibit_modification_hooks, Qt);
726 736
727 unsigned char *strp = SDATA (string); 737 unsigned char *strp = SDATA (string);
728 while (strp < SDATA (string) + SBYTES (string)) 738 while (strp < SDATA (string) + SBYTES (string))
729 { 739 {
730 bool m_x_prefix = false; 740 ptrdiff_t opoint = PT;
731 ptrdiff_t idx;
732 unsigned char *start;
733 ptrdiff_t length, length_byte;
734 741
735 if (strp[0] == '\\' && strp[1] == '=') 742 if (strp[0] == '\\' && strp[1] == '=')
736 { 743 {
737 /* \= quotes the next character; 744 /* \= quotes the next character;
738 thus, to put in \[ without its special meaning, use \=\[. */ 745 thus, to put in \[ without its special meaning, use \=\[. */
739 strp += 2; 746 strp += 2;
747 int len = 1;
748 if (multibyte)
749 STRING_CHAR_AND_LENGTH (strp, len);
750 insert_1_both ((char *) strp, 1, len, false, false, false);
751 strp += len;
752 nchars++;
753 Fput_text_property (make_number (opoint), make_number (opoint + 1),
754 Qescaped, Qt, Qnil);
740 changed = true; 755 changed = true;
741 } 756 }
742 else if (strp[0] == '\\' && strp[1] == '[') 757 else if (strp[0] == '\\' && strp[1] == '[')
743 { 758 {
744 strp += 2; /* skip \[ */ 759 strp += 2; /* skip \[ */
745 start = strp; 760 unsigned char *start = strp;
746 ptrdiff_t start_idx = start - SDATA (string); 761 ptrdiff_t start_idx = start - SDATA (string);
747 762
748 while ((strp - SDATA (string) 763 while ((strp - SDATA (string)
749 < SBYTES (string)) 764 < SBYTES (string))
750 && *strp != ']') 765 && *strp != ']')
751 strp++; 766 strp++;
752 length_byte = strp - start; 767 ptrdiff_t length_byte = strp - start;
753 768
754 strp++; /* skip ] */ 769 strp++; /* skip ] */
755 770
756 /* Save STRP in IDX. */ 771 /* Save STRP in IDX. */
757 idx = strp - SDATA (string); 772 ptrdiff_t idx = strp - SDATA (string);
758 name = Fintern (make_string ((char *) start, length_byte), Qnil); 773 name = Fintern (make_string ((char *) start, length_byte), Qnil);
759 774
760 tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil); 775 tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
@@ -763,27 +778,34 @@ Otherwise, return a new string. */)
763 { 778 {
764 name = AREF (tem, 1); 779 name = AREF (tem, 1);
765 tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil); 780 tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
781 /* Fwhere_is_internal can GC, so we have to take
782 relocation of string contents into account. */
766 } 783 }
767 784
768 /* Note the Fwhere_is_internal can GC, so we have to take 785 ptrdiff_t length;
769 relocation of string contents into account. */
770 strp = SDATA (string) + idx;
771 start = SDATA (string) + start_idx;
772
773 if (NILP (tem)) /* but not on any keys */ 786 if (NILP (tem)) /* but not on any keys */
774 { 787 {
788 insert_1_both ("M-x ", 4, 4, false, false, false);
789 strp = SDATA (string) + start_idx;
775 if (multibyte) 790 if (multibyte)
776 length = multibyte_chars_in_text (start, length_byte); 791 length = multibyte_chars_in_text (strp, length_byte);
777 else 792 else
778 length = length_byte; 793 length = length_byte;
779 m_x_prefix = true; 794 insert_1_both ((char *) strp, length, length_byte,
780 goto subst; 795 false, false, false);
796 Fput_text_property (make_number (opoint), make_number (PT),
797 Qescaped, Qt, Qnil);
781 } 798 }
782 else 799 else
783 { /* function is on a key */ 800 {
801 /* FIXME: Fkey_description doesn't properly mark quote
802 characters that should be escaped. */
784 tem = Fkey_description (tem, Qnil); 803 tem = Fkey_description (tem, Qnil);
785 goto subst_string; 804 insert_from_string (tem, 0, 0, SCHARS (tem), SBYTES (tem), true);
786 } 805 }
806
807 strp = SDATA (string) + idx;
808 changed = true;
787 } 809 }
788 /* \{foo} is replaced with a summary of the keymap (symbol-value foo). 810 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
789 \<foo> just sets the keymap used for \[cmd]. */ 811 \<foo> just sets the keymap used for \[cmd]. */
@@ -791,21 +813,20 @@ Otherwise, return a new string. */)
791 { 813 {
792 /* This is for computing the SHADOWS arg for describe_map_tree. */ 814 /* This is for computing the SHADOWS arg for describe_map_tree. */
793 Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil); 815 Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil);
794 ptrdiff_t count = SPECPDL_INDEX ();
795 816
796 strp += 2; /* skip \{ or \< */ 817 strp += 2; /* skip \{ or \< */
797 start = strp; 818 unsigned char *start = strp;
798 ptrdiff_t start_idx = start - SDATA (string); 819 ptrdiff_t start_idx = start - SDATA (string);
799 820
800 while ((strp - SDATA (string) < SBYTES (string)) 821 while ((strp - SDATA (string) < SBYTES (string))
801 && *strp != '}' && *strp != '>') 822 && *strp != '}' && *strp != '>')
802 strp++; 823 strp++;
803 824
804 length_byte = strp - start; 825 ptrdiff_t length_byte = strp - start;
805 strp++; /* skip } or > */ 826 strp++; /* skip } or > */
806 827
807 /* Save STRP in IDX. */ 828 /* Save STRP in IDX. */
808 idx = strp - SDATA (string); 829 ptrdiff_t idx = strp - SDATA (string);
809 830
810 /* Get the value of the keymap in TEM, or nil if undefined. 831 /* Get the value of the keymap in TEM, or nil if undefined.
811 Do this while still in the user's current buffer 832 Do this while still in the user's current buffer
@@ -824,21 +845,16 @@ Otherwise, return a new string. */)
824 } 845 }
825 } 846 }
826 847
827 /* Now switch to a temp buffer. */
828 struct buffer *oldbuf = current_buffer;
829 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
830 /* This is for an unusual case where some after-change
831 function uses 'format' or 'prin1' or something else that
832 will thrash Vprin1_to_string_buffer we are using. */
833 specbind (Qinhibit_modification_hooks, Qt);
834
835 if (NILP (tem)) 848 if (NILP (tem))
836 { 849 {
837 name = Fsymbol_name (name); 850 name = Fsymbol_name (name);
838 insert_string ("\nUses keymap `"); 851 insert_string ("\nUses keymap `");
852 ptrdiff_t opoint = PT;
839 insert_from_string (name, 0, 0, 853 insert_from_string (name, 0, 0,
840 SCHARS (name), 854 SCHARS (name),
841 SBYTES (name), 1); 855 SBYTES (name), 1);
856 Fput_text_property (make_number (opoint), make_number (PT),
857 Qescaped, Qt, Qnil);
842 insert_string ("', which is not currently defined.\n"); 858 insert_string ("', which is not currently defined.\n");
843 if (start[-1] == '<') keymap = Qnil; 859 if (start[-1] == '<') keymap = Qnil;
844 } 860 }
@@ -853,66 +869,35 @@ Otherwise, return a new string. */)
853 describe_map_tree (tem, 1, Fnreverse (earlier_maps), 869 describe_map_tree (tem, 1, Fnreverse (earlier_maps),
854 Qnil, 0, 1, 0, 0, 1); 870 Qnil, 0, 1, 0, 0, 1);
855 } 871 }
856 tem = Fbuffer_string ();
857 Ferase_buffer ();
858 set_buffer_internal (oldbuf);
859 unbind_to (count, Qnil);
860
861 subst_string:
862 start = SDATA (tem);
863 length = SCHARS (tem);
864 length_byte = SBYTES (tem);
865 subst:;
866 ptrdiff_t stringtail_len = SBYTES (string) - idx;
867 ptrdiff_t offset = bufp - buf;
868 ptrdiff_t old_bufroom = bsize - offset;
869 ptrdiff_t new_bufroom = old_bufroom - 4 * m_x_prefix - length_byte;
870 if (new_bufroom < stringtail_len)
871 {
872 if (INT_SUBTRACT_OVERFLOW (stringtail_len, new_bufroom))
873 string_overflow ();
874 ptrdiff_t growth = max (bsize, stringtail_len - new_bufroom);
875 if (STRING_BYTES_BOUND - bsize < growth)
876 string_overflow ();
877 buf = xrealloc (buf, bsize += growth);
878 bufp = buf + offset;
879 }
880 if (m_x_prefix)
881 {
882 memcpy (bufp, "M-x ", 4);
883 bufp += 4;
884 nchars += 4;
885 }
886 memcpy (bufp, start, length_byte);
887 bufp += length_byte;
888 nchars += length;
889 /* Check STRING again in case gc relocated it. */
890 strp = SDATA (string) + idx;
891 changed = true; 872 changed = true;
892 continue;
893 } 873 }
894 874 else
895 /* Just copy one char. */ 875 {
896 int len = 1; 876 /* Just copy one char. */
897 if (multibyte) 877 int len = 1;
898 STRING_CHAR_AND_LENGTH (strp, len); 878 if (multibyte)
899 memcpy (bufp, strp, len); 879 STRING_CHAR_AND_LENGTH (strp, len);
900 strp += len; 880 insert_1_both ((char *) strp, 1, len, false, false, false);
901 bufp += len; 881 strp += len;
902 nchars++; 882 nchars++;
883 }
903 } 884 }
904 885
905 if (changed) /* don't bother if nothing substituted */ 886 if (changed) /* don't bother if nothing substituted */
906 tem = make_string_from_bytes (buf, nchars, bufp - buf); 887 tem = Fbuffer_string ();
907 else 888 else
908 tem = string; 889 tem = string;
909 xfree (buf); 890
891 Ferase_buffer ();
892 set_buffer_internal (oldbuf);
893 unbind_to (count, Qnil);
910 RETURN_UNGCPRO (tem); 894 RETURN_UNGCPRO (tem);
911} 895}
912 896
913void 897void
914syms_of_doc (void) 898syms_of_doc (void)
915{ 899{
900 DEFSYM (Qescaped, "escaped");
916 DEFSYM (Qfunction_documentation, "function-documentation"); 901 DEFSYM (Qfunction_documentation, "function-documentation");
917 902
918 DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name, 903 DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name,