diff options
| author | Stefan Kangas | 2020-10-18 15:19:09 +0200 |
|---|---|---|
| committer | Stefan Kangas | 2020-10-18 17:25:23 +0200 |
| commit | ef5a604f082f772424400f48b64e9c04edbcc766 (patch) | |
| tree | 98a3987703ed2d710c22be23f057ee6de6d15a53 | |
| parent | 8a1441310aa151e739cfed3bd2eff3358edc8001 (diff) | |
| download | emacs-ef5a604f082f772424400f48b64e9c04edbcc766.tar.gz emacs-ef5a604f082f772424400f48b64e9c04edbcc766.zip | |
Remove C version of substitute-command-keys
* src/doc.c (Fsubstitute_command_keys_old): Remove.
(syms_of_doc): Remove defsubr for Fsubstitute_command_keys_old.
* src/keymap.c (describe_map, describe_map_tree)
(describe_map_compare, describe_map_elt): Remove.
* src/keymap.h: Remove 'describe_map_tree'.
* test/lisp/help-tests.el (with-substitute-command-keys-test)
(help-tests-substitute-command-keys/compare)
(help-tests-substitute-command-keys/compare-all):
Don't test the C version of 'substitute-command-keys' removed
above.
| -rw-r--r-- | src/doc.c | 303 | ||||
| -rw-r--r-- | src/keymap.c | 334 | ||||
| -rw-r--r-- | src/keymap.h | 2 | ||||
| -rw-r--r-- | test/lisp/help-tests.el | 37 |
4 files changed, 3 insertions, 673 deletions
| @@ -715,308 +715,6 @@ See variable `text-quoting-style'. */) | |||
| 715 | } | 715 | } |
| 716 | } | 716 | } |
| 717 | 717 | ||
| 718 | DEFUN ("substitute-command-keys-old", Fsubstitute_command_keys_old, | ||
| 719 | Ssubstitute_command_keys_old, 1, 1, 0, | ||
| 720 | doc: /* Substitute key descriptions for command names in STRING. | ||
| 721 | Each substring of the form \\=\\[COMMAND] is replaced by either a | ||
| 722 | keystroke sequence that invokes COMMAND, or "M-x COMMAND" if COMMAND | ||
| 723 | is not on any keys. | ||
| 724 | |||
| 725 | Each substring of the form \\=\\{MAPVAR} is replaced by a summary of | ||
| 726 | the value of MAPVAR as a keymap. This summary is similar to the one | ||
| 727 | produced by `describe-bindings'. The summary ends in two newlines | ||
| 728 | \(used by the helper function `help-make-xrefs' to find the end of the | ||
| 729 | summary). | ||
| 730 | |||
| 731 | Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR | ||
| 732 | as the keymap for future \\=\\[COMMAND] substrings. | ||
| 733 | |||
| 734 | Each grave accent \\=` is replaced by left quote, and each apostrophe \\=' | ||
| 735 | is replaced by right quote. Left and right quote characters are | ||
| 736 | specified by `text-quoting-style'. | ||
| 737 | |||
| 738 | \\=\\= quotes the following character and is discarded; thus, \\=\\=\\=\\= puts \\=\\= | ||
| 739 | into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and \\=\\=\\=` puts \\=` into the | ||
| 740 | output. | ||
| 741 | |||
| 742 | Return the original STRING if no substitutions are made. | ||
| 743 | Otherwise, return a new string (without any text properties). */) | ||
| 744 | (Lisp_Object string) | ||
| 745 | { | ||
| 746 | char *buf; | ||
| 747 | bool changed = false; | ||
| 748 | bool nonquotes_changed = false; | ||
| 749 | unsigned char *strp; | ||
| 750 | char *bufp; | ||
| 751 | ptrdiff_t idx; | ||
| 752 | ptrdiff_t bsize; | ||
| 753 | Lisp_Object tem; | ||
| 754 | Lisp_Object keymap; | ||
| 755 | unsigned char const *start; | ||
| 756 | ptrdiff_t length, length_byte; | ||
| 757 | Lisp_Object name; | ||
| 758 | ptrdiff_t nchars; | ||
| 759 | |||
| 760 | if (NILP (string)) | ||
| 761 | return Qnil; | ||
| 762 | |||
| 763 | /* If STRING contains non-ASCII unibyte data, process its | ||
| 764 | properly-encoded multibyte equivalent instead. This simplifies | ||
| 765 | the implementation and is OK since substitute-command-keys is | ||
| 766 | intended for use only on text strings. Keep STRING around, since | ||
| 767 | it will be returned if no changes occur. */ | ||
| 768 | Lisp_Object str = Fstring_make_multibyte (string); | ||
| 769 | |||
| 770 | enum text_quoting_style quoting_style = text_quoting_style (); | ||
| 771 | |||
| 772 | nchars = 0; | ||
| 773 | |||
| 774 | /* KEYMAP is either nil (which means search all the active keymaps) | ||
| 775 | or a specified local map (which means search just that and the | ||
| 776 | global map). If non-nil, it might come from Voverriding_local_map, | ||
| 777 | or from a \\<mapname> construct in STRING itself.. */ | ||
| 778 | keymap = Voverriding_local_map; | ||
| 779 | |||
| 780 | ptrdiff_t strbytes = SBYTES (str); | ||
| 781 | bsize = strbytes; | ||
| 782 | |||
| 783 | /* Fixed-size stack buffer. */ | ||
| 784 | char sbuf[MAX_ALLOCA]; | ||
| 785 | |||
| 786 | /* Heap-allocated buffer, if any. */ | ||
| 787 | char *abuf; | ||
| 788 | |||
| 789 | /* Extra room for expansion due to replacing ‘\[]’ with ‘M-x ’. */ | ||
| 790 | enum { EXTRA_ROOM = sizeof "M-x " - sizeof "\\[]" }; | ||
| 791 | |||
| 792 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 793 | |||
| 794 | if (bsize <= sizeof sbuf - EXTRA_ROOM) | ||
| 795 | { | ||
| 796 | abuf = NULL; | ||
| 797 | buf = sbuf; | ||
| 798 | bsize = sizeof sbuf; | ||
| 799 | } | ||
| 800 | else | ||
| 801 | { | ||
| 802 | buf = abuf = xpalloc (NULL, &bsize, EXTRA_ROOM, STRING_BYTES_BOUND, 1); | ||
| 803 | record_unwind_protect_ptr (xfree, abuf); | ||
| 804 | } | ||
| 805 | bufp = buf; | ||
| 806 | |||
| 807 | strp = SDATA (str); | ||
| 808 | while (strp < SDATA (str) + strbytes) | ||
| 809 | { | ||
| 810 | unsigned char *close_bracket; | ||
| 811 | |||
| 812 | if (strp[0] == '\\' && strp[1] == '=' | ||
| 813 | && strp + 2 < SDATA (str) + strbytes) | ||
| 814 | { | ||
| 815 | /* \= quotes the next character; | ||
| 816 | thus, to put in \[ without its special meaning, use \=\[. */ | ||
| 817 | changed = nonquotes_changed = true; | ||
| 818 | strp += 2; | ||
| 819 | /* Fall through to copy one char. */ | ||
| 820 | } | ||
| 821 | else if (strp[0] == '\\' && strp[1] == '[' | ||
| 822 | && (close_bracket | ||
| 823 | = memchr (strp + 2, ']', | ||
| 824 | SDATA (str) + strbytes - (strp + 2)))) | ||
| 825 | { | ||
| 826 | bool follow_remap = 1; | ||
| 827 | |||
| 828 | start = strp + 2; | ||
| 829 | length_byte = close_bracket - start; | ||
| 830 | idx = close_bracket + 1 - SDATA (str); | ||
| 831 | |||
| 832 | name = Fintern (make_string ((char *) start, length_byte), Qnil); | ||
| 833 | |||
| 834 | do_remap: | ||
| 835 | tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil); | ||
| 836 | |||
| 837 | if (VECTORP (tem) && ASIZE (tem) > 1 | ||
| 838 | && EQ (AREF (tem, 0), Qremap) && SYMBOLP (AREF (tem, 1)) | ||
| 839 | && follow_remap) | ||
| 840 | { | ||
| 841 | name = AREF (tem, 1); | ||
| 842 | follow_remap = 0; | ||
| 843 | goto do_remap; | ||
| 844 | } | ||
| 845 | |||
| 846 | /* Fwhere_is_internal can GC, so take relocation of string | ||
| 847 | contents into account. */ | ||
| 848 | strp = SDATA (str) + idx; | ||
| 849 | start = strp - length_byte - 1; | ||
| 850 | |||
| 851 | if (NILP (tem)) /* but not on any keys */ | ||
| 852 | { | ||
| 853 | memcpy (bufp, "M-x ", 4); | ||
| 854 | bufp += 4; | ||
| 855 | nchars += 4; | ||
| 856 | length = multibyte_chars_in_text (start, length_byte); | ||
| 857 | goto subst; | ||
| 858 | } | ||
| 859 | else | ||
| 860 | { /* function is on a key */ | ||
| 861 | tem = Fkey_description (tem, Qnil); | ||
| 862 | goto subst_string; | ||
| 863 | } | ||
| 864 | } | ||
| 865 | /* \{foo} is replaced with a summary of the keymap (symbol-value foo). | ||
| 866 | \<foo> just sets the keymap used for \[cmd]. */ | ||
| 867 | else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<') | ||
| 868 | && (close_bracket | ||
| 869 | = memchr (strp + 2, strp[1] == '{' ? '}' : '>', | ||
| 870 | SDATA (str) + strbytes - (strp + 2)))) | ||
| 871 | { | ||
| 872 | { | ||
| 873 | bool generate_summary = strp[1] == '{'; | ||
| 874 | /* This is for computing the SHADOWS arg for describe_map_tree. */ | ||
| 875 | Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil); | ||
| 876 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 877 | |||
| 878 | start = strp + 2; | ||
| 879 | length_byte = close_bracket - start; | ||
| 880 | idx = close_bracket + 1 - SDATA (str); | ||
| 881 | |||
| 882 | /* Get the value of the keymap in TEM, or nil if undefined. | ||
| 883 | Do this while still in the user's current buffer | ||
| 884 | in case it is a local variable. */ | ||
| 885 | name = Fintern (make_string ((char *) start, length_byte), Qnil); | ||
| 886 | tem = Fboundp (name); | ||
| 887 | if (! NILP (tem)) | ||
| 888 | { | ||
| 889 | tem = Fsymbol_value (name); | ||
| 890 | if (! NILP (tem)) | ||
| 891 | tem = get_keymap (tem, 0, 1); | ||
| 892 | } | ||
| 893 | |||
| 894 | /* Now switch to a temp buffer. */ | ||
| 895 | struct buffer *oldbuf = current_buffer; | ||
| 896 | set_buffer_internal (XBUFFER (Vprin1_to_string_buffer)); | ||
| 897 | /* This is for an unusual case where some after-change | ||
| 898 | function uses 'format' or 'prin1' or something else that | ||
| 899 | will thrash Vprin1_to_string_buffer we are using. */ | ||
| 900 | specbind (Qinhibit_modification_hooks, Qt); | ||
| 901 | |||
| 902 | if (NILP (tem)) | ||
| 903 | { | ||
| 904 | name = Fsymbol_name (name); | ||
| 905 | AUTO_STRING (msg_prefix, "\nUses keymap `"); | ||
| 906 | insert1 (Fsubstitute_command_keys_old (msg_prefix)); | ||
| 907 | insert_from_string (name, 0, 0, | ||
| 908 | SCHARS (name), | ||
| 909 | SBYTES (name), 1); | ||
| 910 | AUTO_STRING (msg_suffix, "', which is not currently defined.\n"); | ||
| 911 | insert1 (Fsubstitute_command_keys_old (msg_suffix)); | ||
| 912 | if (!generate_summary) | ||
| 913 | keymap = Qnil; | ||
| 914 | } | ||
| 915 | else if (!generate_summary) | ||
| 916 | keymap = tem; | ||
| 917 | else | ||
| 918 | { | ||
| 919 | /* Get the list of active keymaps that precede this one. | ||
| 920 | If this one's not active, get nil. */ | ||
| 921 | Lisp_Object earlier_maps | ||
| 922 | = Fcdr (Fmemq (tem, Freverse (active_maps))); | ||
| 923 | describe_map_tree (tem, 1, Fnreverse (earlier_maps), | ||
| 924 | Qnil, 0, 1, 0, 0, 1); | ||
| 925 | } | ||
| 926 | tem = Fbuffer_string (); | ||
| 927 | Ferase_buffer (); | ||
| 928 | set_buffer_internal (oldbuf); | ||
| 929 | unbind_to (count, Qnil); | ||
| 930 | } | ||
| 931 | |||
| 932 | subst_string: | ||
| 933 | /* Convert non-ASCII unibyte data to properly-encoded multibyte, | ||
| 934 | for the same reason STRING was converted to STR. */ | ||
| 935 | tem = Fstring_make_multibyte (tem); | ||
| 936 | start = SDATA (tem); | ||
| 937 | length = SCHARS (tem); | ||
| 938 | length_byte = SBYTES (tem); | ||
| 939 | subst: | ||
| 940 | nonquotes_changed = true; | ||
| 941 | subst_quote: | ||
| 942 | changed = true; | ||
| 943 | { | ||
| 944 | ptrdiff_t offset = bufp - buf; | ||
| 945 | ptrdiff_t avail = bsize - offset; | ||
| 946 | ptrdiff_t need = strbytes - idx; | ||
| 947 | if (INT_ADD_WRAPV (need, length_byte + EXTRA_ROOM, &need)) | ||
| 948 | string_overflow (); | ||
| 949 | if (avail < need) | ||
| 950 | { | ||
| 951 | abuf = xpalloc (abuf, &bsize, need - avail, | ||
| 952 | STRING_BYTES_BOUND, 1); | ||
| 953 | if (buf == sbuf) | ||
| 954 | { | ||
| 955 | record_unwind_protect_ptr (xfree, abuf); | ||
| 956 | memcpy (abuf, sbuf, offset); | ||
| 957 | } | ||
| 958 | else | ||
| 959 | set_unwind_protect_ptr (count, xfree, abuf); | ||
| 960 | buf = abuf; | ||
| 961 | bufp = buf + offset; | ||
| 962 | } | ||
| 963 | memcpy (bufp, start, length_byte); | ||
| 964 | bufp += length_byte; | ||
| 965 | nchars += length; | ||
| 966 | |||
| 967 | /* Some of the previous code can GC, so take relocation of | ||
| 968 | string contents into account. */ | ||
| 969 | strp = SDATA (str) + idx; | ||
| 970 | |||
| 971 | continue; | ||
| 972 | } | ||
| 973 | } | ||
| 974 | else if ((strp[0] == '`' || strp[0] == '\'') | ||
| 975 | && quoting_style == CURVE_QUOTING_STYLE) | ||
| 976 | { | ||
| 977 | start = (unsigned char const *) (strp[0] == '`' ? uLSQM : uRSQM); | ||
| 978 | length = 1; | ||
| 979 | length_byte = sizeof uLSQM - 1; | ||
| 980 | idx = strp - SDATA (str) + 1; | ||
| 981 | goto subst_quote; | ||
| 982 | } | ||
| 983 | else if (strp[0] == '`' && quoting_style == STRAIGHT_QUOTING_STYLE) | ||
| 984 | { | ||
| 985 | *bufp++ = '\''; | ||
| 986 | strp++; | ||
| 987 | nchars++; | ||
| 988 | changed = true; | ||
| 989 | continue; | ||
| 990 | } | ||
| 991 | |||
| 992 | /* Copy one char. */ | ||
| 993 | do | ||
| 994 | *bufp++ = *strp++; | ||
| 995 | while (! CHAR_HEAD_P (*strp)); | ||
| 996 | nchars++; | ||
| 997 | } | ||
| 998 | |||
| 999 | if (changed) /* don't bother if nothing substituted */ | ||
| 1000 | { | ||
| 1001 | tem = make_string_from_bytes (buf, nchars, bufp - buf); | ||
| 1002 | if (!nonquotes_changed) | ||
| 1003 | { | ||
| 1004 | /* Nothing has changed other than quoting, so copy the string’s | ||
| 1005 | text properties. FIXME: Text properties should survive other | ||
| 1006 | changes too; see bug#17052. */ | ||
| 1007 | INTERVAL interval_copy = copy_intervals (string_intervals (string), | ||
| 1008 | 0, SCHARS (string)); | ||
| 1009 | if (interval_copy) | ||
| 1010 | { | ||
| 1011 | set_interval_object (interval_copy, tem); | ||
| 1012 | set_string_intervals (tem, interval_copy); | ||
| 1013 | } | ||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | else | ||
| 1017 | tem = string; | ||
| 1018 | return unbind_to (count, tem); | ||
| 1019 | } | ||
| 1020 | 718 | ||
| 1021 | void | 719 | void |
| 1022 | syms_of_doc (void) | 720 | syms_of_doc (void) |
| @@ -1058,5 +756,4 @@ otherwise. */); | |||
| 1058 | defsubr (&Sdocumentation_property); | 756 | defsubr (&Sdocumentation_property); |
| 1059 | defsubr (&Ssnarf_documentation); | 757 | defsubr (&Ssnarf_documentation); |
| 1060 | defsubr (&Sget_quoting_style); | 758 | defsubr (&Sget_quoting_style); |
| 1061 | defsubr (&Ssubstitute_command_keys_old); | ||
| 1062 | } | 759 | } |
diff --git a/src/keymap.c b/src/keymap.c index 1eded130b5d..46fa586c753 100644 --- a/src/keymap.c +++ b/src/keymap.c | |||
| @@ -91,9 +91,6 @@ static Lisp_Object store_in_keymap (Lisp_Object, Lisp_Object, Lisp_Object); | |||
| 91 | static Lisp_Object define_as_prefix (Lisp_Object, Lisp_Object); | 91 | static Lisp_Object define_as_prefix (Lisp_Object, Lisp_Object); |
| 92 | static void describe_command (Lisp_Object, Lisp_Object); | 92 | static void describe_command (Lisp_Object, Lisp_Object); |
| 93 | static void describe_translation (Lisp_Object, Lisp_Object); | 93 | static void describe_translation (Lisp_Object, Lisp_Object); |
| 94 | static void describe_map (Lisp_Object, Lisp_Object, | ||
| 95 | void (*) (Lisp_Object, Lisp_Object), | ||
| 96 | bool, Lisp_Object, Lisp_Object *, bool, bool); | ||
| 97 | static void describe_vector (Lisp_Object, Lisp_Object, Lisp_Object, | 94 | static void describe_vector (Lisp_Object, Lisp_Object, Lisp_Object, |
| 98 | void (*) (Lisp_Object, Lisp_Object), bool, | 95 | void (*) (Lisp_Object, Lisp_Object), bool, |
| 99 | Lisp_Object, Lisp_Object, bool, bool); | 96 | Lisp_Object, Lisp_Object, bool, bool); |
| @@ -2946,119 +2943,6 @@ You type Translation\n\ | |||
| 2946 | return Qnil; | 2943 | return Qnil; |
| 2947 | } | 2944 | } |
| 2948 | 2945 | ||
| 2949 | /* Insert a description of the key bindings in STARTMAP, | ||
| 2950 | followed by those of all maps reachable through STARTMAP. | ||
| 2951 | If PARTIAL, omit certain "uninteresting" commands | ||
| 2952 | (such as `undefined'). | ||
| 2953 | If SHADOW is non-nil, it is a list of maps; | ||
| 2954 | don't mention keys which would be shadowed by any of them. | ||
| 2955 | PREFIX, if non-nil, says mention only keys that start with PREFIX. | ||
| 2956 | TITLE, if not 0, is a string to insert at the beginning. | ||
| 2957 | TITLE should not end with a colon or a newline; we supply that. | ||
| 2958 | If NOMENU, then omit menu-bar commands. | ||
| 2959 | |||
| 2960 | If TRANSL, the definitions are actually key translations | ||
| 2961 | so print strings and vectors differently. | ||
| 2962 | |||
| 2963 | If ALWAYS_TITLE, print the title even if there are no maps | ||
| 2964 | to look through. | ||
| 2965 | |||
| 2966 | If MENTION_SHADOW, then when something is shadowed by SHADOW, | ||
| 2967 | don't omit it; instead, mention it but say it is shadowed. | ||
| 2968 | |||
| 2969 | Any inserted text ends in two newlines (used by `help-make-xrefs'). */ | ||
| 2970 | |||
| 2971 | void | ||
| 2972 | describe_map_tree (Lisp_Object startmap, bool partial, Lisp_Object shadow, | ||
| 2973 | Lisp_Object prefix, const char *title, bool nomenu, | ||
| 2974 | bool transl, bool always_title, bool mention_shadow) | ||
| 2975 | { | ||
| 2976 | Lisp_Object maps, orig_maps, seen, sub_shadows; | ||
| 2977 | bool something = 0; | ||
| 2978 | const char *key_heading | ||
| 2979 | = "\ | ||
| 2980 | key binding\n\ | ||
| 2981 | --- -------\n"; | ||
| 2982 | |||
| 2983 | orig_maps = maps = Faccessible_keymaps (startmap, prefix); | ||
| 2984 | seen = Qnil; | ||
| 2985 | sub_shadows = Qnil; | ||
| 2986 | |||
| 2987 | if (nomenu) | ||
| 2988 | { | ||
| 2989 | Lisp_Object list; | ||
| 2990 | |||
| 2991 | /* Delete from MAPS each element that is for the menu bar. */ | ||
| 2992 | for (list = maps; CONSP (list); list = XCDR (list)) | ||
| 2993 | { | ||
| 2994 | Lisp_Object elt, elt_prefix, tem; | ||
| 2995 | |||
| 2996 | elt = XCAR (list); | ||
| 2997 | elt_prefix = Fcar (elt); | ||
| 2998 | if (ASIZE (elt_prefix) >= 1) | ||
| 2999 | { | ||
| 3000 | tem = Faref (elt_prefix, make_fixnum (0)); | ||
| 3001 | if (EQ (tem, Qmenu_bar)) | ||
| 3002 | maps = Fdelq (elt, maps); | ||
| 3003 | } | ||
| 3004 | } | ||
| 3005 | } | ||
| 3006 | |||
| 3007 | if (!NILP (maps) || always_title) | ||
| 3008 | { | ||
| 3009 | if (title) | ||
| 3010 | { | ||
| 3011 | insert_string (title); | ||
| 3012 | if (!NILP (prefix)) | ||
| 3013 | { | ||
| 3014 | insert_string (" Starting With "); | ||
| 3015 | insert1 (Fkey_description (prefix, Qnil)); | ||
| 3016 | } | ||
| 3017 | insert_string (":\n"); | ||
| 3018 | } | ||
| 3019 | insert_string (key_heading); | ||
| 3020 | something = 1; | ||
| 3021 | } | ||
| 3022 | |||
| 3023 | for (; CONSP (maps); maps = XCDR (maps)) | ||
| 3024 | { | ||
| 3025 | register Lisp_Object elt, elt_prefix, tail; | ||
| 3026 | |||
| 3027 | elt = XCAR (maps); | ||
| 3028 | elt_prefix = Fcar (elt); | ||
| 3029 | |||
| 3030 | sub_shadows = Flookup_key (shadow, elt_prefix, Qt); | ||
| 3031 | if (FIXNATP (sub_shadows)) | ||
| 3032 | sub_shadows = Qnil; | ||
| 3033 | else if (!KEYMAPP (sub_shadows) | ||
| 3034 | && !NILP (sub_shadows) | ||
| 3035 | && !(CONSP (sub_shadows) | ||
| 3036 | && KEYMAPP (XCAR (sub_shadows)))) | ||
| 3037 | /* If elt_prefix is bound to something that's not a keymap, | ||
| 3038 | it completely shadows this map, so don't | ||
| 3039 | describe this map at all. */ | ||
| 3040 | goto skip; | ||
| 3041 | |||
| 3042 | /* Maps we have already listed in this loop shadow this map. */ | ||
| 3043 | for (tail = orig_maps; !EQ (tail, maps); tail = XCDR (tail)) | ||
| 3044 | { | ||
| 3045 | Lisp_Object tem; | ||
| 3046 | tem = Fequal (Fcar (XCAR (tail)), elt_prefix); | ||
| 3047 | if (!NILP (tem)) | ||
| 3048 | sub_shadows = Fcons (XCDR (XCAR (tail)), sub_shadows); | ||
| 3049 | } | ||
| 3050 | |||
| 3051 | describe_map (Fcdr (elt), elt_prefix, | ||
| 3052 | transl ? describe_translation : describe_command, | ||
| 3053 | partial, sub_shadows, &seen, nomenu, mention_shadow); | ||
| 3054 | |||
| 3055 | skip: ; | ||
| 3056 | } | ||
| 3057 | |||
| 3058 | if (something) | ||
| 3059 | insert_string ("\n"); | ||
| 3060 | } | ||
| 3061 | |||
| 3062 | static int previous_description_column; | 2946 | static int previous_description_column; |
| 3063 | 2947 | ||
| 3064 | static void | 2948 | static void |
| @@ -3121,224 +3005,6 @@ describe_translation (Lisp_Object definition, Lisp_Object args) | |||
| 3121 | insert_string ("??\n"); | 3005 | insert_string ("??\n"); |
| 3122 | } | 3006 | } |
| 3123 | 3007 | ||
| 3124 | /* describe_map puts all the usable elements of a sparse keymap | ||
| 3125 | into an array of `struct describe_map_elt', | ||
| 3126 | then sorts them by the events. */ | ||
| 3127 | |||
| 3128 | struct describe_map_elt | ||
| 3129 | { | ||
| 3130 | Lisp_Object event; | ||
| 3131 | Lisp_Object definition; | ||
| 3132 | bool shadowed; | ||
| 3133 | }; | ||
| 3134 | |||
| 3135 | /* qsort comparison function for sorting `struct describe_map_elt' by | ||
| 3136 | the event field. */ | ||
| 3137 | |||
| 3138 | static int | ||
| 3139 | describe_map_compare (const void *aa, const void *bb) | ||
| 3140 | { | ||
| 3141 | const struct describe_map_elt *a = aa, *b = bb; | ||
| 3142 | if (FIXNUMP (a->event) && FIXNUMP (b->event)) | ||
| 3143 | return ((XFIXNUM (a->event) > XFIXNUM (b->event)) | ||
| 3144 | - (XFIXNUM (a->event) < XFIXNUM (b->event))); | ||
| 3145 | if (!FIXNUMP (a->event) && FIXNUMP (b->event)) | ||
| 3146 | return 1; | ||
| 3147 | if (FIXNUMP (a->event) && !FIXNUMP (b->event)) | ||
| 3148 | return -1; | ||
| 3149 | if (SYMBOLP (a->event) && SYMBOLP (b->event)) | ||
| 3150 | /* Sort the keystroke names in the "natural" way, with (for | ||
| 3151 | instance) "<f2>" coming between "<f1>" and "<f11>". */ | ||
| 3152 | return string_version_cmp (SYMBOL_NAME (a->event), SYMBOL_NAME (b->event)); | ||
| 3153 | return 0; | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | /* Describe the contents of map MAP, assuming that this map itself is | ||
| 3157 | reached by the sequence of prefix keys PREFIX (a string or vector). | ||
| 3158 | PARTIAL, SHADOW, NOMENU are as in `describe_map_tree' above. */ | ||
| 3159 | |||
| 3160 | static void | ||
| 3161 | describe_map (Lisp_Object map, Lisp_Object prefix, | ||
| 3162 | void (*elt_describer) (Lisp_Object, Lisp_Object), | ||
| 3163 | bool partial, Lisp_Object shadow, | ||
| 3164 | Lisp_Object *seen, bool nomenu, bool mention_shadow) | ||
| 3165 | { | ||
| 3166 | Lisp_Object tail, definition, event; | ||
| 3167 | Lisp_Object tem; | ||
| 3168 | Lisp_Object suppress; | ||
| 3169 | Lisp_Object kludge; | ||
| 3170 | bool first = 1; | ||
| 3171 | |||
| 3172 | /* These accumulate the values from sparse keymap bindings, | ||
| 3173 | so we can sort them and handle them in order. */ | ||
| 3174 | ptrdiff_t length_needed = 0; | ||
| 3175 | struct describe_map_elt *vect; | ||
| 3176 | ptrdiff_t slots_used = 0; | ||
| 3177 | ptrdiff_t i; | ||
| 3178 | |||
| 3179 | suppress = Qnil; | ||
| 3180 | |||
| 3181 | if (partial) | ||
| 3182 | suppress = intern ("suppress-keymap"); | ||
| 3183 | |||
| 3184 | /* This vector gets used to present single keys to Flookup_key. Since | ||
| 3185 | that is done once per keymap element, we don't want to cons up a | ||
| 3186 | fresh vector every time. */ | ||
| 3187 | kludge = make_nil_vector (1); | ||
| 3188 | definition = Qnil; | ||
| 3189 | |||
| 3190 | map = call1 (Qkeymap_canonicalize, map); | ||
| 3191 | |||
| 3192 | for (tail = map; CONSP (tail); tail = XCDR (tail)) | ||
| 3193 | length_needed++; | ||
| 3194 | |||
| 3195 | USE_SAFE_ALLOCA; | ||
| 3196 | SAFE_NALLOCA (vect, 1, length_needed); | ||
| 3197 | |||
| 3198 | for (tail = map; CONSP (tail); tail = XCDR (tail)) | ||
| 3199 | { | ||
| 3200 | maybe_quit (); | ||
| 3201 | |||
| 3202 | if (VECTORP (XCAR (tail)) | ||
| 3203 | || CHAR_TABLE_P (XCAR (tail))) | ||
| 3204 | describe_vector (XCAR (tail), | ||
| 3205 | prefix, Qnil, elt_describer, partial, shadow, map, | ||
| 3206 | 1, mention_shadow); | ||
| 3207 | else if (CONSP (XCAR (tail))) | ||
| 3208 | { | ||
| 3209 | bool this_shadowed = 0; | ||
| 3210 | |||
| 3211 | event = XCAR (XCAR (tail)); | ||
| 3212 | |||
| 3213 | /* Ignore bindings whose "prefix" are not really valid events. | ||
| 3214 | (We get these in the frames and buffers menu.) */ | ||
| 3215 | if (!(SYMBOLP (event) || FIXNUMP (event))) | ||
| 3216 | continue; | ||
| 3217 | |||
| 3218 | if (nomenu && EQ (event, Qmenu_bar)) | ||
| 3219 | continue; | ||
| 3220 | |||
| 3221 | definition = get_keyelt (XCDR (XCAR (tail)), 0); | ||
| 3222 | |||
| 3223 | /* Don't show undefined commands or suppressed commands. */ | ||
| 3224 | if (NILP (definition)) continue; | ||
| 3225 | if (SYMBOLP (definition) && partial) | ||
| 3226 | { | ||
| 3227 | tem = Fget (definition, suppress); | ||
| 3228 | if (!NILP (tem)) | ||
| 3229 | continue; | ||
| 3230 | } | ||
| 3231 | |||
| 3232 | /* Don't show a command that isn't really visible | ||
| 3233 | because a local definition of the same key shadows it. */ | ||
| 3234 | |||
| 3235 | ASET (kludge, 0, event); | ||
| 3236 | if (!NILP (shadow)) | ||
| 3237 | { | ||
| 3238 | tem = shadow_lookup (shadow, kludge, Qt, 0); | ||
| 3239 | if (!NILP (tem)) | ||
| 3240 | { | ||
| 3241 | /* If both bindings are keymaps, this key is a prefix key, | ||
| 3242 | so don't say it is shadowed. */ | ||
| 3243 | if (KEYMAPP (definition) && KEYMAPP (tem)) | ||
| 3244 | ; | ||
| 3245 | /* Avoid generating duplicate entries if the | ||
| 3246 | shadowed binding has the same definition. */ | ||
| 3247 | else if (mention_shadow && !EQ (tem, definition)) | ||
| 3248 | this_shadowed = 1; | ||
| 3249 | else | ||
| 3250 | continue; | ||
| 3251 | } | ||
| 3252 | } | ||
| 3253 | |||
| 3254 | tem = Flookup_key (map, kludge, Qt); | ||
| 3255 | if (!EQ (tem, definition)) continue; | ||
| 3256 | |||
| 3257 | vect[slots_used].event = event; | ||
| 3258 | vect[slots_used].definition = definition; | ||
| 3259 | vect[slots_used].shadowed = this_shadowed; | ||
| 3260 | slots_used++; | ||
| 3261 | } | ||
| 3262 | else if (EQ (XCAR (tail), Qkeymap)) | ||
| 3263 | { | ||
| 3264 | /* The same keymap might be in the structure twice, if we're | ||
| 3265 | using an inherited keymap. So skip anything we've already | ||
| 3266 | encountered. */ | ||
| 3267 | tem = Fassq (tail, *seen); | ||
| 3268 | if (CONSP (tem) && !NILP (Fequal (XCAR (tem), prefix))) | ||
| 3269 | break; | ||
| 3270 | *seen = Fcons (Fcons (tail, prefix), *seen); | ||
| 3271 | } | ||
| 3272 | } | ||
| 3273 | |||
| 3274 | /* If we found some sparse map events, sort them. */ | ||
| 3275 | |||
| 3276 | qsort (vect, slots_used, sizeof (struct describe_map_elt), | ||
| 3277 | describe_map_compare); | ||
| 3278 | |||
| 3279 | /* Now output them in sorted order. */ | ||
| 3280 | |||
| 3281 | for (i = 0; i < slots_used; i++) | ||
| 3282 | { | ||
| 3283 | Lisp_Object start, end; | ||
| 3284 | |||
| 3285 | if (first) | ||
| 3286 | { | ||
| 3287 | previous_description_column = 0; | ||
| 3288 | insert ("\n", 1); | ||
| 3289 | first = 0; | ||
| 3290 | } | ||
| 3291 | |||
| 3292 | ASET (kludge, 0, vect[i].event); | ||
| 3293 | start = vect[i].event; | ||
| 3294 | end = start; | ||
| 3295 | |||
| 3296 | definition = vect[i].definition; | ||
| 3297 | |||
| 3298 | /* Find consecutive chars that are identically defined. */ | ||
| 3299 | if (FIXNUMP (vect[i].event)) | ||
| 3300 | { | ||
| 3301 | while (i + 1 < slots_used | ||
| 3302 | && EQ (vect[i+1].event, make_fixnum (XFIXNUM (vect[i].event) + 1)) | ||
| 3303 | && !NILP (Fequal (vect[i + 1].definition, definition)) | ||
| 3304 | && vect[i].shadowed == vect[i + 1].shadowed) | ||
| 3305 | i++; | ||
| 3306 | end = vect[i].event; | ||
| 3307 | } | ||
| 3308 | |||
| 3309 | /* Now START .. END is the range to describe next. */ | ||
| 3310 | |||
| 3311 | /* Insert the string to describe the event START. */ | ||
| 3312 | insert1 (Fkey_description (kludge, prefix)); | ||
| 3313 | |||
| 3314 | if (!EQ (start, end)) | ||
| 3315 | { | ||
| 3316 | insert (" .. ", 4); | ||
| 3317 | |||
| 3318 | ASET (kludge, 0, end); | ||
| 3319 | /* Insert the string to describe the character END. */ | ||
| 3320 | insert1 (Fkey_description (kludge, prefix)); | ||
| 3321 | } | ||
| 3322 | |||
| 3323 | /* Print a description of the definition of this character. | ||
| 3324 | elt_describer will take care of spacing out far enough | ||
| 3325 | for alignment purposes. */ | ||
| 3326 | (*elt_describer) (vect[i].definition, Qnil); | ||
| 3327 | |||
| 3328 | if (vect[i].shadowed) | ||
| 3329 | { | ||
| 3330 | ptrdiff_t pt = max (PT - 1, BEG); | ||
| 3331 | |||
| 3332 | SET_PT (pt); | ||
| 3333 | insert_string ("\n (this binding is currently shadowed)"); | ||
| 3334 | pt = min (PT + 1, Z); | ||
| 3335 | SET_PT (pt); | ||
| 3336 | } | ||
| 3337 | } | ||
| 3338 | |||
| 3339 | SAFE_FREE (); | ||
| 3340 | } | ||
| 3341 | |||
| 3342 | static void | 3008 | static void |
| 3343 | describe_vector_princ (Lisp_Object elt, Lisp_Object fun) | 3009 | describe_vector_princ (Lisp_Object elt, Lisp_Object fun) |
| 3344 | { | 3010 | { |
diff --git a/src/keymap.h b/src/keymap.h index 3ef48fb748e..2f7df2bd955 100644 --- a/src/keymap.h +++ b/src/keymap.h | |||
| @@ -36,8 +36,6 @@ extern Lisp_Object current_global_map; | |||
| 36 | extern char *push_key_description (EMACS_INT, char *); | 36 | extern char *push_key_description (EMACS_INT, char *); |
| 37 | extern Lisp_Object access_keymap (Lisp_Object, Lisp_Object, bool, bool, bool); | 37 | extern Lisp_Object access_keymap (Lisp_Object, Lisp_Object, bool, bool, bool); |
| 38 | extern Lisp_Object get_keymap (Lisp_Object, bool, bool); | 38 | extern Lisp_Object get_keymap (Lisp_Object, bool, bool); |
| 39 | extern void describe_map_tree (Lisp_Object, bool, Lisp_Object, Lisp_Object, | ||
| 40 | const char *, bool, bool, bool, bool); | ||
| 41 | extern ptrdiff_t current_minor_maps (Lisp_Object **, Lisp_Object **); | 39 | extern ptrdiff_t current_minor_maps (Lisp_Object **, Lisp_Object **); |
| 42 | extern void initial_define_key (Lisp_Object, int, const char *); | 40 | extern void initial_define_key (Lisp_Object, int, const char *); |
| 43 | extern void initial_define_lispy_key (Lisp_Object, const char *, const char *); | 41 | extern void initial_define_lispy_key (Lisp_Object, const char *, const char *); |
diff --git a/test/lisp/help-tests.el b/test/lisp/help-tests.el index aff5d1853a6..079b1114a81 100644 --- a/test/lisp/help-tests.el +++ b/test/lisp/help-tests.el | |||
| @@ -58,23 +58,15 @@ | |||
| 58 | ;;; substitute-command-keys | 58 | ;;; substitute-command-keys |
| 59 | 59 | ||
| 60 | (defmacro with-substitute-command-keys-test (&rest body) | 60 | (defmacro with-substitute-command-keys-test (&rest body) |
| 61 | `(cl-flet* ((should-be-same-as-c-version | 61 | `(cl-flet* ((test |
| 62 | ;; TODO: Remove this when old C function is removed. | ||
| 63 | (lambda (orig) | ||
| 64 | (should (equal-including-properties | ||
| 65 | (substitute-command-keys orig) | ||
| 66 | (substitute-command-keys-old orig))))) | ||
| 67 | (test | ||
| 68 | (lambda (orig result) | 62 | (lambda (orig result) |
| 69 | (should (equal-including-properties | 63 | (should (equal-including-properties |
| 70 | (substitute-command-keys orig) | 64 | (substitute-command-keys orig) |
| 71 | result)) | 65 | result)))) |
| 72 | (should-be-same-as-c-version orig))) | ||
| 73 | (test-re | 66 | (test-re |
| 74 | (lambda (orig regexp) | 67 | (lambda (orig regexp) |
| 75 | (should (string-match (concat "^" regexp "$") | 68 | (should (string-match (concat "^" regexp "$") |
| 76 | (substitute-command-keys orig))) | 69 | (substitute-command-keys orig)))))) |
| 77 | (should-be-same-as-c-version orig)))) | ||
| 78 | ,@body)) | 70 | ,@body)) |
| 79 | 71 | ||
| 80 | (ert-deftest help-tests-substitute-command-keys/no-change () | 72 | (ert-deftest help-tests-substitute-command-keys/no-change () |
| @@ -369,29 +361,6 @@ C-b undefined | |||
| 369 | 361 | ||
| 370 | "))))) | 362 | "))))) |
| 371 | 363 | ||
| 372 | ;; TODO: This is a temporary test that should be removed together with | ||
| 373 | ;; substitute-command-keys-old. | ||
| 374 | (ert-deftest help-tests-substitute-command-keys/compare () | ||
| 375 | (with-substitute-command-keys-test | ||
| 376 | (with-temp-buffer | ||
| 377 | (Info-mode) | ||
| 378 | (outline-minor-mode) | ||
| 379 | (test-re "\\{Info-mode-map}" ".*"))) | ||
| 380 | (with-substitute-command-keys-test | ||
| 381 | (with-temp-buffer | ||
| 382 | (c-mode) | ||
| 383 | (outline-minor-mode) | ||
| 384 | (test-re "\\{c-mode-map}" ".*")))) | ||
| 385 | |||
| 386 | (ert-deftest help-tests-substitute-command-keys/compare-all () | ||
| 387 | (let (keymaps) | ||
| 388 | (mapatoms (lambda (var) | ||
| 389 | (when (keymapp var) | ||
| 390 | (push var keymaps)))) | ||
| 391 | (dolist (keymap keymaps) | ||
| 392 | (with-substitute-command-keys-test | ||
| 393 | (test-re (concat "\\{" (symbol-name keymap) "}") ".*"))))) | ||
| 394 | |||
| 395 | (provide 'help-tests) | 364 | (provide 'help-tests) |
| 396 | 365 | ||
| 397 | ;;; help-tests.el ends here | 366 | ;;; help-tests.el ends here |