diff options
| author | Paul Eggert | 2015-07-05 22:54:08 -0700 |
|---|---|---|
| committer | Paul Eggert | 2015-07-05 22:55:20 -0700 |
| commit | be582b5e52180f4f25dbba73221d092e28ae68cc (patch) | |
| tree | e7dae96f78572b5e60e0b7863bf7e702590f3896 | |
| parent | 0c26ac734b1ce48d9ced0d0528f1829de363f2a3 (diff) | |
| download | emacs-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.texi | 5 | ||||
| -rw-r--r-- | etc/NEWS | 6 | ||||
| -rw-r--r-- | src/doc.c | 143 |
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. | |||
| 333 | This permits display of documentation that refers accurately to the | 333 | This permits display of documentation that refers accurately to the |
| 334 | user's own customized key bindings. | 334 | user's own customized key bindings. |
| 335 | 335 | ||
| 336 | In the returned string, replacement characters that should not be | ||
| 337 | further transformed have the text property @code{escaped}. For | ||
| 338 | example, when @samp{\=`} is replaced by @samp{`} in the output, the | ||
| 339 | replacement character has the text property @code{escaped}. | ||
| 340 | |||
| 336 | @cindex advertised binding | 341 | @cindex advertised binding |
| 337 | If a command has multiple bindings, this function normally uses the | 342 | If a command has multiple bindings, this function normally uses the |
| 338 | first one it finds. You can specify one particular key binding by | 343 | first one it finds. You can specify one particular key binding by |
| @@ -781,6 +781,12 @@ when signaling a file error. For example, it now reports "Permission | |||
| 781 | denied" instead of "permission denied". The old behavior was problematic | 781 | denied" instead of "permission denied". The old behavior was problematic |
| 782 | in languages like German where downcasing rules depend on grammar. | 782 | in languages like German where downcasing rules depend on grammar. |
| 783 | 783 | ||
| 784 | ** substitute-command-keys now indicates which characters are data. | ||
| 785 | The string returned by substitute-command-keys now has the text | ||
| 786 | property 'escaped' for characters that are part of data and should | ||
| 787 | not be further transformed. For example, the character ` might be | ||
| 788 | escaped 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 |
| 786 | now match multibyte characters using Unicode character properties. | 792 | now match multibyte characters using Unicode character properties. |
| @@ -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; |
| 697 | thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output. | 697 | thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output. |
| 698 | 698 | ||
| 699 | Replacement characters that should not be further transformed have the | ||
| 700 | text property `escaped'. For example, when \\=\\=\\=` is replaced by \\=` in | ||
| 701 | the output, the replacement character has the text property `escaped'. | ||
| 702 | |||
| 699 | Return the original STRING if no substitutions are made. | 703 | Return the original STRING if no substitutions are made. |
| 700 | Otherwise, return a new string. */) | 704 | Otherwise, 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 | ||
| 913 | void | 897 | void |
| 914 | syms_of_doc (void) | 898 | syms_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, |