unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
@ 2021-09-23  8:39 Shuguang Sun via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-09-23 17:15 ` Juri Linkov
                   ` (2 more replies)
  0 siblings, 3 replies; 63+ messages in thread
From: Shuguang Sun via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-09-23  8:39 UTC (permalink / raw)
  To: 50752

[-- Attachment #1: Type: text/plain, Size: 3278 bytes --]

Hi,


I'm using the package pdf-tools to view PDF files. However the popu-menu does't work in recent emacs snapshot. I find it is due the automaticly lowering the menu-bar by easy-menu-deine. Is it a feature or bug?


Of pdf-tools (from melpa or from http://github.com/vedang/pdf-tools/), in the pdf-misc.el it defines
```
(easy-menu-define nil pdf-misc-menu-bar-minor-mode-map
  "Menu for PDF Tools."
  `("PDF Tools"
    ["Go Backward" pdf-history-backward
     :visible (bound-and-true-p pdf-history-minor-mode)
     :active (and (bound-and-true-p pdf-history-minor-mode)
                  (not (pdf-history-end-of-history-p)))]
```
And the responding function
```
(defun pdf-misc-popup-context-menu (event)
  "Popup a context menu at position determined by EVENT."
  (interactive "@e")
  (popup-menu
   (cons 'keymap
         (cddr (lookup-key pdf-misc-menu-bar-minor-mode-map
                           [menu-bar PDF\ Tools])))))
```

However, it can't find the key of "PDF\ Tools". Instead, I find in the `pdf-misc-menu-bar-minor-mode-map`, that,
```
(keymap
 (menu-bar keymap
           (pdf\ tools menu-item #1="PDF Tools"
                       (keymap #1#
                               (Go\ Backward menu-item "Go Backward" pdf-history-backward :enable
```

It becomes lower case (`pdf\ tools`).


If I change the case, the function works again:
```(defun pdf-misc-popup-context-menu (event)
  "Popup a context menu at position determined by EVENT."
  (interactive "@e")
  (popup-menu
   (cons 'keymap
         (cddr (lookup-key pdf-misc-menu-bar-minor-mode-map
                           [menu-bar pdf\ tools])))))
```


Best Regards,
Shuguang Sun





In GNU Emacs 28.0.50 (build 1, x86_64-w64-mingw32)
 of 2021-09-21 built on YJ190169-SSG
Repository revision: 5b962a7ad8d0acfe40a41ce139059b9c8e46f666
Repository branch: master
Windowing system distributor 'Microsoft Corp.', version 10.0.19043
System Description: Microsoft Windows 10 Pro (v10.0.2009.19043.1237)

Configured using:
 'configure --without-pop --with-native-image-api
 --with-native-compilation --without-compress-install
 '--program-transform-name=s/^ctags$/ctags.emacs/''

Configured features:
ACL DBUS GIF GMP GNUTLS HARFBUZZ JPEG JSON LCMS2 LIBXML2 MODULES
NATIVE_COMP NOTIFY W32NOTIFY PDUMPER PNG RSVG SOUND THREADS TIFF
TOOLKIT_SCROLL_BARS XPM ZLIB

[-- Attachment #2: Type: text/html, Size: 3664 bytes --]

^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-09-23  8:39 bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key Shuguang Sun via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-09-23 17:15 ` Juri Linkov
  2021-09-23 21:45 ` Lars Ingebrigtsen
  2021-09-23 22:28 ` Glenn Morris
  2 siblings, 0 replies; 63+ messages in thread
From: Juri Linkov @ 2021-09-23 17:15 UTC (permalink / raw)
  To: Shuguang Sun; +Cc: 50752

> However, it can't find the key of "PDF\ Tools". Instead, I find in the
> `pdf-misc-menu-bar-minor-mode-map`, that,
>
> It becomes lower case (`pdf\ tools`).

It seems this problem is caused by the recent commit
e5392d38ac27c4cf1674997ab38a453877e65109.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-09-23  8:39 bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key Shuguang Sun via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-09-23 17:15 ` Juri Linkov
@ 2021-09-23 21:45 ` Lars Ingebrigtsen
  2021-10-12 22:22   ` Stefan Kangas
  2021-09-23 22:28 ` Glenn Morris
  2 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-09-23 21:45 UTC (permalink / raw)
  To: Shuguang Sun; +Cc: 50752

"Shuguang Sun" <shuguang79@qq.com> writes:

> If I change the case, the function works again:
> ```(defun pdf-misc-popup-context-menu (event)
>   "Popup a context menu at position determined by EVENT."
>   (interactive "@e")
>   (popup-menu
>    (cons 'keymap
>          (cddr (lookup-key pdf-misc-menu-bar-minor-mode-map
>                            [menu-bar pdf\ tools])))))

Yes, the names have changed in Emacs 28, so external packages that alter
the menus like this have to be adjusted.  But I wonder whether we could
make `lookup-key' be case-insensitive in this case...

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-09-23  8:39 bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key Shuguang Sun via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-09-23 17:15 ` Juri Linkov
  2021-09-23 21:45 ` Lars Ingebrigtsen
@ 2021-09-23 22:28 ` Glenn Morris
  2 siblings, 0 replies; 63+ messages in thread
From: Glenn Morris @ 2021-09-23 22:28 UTC (permalink / raw)
  To: 50752; +Cc: Shuguang Sun


Previous discussion: https://lists.gnu.org/r/emacs-devel/2021-03/msg00031.html





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-09-23 21:45 ` Lars Ingebrigtsen
@ 2021-10-12 22:22   ` Stefan Kangas
  2021-10-13 11:28     ` Lars Ingebrigtsen
  2021-10-13 11:59     ` Eli Zaretskii
  0 siblings, 2 replies; 63+ messages in thread
From: Stefan Kangas @ 2021-10-12 22:22 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Shuguang Sun, 50752

[-- Attachment #1: Type: text/plain, Size: 1100 bytes --]

tags 50752 + patch
thanks

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Yes, the names have changed in Emacs 28, so external packages that alter
> the menus like this have to be adjusted.  But I wonder whether we could
> make `lookup-key' be case-insensitive in this case...

As Glenn points out, we discussed this here:
https://lists.gnu.org/r/emacs-devel/2021-03/msg00031.html

We also discussed it here:
https://lists.gnu.org/r/emacs-devel/2021-03/msg00014.html

I had an incomplete patch in the works, but I dropped the ball here.

Please find attached an updated and complete patch that should fix the
above issue.  In addition to the new tests, I have tested it locally,
and without the patch, I can reproduce the issue reported here by
Shuguang, i.e. I get this error:

    popup-menu: Empty menu

With the patch, the menu is correctly displayed, as is expected.  This
is tested with pdf-tools-20211004.514 installed from MELPA, which should
be equivalent to the latest version in the git repository at:

    http://github.com/vedang/pdf-tools

Review and additional testing is very welcome.

[-- Attachment #2: 0001-Be-more-allowing-when-looking-for-menu-bar-items.patch --]
[-- Type: text/x-diff, Size: 6222 bytes --]

From 0ee56b91506b445161bf2e839f4caa5ed78972bf Mon Sep 17 00:00:00 2001
From: Stefan Kangas <stefan@marxist.se>
Date: Wed, 13 Oct 2021 00:04:23 +0200
Subject: [PATCH] Be more allowing when looking for menu-bar items

* src/keymap.c (lookup_key_1): Factor out function from
Flookup_key.
(Flookup_key): Be case insensitive, and treat spaces as dashes,
when looking for Qmenu_bar items.  (Bug#50752)
* test/src/keymap-tests.el (keymap-lookup-key/mixed-case)
(subr-test-lookup-keymap/with-spaces): New tests.
---
 src/keymap.c             | 110 +++++++++++++++++++++++++++++++--------
 test/src/keymap-tests.el |  11 ++++
 2 files changed, 100 insertions(+), 21 deletions(-)

diff --git a/src/keymap.c b/src/keymap.c
index be45d2be1e..2fb5d8f41e 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1180,27 +1180,8 @@ DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1240,6 +1221,93 @@ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+
+  if (!NILP (found) && !NUMBERP (found))
+    goto end;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define'), or use " " instead of "-".  */
+  if (VECTORP (key) && EQ (AREF (key, 0), Qmenu_bar))
+    {
+      ptrdiff_t key_len = ASIZE (key);
+      Lisp_Object new_key = make_vector (key_len, Qnil);
+
+      /* First, let's try converting all symbols like "Foo-Bar-Baz" to
+	 "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+	{
+	  Lisp_Object lc_key = Fdowncase (Fsymbol_name (AREF (key, i)));
+	  ASET (new_key, i, Fintern (lc_key, Qnil));
+	}
+      found = lookup_key_1 (keymap, new_key, accept_default);
+
+      if (!NILP (found) && !NUMBERP (found))
+	goto end;
+
+      /* If we still don't have a match, let's convert any spaces in
+	 our lowercased string into dashes, e.g. "foo bar baz" to
+	 "foo-bar-baz". */
+      for (int i = 0; i < key_len; i++)
+	{
+	  Lisp_Object lc_key = Fdowncase (Fsymbol_name (AREF (key, i)));
+
+	  USE_SAFE_ALLOCA;
+	  ptrdiff_t size = SCHARS (lc_key), n;
+	  if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+	    n = PTRDIFF_MAX;
+	  unsigned char *dst = SAFE_ALLOCA (n);
+	  unsigned char *o = dst;
+	  ptrdiff_t j = 0, j_byte = 0, chars = 0;
+
+	  while (j < SCHARS (lc_key))
+	    {
+	      int ch = fetch_string_char_advance (lc_key, &j, &j_byte);
+	      if (ch == ' ')
+		*o = '-';
+	      else
+		*o = ch;
+	      chars++;
+
+	      int len;
+	      string_char_and_length (o, &len);
+	      o += len;
+	    }
+	  eassert (o <= dst + n);
+	  Lisp_Object
+	    new_it = make_multibyte_string ((char *) dst, chars, o - dst);
+	  ASET (new_key, i, Fintern (new_it, Qnil));
+	  SAFE_FREE ();
+	}
+      found = lookup_key_1 (keymap, new_key, accept_default);
+    }
+
+ end:
+  return found;
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..8f3dff2acb 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,17 @@ keymap-lookup-key/too-long
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo))))
+
+(ert-deftest subr-test-lookup-keymap/with-spaces ()
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31"
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-12 22:22   ` Stefan Kangas
@ 2021-10-13 11:28     ` Lars Ingebrigtsen
  2021-10-13 11:59     ` Eli Zaretskii
  1 sibling, 0 replies; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-13 11:28 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Shuguang Sun, 50752

Stefan Kangas <stefan@marxist.se> writes:

> Review and additional testing is very welcome.

Looks good to me.  I've tested it now in Emacs 28, and I don't see any
regressions.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-12 22:22   ` Stefan Kangas
  2021-10-13 11:28     ` Lars Ingebrigtsen
@ 2021-10-13 11:59     ` Eli Zaretskii
  2021-10-13 12:04       ` Lars Ingebrigtsen
                         ` (2 more replies)
  1 sibling, 3 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-13 11:59 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: shuguang79, larsi, 50752

> From: Stefan Kangas <stefan@marxist.se>
> Date: Tue, 12 Oct 2021 15:22:59 -0700
> Cc: Shuguang Sun <shuguang79@qq.com>, 50752@debbugs.gnu.org
> 
> +      for (int i = 0; i < key_len; i++)
> +	{
> +	  Lisp_Object lc_key = Fdowncase (Fsymbol_name (AREF (key, i)));
> +	  ASET (new_key, i, Fintern (lc_key, Qnil));
> +	}

Beware: downcase uses the current buffer's case-table.  Is that
something we want here, or could it be undesirable in some cases?

> +      found = lookup_key_1 (keymap, new_key, accept_default);
> +
> +      if (!NILP (found) && !NUMBERP (found))
> +	goto end;
> +
> +      /* If we still don't have a match, let's convert any spaces in
> +	 our lowercased string into dashes, e.g. "foo bar baz" to
> +	 "foo-bar-baz". */
> +      for (int i = 0; i < key_len; i++)
> +	{
> +	  Lisp_Object lc_key = Fdowncase (Fsymbol_name (AREF (key, i)));

Can't we reuse the results of the original downcasing, instead of
doing that again?

> +	  USE_SAFE_ALLOCA;
> +	  ptrdiff_t size = SCHARS (lc_key), n;
> +	  if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
> +	    n = PTRDIFF_MAX;
> +	  unsigned char *dst = SAFE_ALLOCA (n);
> +	  unsigned char *o = dst;
> +	  ptrdiff_t j = 0, j_byte = 0, chars = 0;
> +
> +	  while (j < SCHARS (lc_key))
> +	    {
> +	      int ch = fetch_string_char_advance (lc_key, &j, &j_byte);
> +	      if (ch == ' ')
> +		*o = '-';
> +	      else
> +		*o = ch;
> +	      chars++;

This will only work with plain-ASCII characters in lc_key (but then
you don't need fetch_string_char_advance, you can access the bytes one
by one).  You need to use CHAR_STRING instead.

> +	      int len;
> +	      string_char_and_length (o, &len);
> +	      o += len;

This is overhead.  You already know the length of the multibyte
string, because fetch_string_char_advance reports it back to you via
j_byte.  So just use that.

> diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
> index 68b42c346c..8f3dff2acb 100644
> --- a/test/src/keymap-tests.el
> +++ b/test/src/keymap-tests.el
> @@ -124,6 +124,17 @@ keymap-lookup-key/too-long
>  ;; (ert-deftest keymap-lookup-key/accept-default ()
>  ;;   ...)
>  
> +(ert-deftest keymap-lookup-key/mixed-case ()
> +  (let ((map (make-keymap)))
> +    (define-key map [menu-bar foo bar] 'foo)
> +    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
> +    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo))))
> +
> +(ert-deftest subr-test-lookup-keymap/with-spaces ()
> +  (let ((map (make-keymap)))
> +    (define-key map [menu-bar foo-bar] 'foo)
> +    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
> +
>  (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
>    "Header should be inserted into the current buffer.
>  https://debbugs.gnu.org/39149#31"

Please add tests where the symbols use non-ASCII characters.

Also, what about the existing calls to Flookup_key from C: do they all
need to go through the added processing, or could some of them be
satisfied by calling lookup_key_1?

This change needs a NEWS entry.

Thanks.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 11:59     ` Eli Zaretskii
@ 2021-10-13 12:04       ` Lars Ingebrigtsen
  2021-10-13 12:19         ` Stefan Kangas
  2021-10-15  5:59       ` Eli Zaretskii
  2021-10-19  3:18       ` Stefan Kangas
  2 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-13 12:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Stefan Kangas, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> Beware: downcase uses the current buffer's case-table.  Is that
> something we want here, or could it be undesirable in some cases?

An upper case I in Turkish would be translated to ı, which would not be
what we wanted, I think.  

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 12:04       ` Lars Ingebrigtsen
@ 2021-10-13 12:19         ` Stefan Kangas
  2021-10-13 12:58           ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-13 12:19 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Shuguang Sun, 50752

Lars Ingebrigtsen <larsi@gnus.org> writes:

> An upper case I in Turkish would be translated to ı, which would not be
> what we wanted, I think.

Could you explain why you think that?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 12:19         ` Stefan Kangas
@ 2021-10-13 12:58           ` Lars Ingebrigtsen
  2021-10-13 15:26             ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-13 12:58 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Shuguang Sun, 50752

Stefan Kangas <stefan@marxist.se> writes:

> Lars Ingebrigtsen <larsi@gnus.org> writes:
>
>> An upper case I in Turkish would be translated to ı, which would not be
>> what we wanted, I think.
>
> Could you explain why you think that?

If the menu name the package tried to change was

"PIF Tools"

it's now `pif tools' after being changed to use easy-menu-define, I
think?  So the downcase would work fine for everybody -- except people
that have a Turkish locale, where the downcase would yield `pıf tools',
and we'd have no match after all.

I think.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 12:58           ` Lars Ingebrigtsen
@ 2021-10-13 15:26             ` Stefan Kangas
  2021-10-13 15:42               ` Lars Ingebrigtsen
  2021-10-13 16:09               ` Eli Zaretskii
  0 siblings, 2 replies; 63+ messages in thread
From: Stefan Kangas @ 2021-10-13 15:26 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Shuguang Sun, 50752

Lars Ingebrigtsen <larsi@gnus.org> writes:

> it's now `pif tools' after being changed to use easy-menu-define, I
> think?  So the downcase would work fine for everybody -- except people
> that have a Turkish locale, where the downcase would yield `pıf tools',
> and we'd have no match after all.

I didn't see that we were discussing a regular "I" character (bad font
in this client), but yes that is obviously incorrect.

Do we have an alternative to downcase, or should we just ensure that
it uses a standard case-table?  Could that lead to any other problems?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 15:26             ` Stefan Kangas
@ 2021-10-13 15:42               ` Lars Ingebrigtsen
  2021-10-19  3:22                 ` Stefan Kangas
  2021-10-13 16:09               ` Eli Zaretskii
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-13 15:42 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Shuguang Sun, 50752

Stefan Kangas <stefan@marxist.se> writes:

> Do we have an alternative to downcase, or should we just ensure that
> it uses a standard case-table?  Could that lead to any other problems?

But then non-ASCII characters wouldn't downcase correctly.  :-)

Since we're just trying to be backwards compatible, perhaps it would
make sense to try downcase twice -- once with the current case-table and
once with the standard one and see whether either matches?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 15:26             ` Stefan Kangas
  2021-10-13 15:42               ` Lars Ingebrigtsen
@ 2021-10-13 16:09               ` Eli Zaretskii
  1 sibling, 0 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-13 16:09 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: shuguang79, larsi, 50752

> From: Stefan Kangas <stefan@marxist.se>
> Date: Wed, 13 Oct 2021 17:26:33 +0200
> Cc: Eli Zaretskii <eliz@gnu.org>, Shuguang Sun <shuguang79@qq.com>, 50752@debbugs.gnu.org
> 
> Do we have an alternative to downcase, or should we just ensure that
> it uses a standard case-table?  Could that lead to any other problems?
 
We could use the equivalent of

  (get-char-code-property ?I 'lowercase)

If the above returns nil, it means the lower-case variant is the
character itself.

In C, this means to use uniprop_table, like bidi.c and casefiddle.c
do.  This accesses the database generated from UnicodeData.txt.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 11:59     ` Eli Zaretskii
  2021-10-13 12:04       ` Lars Ingebrigtsen
@ 2021-10-15  5:59       ` Eli Zaretskii
  2021-10-15 18:34         ` Stefan Kangas
  2021-10-19  3:18       ` Stefan Kangas
  2 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-15  5:59 UTC (permalink / raw)
  To: stefan; +Cc: shuguang79, larsi, 50752

> Date: Wed, 13 Oct 2021 14:59:03 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: shuguang79@qq.com, larsi@gnus.org, 50752@debbugs.gnu.org
> 
> > +	  USE_SAFE_ALLOCA;
> > +	  ptrdiff_t size = SCHARS (lc_key), n;
> > +	  if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
> > +	    n = PTRDIFF_MAX;
> > +	  unsigned char *dst = SAFE_ALLOCA (n);
> > +	  unsigned char *o = dst;
> > +	  ptrdiff_t j = 0, j_byte = 0, chars = 0;
> > +
> > +	  while (j < SCHARS (lc_key))
> > +	    {
> > +	      int ch = fetch_string_char_advance (lc_key, &j, &j_byte);
> > +	      if (ch == ' ')
> > +		*o = '-';
> > +	      else
> > +		*o = ch;
> > +	      chars++;
> 
> This will only work with plain-ASCII characters in lc_key (but then
> you don't need fetch_string_char_advance, you can access the bytes one
> by one).  You need to use CHAR_STRING instead.

Thinking more about this, you don't need all these complications with
fetch_string_char_advance and CHAR_STRING.  Since all you need is
replace ' ' with '-', you can walk the string data byte by byte,
because UTF-8 encoding makes sure no other byte of any multibyte
sequence will ever include a 7-bit byte equal to an ASCII single-byte
character.  So just checking the bytes for equality to ' ' is enough.
Thus, you could make a copy of the symbol's name, then walk that copy
byte by byte looking for space characters and replacing them.

Moreover, you could check up front, using 'strstr', whether the
symbol's name includes any space characters, and if not, short-circuit
the entire second attempt.

These two measures should make the code faster and easier to program
and understand.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-15  5:59       ` Eli Zaretskii
@ 2021-10-15 18:34         ` Stefan Kangas
  0 siblings, 0 replies; 63+ messages in thread
From: Stefan Kangas @ 2021-10-15 18:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: shuguang79, larsi, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> These two measures should make the code faster and easier to program
> and understand.

Thanks, this really helps!

I plan to continue looking into the issue this weekend.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 11:59     ` Eli Zaretskii
  2021-10-13 12:04       ` Lars Ingebrigtsen
  2021-10-15  5:59       ` Eli Zaretskii
@ 2021-10-19  3:18       ` Stefan Kangas
  2 siblings, 0 replies; 63+ messages in thread
From: Stefan Kangas @ 2021-10-19  3:18 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: shuguang79, larsi, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> Also, what about the existing calls to Flookup_key from C: do they all
> need to go through the added processing, or could some of them be
> satisfied by calling lookup_key_1?

AFAICT, they need to go through the added processing, as the items could
be extended menu items in all cases.

(I will send separately a new patch that should fix the rest of your
comments.)





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-13 15:42               ` Lars Ingebrigtsen
@ 2021-10-19  3:22                 ` Stefan Kangas
  2021-10-19  3:40                   ` Lars Ingebrigtsen
  2021-10-19 11:43                   ` Eli Zaretskii
  0 siblings, 2 replies; 63+ messages in thread
From: Stefan Kangas @ 2021-10-19  3:22 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Shuguang Sun, 50752

[-- Attachment #1: Type: text/plain, Size: 1627 bytes --]

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Stefan Kangas <stefan@marxist.se> writes:
>
>> Do we have an alternative to downcase, or should we just ensure that
>> it uses a standard case-table?  Could that lead to any other problems?
>
> But then non-ASCII characters wouldn't downcase correctly.  :-)
>
> Since we're just trying to be backwards compatible, perhaps it would
> make sense to try downcase twice -- once with the current case-table and
> once with the standard one and see whether either matches?

So I've tried this approach in the attached patch, but I couldn't get it
to work.  I'm probably doing something wrong, given that I've never so
much as glanced at language environments and case tables before this.

Eli Zaretskii <eliz@gnu.org> writes:

> We could use the equivalent of
>
>   (get-char-code-property ?I 'lowercase)
>
> If the above returns nil, it means the lower-case variant is the
> character itself.
>
> In C, this means to use uniprop_table, like bidi.c and casefiddle.c
> do.  This accesses the database generated from UnicodeData.txt.

I didn't try this approach, mostly because it sounds more difficult to
implement than what Lars said.  I think?  Wouldn't it amount to
basically re-implementing Fdowncase?  Sorry, I didn't look too closely
at this.  Perhaps this would be the better approach.

If anyone has any preferences or further ideas here, that would be much
appreciated, otherwise I'll keep investigating.

The attached patch is what I have so far.  It's obviously not yet
finished, but all tests pass except for the one for "I->i" conversion in
the Turkish language environment.

[-- Attachment #2: 0001-Be-more-allowing-when-looking-for-menu-bar-items.patch --]
[-- Type: text/x-diff, Size: 9529 bytes --]

From 7060128663ebb74ccf659bd1ee6dc38f7c66ba9e Mon Sep 17 00:00:00 2001
From: Stefan Kangas <stefan@marxist.se>
Date: Wed, 13 Oct 2021 00:04:23 +0200
Subject: [PATCH] Be more allowing when looking for menu-bar items

* src/keymap.c (lookup_key_1): Factor out function from
Flookup_key.
(Flookup_key): Be case insensitive, and treat spaces as dashes,
when looking for Qmenu_bar items.  (Bug#50752)

* test/src/keymap-tests.el
(keymap-lookup-key/mixed-case)
(keymap-lookup-key/mixed-case-multibyte)
(keymap-lookup-keymap/with-spaces)
(keymap-lookup-keymap/with-spaces-multibyte)
(keymap-lookup-keymap/with-spaces-multibyte-lang-env): New tests.
---
 etc/NEWS                 |   8 +++
 src/keymap.c             | 125 ++++++++++++++++++++++++++++++++-------
 test/src/keymap-tests.el |  43 ++++++++++++++
 3 files changed, 155 insertions(+), 21 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index b7c4346db9..cb3a0c3ec4 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -4319,6 +4319,14 @@ The new optional "," parameter has been added, and
 ** 'parse-time-string' can now parse ISO 8601 format strings.
 These have a format like "2020-01-15T16:12:21-08:00".
 
+---
+** 'lookup-key' now downcases symbols in extended menu items.
+If looking for a key like '[menu-bar Foo-Bar]', attempt to find
+'[menu-bar foo-bar]' as well.  If looking for a key like '[menu-bar
+Foo\ Bar]', attempt to find both '[menu-bar foo\ bar]' and '[menu-bar
+foo-bar]'.  This improves backwards compatibility when menus are
+converted to use 'easy-menu-define'.
+
 ---
 ** 'make-network-process', 'make-serial-process' ':coding' behavior change.
 Previously, passing ':coding nil' to either of these functions would
diff --git a/src/keymap.c b/src/keymap.c
index be45d2be1e..4b3d50f53e 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1180,27 +1180,8 @@ DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1240,6 +1221,108 @@ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define'), or use " " instead of "-".
+     We accept these variations for backwards-compatibility.
+     (Bug#50752)  */
+  if (VECTORP (key) && ASIZE (key) > 0 && EQ (AREF (key, 0), Qmenu_bar))
+    {
+      ptrdiff_t key_len = ASIZE (key);
+      Lisp_Object new_key = make_vector (key_len, Qnil);
+
+      /* Try both the default ASCII case table, and the buffer local
+	 one.  Otherwise, we will fail for e.g. the "Turkish" language
+	 environment where 'I' does not downcase to 'i'.  */
+      Lisp_Object old_case_table = Fcurrent_case_table ();
+      Lisp_Object tables[2] = {Vascii_downcase_table, old_case_table};
+      for (int i = 0; i < 2; i++)
+	{
+	  Fset_case_table (tables[i]);
+
+	  /* First, let's try converting all symbols like "Foo-Bar-Baz" to
+	     "foo-bar-baz".  */
+	  for (int i = 0; i < key_len; i++)
+	    {
+	      Lisp_Object lc_key = Fdowncase (Fsymbol_name (AREF (key, i)));
+	      ASET (new_key, i, Fintern (lc_key, Qnil));
+	    }
+	  found = lookup_key_1 (keymap, new_key, accept_default);
+
+	  if (!NILP (found) && !NUMBERP (found))
+	    break;
+
+	  /* If we still don't have a match, let's convert any spaces in
+	     our lowercased string into dashes, e.g. "foo bar baz" to
+	     "foo-bar-baz".  */
+	  for (int i = 0; i < key_len; i++)
+	    {
+	      Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));
+
+	      /* If there are no spaces in this symbol, just skip it.  */
+	      if (!strstr (SSDATA (lc_key), " "))
+		continue;
+
+	      USE_SAFE_ALLOCA;
+	      ptrdiff_t size = SCHARS (lc_key), n;
+	      if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+		n = PTRDIFF_MAX;
+	      unsigned char *dst = SAFE_ALLOCA (n);
+
+	      /* We can walk the string data byte by byte, because UTF-8
+		 encoding ensures that no other byte of any multibyte
+		 sequence will ever include a 7-bit byte equal to an ASCII
+		 single-byte character.  */
+	      memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
+	      for (int i = 0; i < SBYTES (lc_key); ++i)
+		{
+		  if (*(dst + i) == ' ')
+		    *(dst + i) = '-';
+		}
+
+	      Lisp_Object
+		new_it = make_multibyte_string ((char *) dst, SCHARS (lc_key), SBYTES (lc_key));
+	      ASET (new_key, i, Fintern (new_it, Qnil));
+	      SAFE_FREE ();
+	    }
+	  found = lookup_key_1 (keymap, new_key, accept_default);
+
+	  if (!NILP (found) && !NUMBERP (found))
+	    break;
+	}
+      /* Restore the previous case table before returning.  */
+      Fset_case_table (old_case_table);
+    }
+
+  return found;
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..a7480fe5cc 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,49 @@ keymap-lookup-key/too-long
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo)))
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar i-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
+
+(ert-deftest keymap-lookup-key/mixed-case-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    ;; (downcase "Åäö") => "åäö"
+    (define-key map [menu-bar åäö bar] 'foo)
+    (should (eq (lookup-key map [menu-bar åäö bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Åäö Bar]) 'foo))
+    ;; (downcase "Γ") => "γ"
+    (define-key map [menu-bar γ bar] 'baz)
+    (should (eq (lookup-key map [menu-bar γ bar]) 'baz))
+    (should (eq (lookup-key map [menu-bar Γ Bar]) 'baz))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar åäö-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Åäö\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte-lang-env ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((lang-env current-language-environment))
+    (set-language-environment "Turkish")
+    (let ((map (make-keymap)))
+      (define-key map [menu-bar i-bar] 'foo)
+      (should (eq (lookup-key map [menu-bar I-bar]) 'foo)))
+    (set-language-environment lang-env)))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31"
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19  3:22                 ` Stefan Kangas
@ 2021-10-19  3:40                   ` Lars Ingebrigtsen
  2021-10-19  3:52                     ` Lars Ingebrigtsen
  2021-10-19 11:43                   ` Eli Zaretskii
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19  3:40 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Shuguang Sun, 50752

Stefan Kangas <stefan@marxist.se> writes:

> The attached patch is what I have so far.  It's obviously not yet
> finished, but all tests pass except for the one for "I->i" conversion in
> the Turkish language environment.

I set up a Turkish lang environment to test, and I'm just getting very
odd results all over from downcase.

After generating the locale, I said:

LANG=tr_TR.UTF-8 ./src/emacs -Q

and

(downcase "İ i I ı")
=> "i̇ i ı ı"

(upcase "İ i I ı")
=> "İ İ I I"

So everything here looks totally fine.  I is downcased to ı as supposed.
But look!

(downcase "I")
=> "1"

Here it's downcasing

  name: LATIN CAPITAL LETTER I

to

  name: DIGIT ONE

!?

But if I put something else that's non-ASCII into the string, then it
downcases correctly:

(downcase "I é")
=> "ı é"

So if the string is multibyte, it downcases correctly, but if not, it...
turns a capital I into the digit 1?

(downcase "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
=> "abcdefgh1jklmnopqrstuvwxyz"

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19  3:40                   ` Lars Ingebrigtsen
@ 2021-10-19  3:52                     ` Lars Ingebrigtsen
  2021-10-19 11:56                       ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19  3:52 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Shuguang Sun, 50752

Lars Ingebrigtsen <larsi@gnus.org> writes:

> So if the string is multibyte, it downcases correctly, but if not, it...
> turns a capital I into the digit 1?
>
> (downcase "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
> => "abcdefgh1jklmnopqrstuvwxyz"

I guess it's from this:

static Lisp_Object
do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
{
  ptrdiff_t i, size = SCHARS (obj);
  int ch, cased;

  obj = Fcopy_sequence (obj);
  for (i = 0; i < size; i++)
    {
      ch = make_char_multibyte (SREF (obj, i));
      cased = case_single_character (ctx, ch);
      if (ch == cased)
	continue;
      cased = make_char_unibyte (cased);
      /* If the char can't be converted to a valid byte, just don't
	 change it.  */
      if (SINGLE_BYTE_CHAR_P (cased))
	SSET (obj, i, cased);
    }
  return obj;
}

Which just looks wrong to me.  The logic in Fdowncase seems to assume
that a unibyte string can never be downcased to a multibyte one, but
that make_char_unibyte is picking out the lowest eight bits of the char
we've downcased to and puts that into the downcased string.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19  3:22                 ` Stefan Kangas
  2021-10-19  3:40                   ` Lars Ingebrigtsen
@ 2021-10-19 11:43                   ` Eli Zaretskii
  2021-10-19 21:54                     ` Stefan Kangas
  1 sibling, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 11:43 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: shuguang79, larsi, 50752

> From: Stefan Kangas <stefan@marxist.se>
> Date: Mon, 18 Oct 2021 20:22:18 -0700
> Cc: Eli Zaretskii <eliz@gnu.org>, Shuguang Sun <shuguang79@qq.com>, 50752@debbugs.gnu.org
> 
> If anyone has any preferences or further ideas here, that would be much
> appreciated, otherwise I'll keep investigating.
> 
> The attached patch is what I have so far.  It's obviously not yet
> finished, but all tests pass except for the one for "I->i" conversion in
> the Turkish language environment.

Don't give up, you are close.

> +	      memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
> +	      for (int i = 0; i < SBYTES (lc_key); ++i)
> +		{
> +		  if (*(dst + i) == ' ')
> +		    *(dst + i) = '-';
> +		}

If you want to use an index to walk the string data, as you did above,
please use dst[i] instead of *(dst + i); the latter is correct, but
ugly and un-C-ish.  Or you could use a pointer to walk, like this:

        unsigned char *p = dst, *dst_end = dst + SBYTES (lc_key);
	for ( ; p < dst_end; p++)
	  {
	    if (*p == ' ')
	      *p = '-';
	  }

> > We could use the equivalent of
> >
> >   (get-char-code-property ?I 'lowercase)
> >
> > If the above returns nil, it means the lower-case variant is the
> > character itself.
> >
> > In C, this means to use uniprop_table, like bidi.c and casefiddle.c
> > do.  This accesses the database generated from UnicodeData.txt.
> 
> I didn't try this approach, mostly because it sounds more difficult to
> implement than what Lars said.  I think?  Wouldn't it amount to
> basically re-implementing Fdowncase?  Sorry, I didn't look too closely
> at this.  Perhaps this would be the better approach.

It shouldn't be hard.  You need to call uniprop_table to get a
char-table:

   Lisp_Object unicode_case_table = uniprop_table (intern ("lowercase"));

which you then reference with

   int low_ch = XFIXNUM (CHAR_TABLE_REF (unicode_case_table, ch));

to get the codepoint of the lower-case character that corresponds to
the (possibly upper-case) character whose codepoint is CH.  Then
downcasing a string boils down to a loop that fetches characters one
by one with fetch_string_char_advance and then stores the lower-case
characters, obtained as above, with CHAR_STRING.  (It's a bit more
complicated than that, because CHAR_TABLE_REF can return nil for the
characters that are either already lower-case or don't have case
variants.  And the uniprop_table call should be done once, at startup
time, or upon first usage, and stored in a staticpro'd variable, see
bidi_initialize for an example.)





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19  3:52                     ` Lars Ingebrigtsen
@ 2021-10-19 11:56                       ` Eli Zaretskii
  2021-10-19 12:07                         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 11:56 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Date: Tue, 19 Oct 2021 05:52:15 +0200
> Cc: Shuguang Sun <shuguang79@qq.com>, 50752@debbugs.gnu.org
> 
> Which just looks wrong to me.  The logic in Fdowncase seems to assume
> that a unibyte string can never be downcased to a multibyte one, but
> that make_char_unibyte is picking out the lowest eight bits of the char
> we've downcased to and puts that into the downcased string.

What would you do instead?  It's a conundrum with no easy solutions.
The original string could include non-ASCII bytes.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 11:56                       ` Eli Zaretskii
@ 2021-10-19 12:07                         ` Lars Ingebrigtsen
  2021-10-19 12:17                           ` Lars Ingebrigtsen
  2021-10-19 12:37                           ` Eli Zaretskii
  0 siblings, 2 replies; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 12:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> What would you do instead?  It's a conundrum with no easy solutions.
> The original string could include non-ASCII bytes.

First of all, I think the code is just plain buggy:

  for (i = 0; i < size; i++)
    {
      ch = make_char_multibyte (SREF (obj, i));
      cased = case_single_character (ctx, ch);
      if (ch == cased)
	continue;
      cased = make_char_unibyte (cased);
      /* If the char can't be converted to a valid byte, just don't
	 change it.  */
      if (SINGLE_BYTE_CHAR_P (cased))
	SSET (obj, i, cased);
    }

That make_char_unibyte makes SINGLE_BYTE_CHAR_P always return true,
doesn't it?  Uhm...  No, what happens to raw bytes...  Oh, yeah,
case_single_character doesn't work for raw bytes, so the "continue" is
always taken for those.

So the code is all kinds of confused, I think.

Second of all -- to handle this specific, very unusual case (i.e.,
downcasing a ascii character gets us a non-ascii character), when we
detect this issue, we should just abort this loop and call
do_casify_multibyte_string instead.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 12:07                         ` Lars Ingebrigtsen
@ 2021-10-19 12:17                           ` Lars Ingebrigtsen
  2021-10-19 12:37                           ` Eli Zaretskii
  1 sibling, 0 replies; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 12:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Lars Ingebrigtsen <larsi@gnus.org> writes:

>       /* If the char can't be converted to a valid byte, just don't
> 	 change it.  */
>       if (SINGLE_BYTE_CHAR_P (cased))
> 	SSET (obj, i, cased);

[...]

> So the code is all kinds of confused, I think.

(I.e., I think the probable intention here is that when downcasing
something, and you get something that's multibyte, you shouldn't alter
the string -- but it does alter the string: It makes the "I" into the
digit "1".)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 12:07                         ` Lars Ingebrigtsen
  2021-10-19 12:17                           ` Lars Ingebrigtsen
@ 2021-10-19 12:37                           ` Eli Zaretskii
  2021-10-19 12:45                             ` Lars Ingebrigtsen
  1 sibling, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 12:37 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 14:07:59 +0200
> 
> Second of all -- to handle this specific, very unusual case (i.e.,
> downcasing a ascii character gets us a non-ascii character), when we
> detect this issue, we should just abort this loop and call
> do_casify_multibyte_string instead.

You mean, you want to special-case Turkish (and a couple of similar)
locale?  That might be possible, but the more general problem will
still be left more or less intact.  And then we need to consider how
many places don't expect to get multibyte string when they downcase a
unibyte one.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 12:37                           ` Eli Zaretskii
@ 2021-10-19 12:45                             ` Lars Ingebrigtsen
  2021-10-19 13:24                               ` Lars Ingebrigtsen
  2021-10-19 15:41                               ` Eli Zaretskii
  0 siblings, 2 replies; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 12:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> You mean, you want to special-case Turkish (and a couple of similar)
> locale?

Nope.  The loop can just check whether we get a multibyte result when
downcasing unibyte (ASCII), and then defer to the multibyte version to
do the computation.

This will basically only happen when using a Turkish (and a couple
similar) locales, though, so the general performance impact will be
approximately nil.

> And then we need to consider how many places don't expect to get
> multibyte string when they downcase a unibyte one.

That's a consideration, but I don't think we'll find out until we try.
(My guess is that nothing will be affected.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 12:45                             ` Lars Ingebrigtsen
@ 2021-10-19 13:24                               ` Lars Ingebrigtsen
  2021-10-19 16:01                                 ` Eli Zaretskii
  2021-10-19 15:41                               ` Eli Zaretskii
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 13:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Nope.  The loop can just check whether we get a multibyte result when
> downcasing unibyte (ASCII), and then defer to the multibyte version to
> do the computation.

I.e., this change, which even passes all the case tests:

diff --git a/src/casefiddle.c b/src/casefiddle.c
index a7a2541490..b46d42f5e2 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -310,11 +310,12 @@ do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
       cased = case_single_character (ctx, ch);
       if (ch == cased)
 	continue;
-      cased = make_char_unibyte (cased);
-      /* If the char can't be converted to a valid byte, just don't
-	 change it.  */
-      if (SINGLE_BYTE_CHAR_P (cased))
-	SSET (obj, i, cased);
+      /* If downcasing changed an ASCII character into a non-ASCII
+	 character (this can happen in some locales, like the Turkish
+	 "I"), use the multibyte algorithm.  */
+      if (SINGLE_BYTE_CHAR_P (ch) && !SINGLE_BYTE_CHAR_P (cased))
+	return do_casify_multibyte_string (ctx, obj);
+      SSET (obj, i, make_char_unibyte (cased));
     }
   return obj;
 }

It's a wonder that Emacs works at all in a Turkish environment -- I
instrumented the function and made it spit out every time it translated
"I" to "1" during startup, and it was a huge stream of

Got multi: jISX0208.1983-0
Got multi: bIG5-0
Got multi: jISX0208.1983-0
Got multi: jISX0208.1983-0
Got multi: bIG5-0
Got multi: jISX0208.1983-0
Got multi: bIG5-0
Got multi: jISX0208.1983-0

etc.  But I guess it doesn't trip up anything really vital.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 12:45                             ` Lars Ingebrigtsen
  2021-10-19 13:24                               ` Lars Ingebrigtsen
@ 2021-10-19 15:41                               ` Eli Zaretskii
  2021-10-19 15:57                                 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 15:41 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 14:45:23 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > You mean, you want to special-case Turkish (and a couple of similar)
> > locale?
> 
> Nope.  The loop can just check whether we get a multibyte result when
> downcasing unibyte (ASCII), and then defer to the multibyte version to
> do the computation.
> 
> This will basically only happen when using a Turkish (and a couple
> similar) locales, though, so the general performance impact will be
> approximately nil.

I'd actually prefer to ignore any locale-specific behavior that take
an ASCII character and downcases (or upcases) it to a non-ASCII one,
in the unibyte case.  IOW, if changing a case of an ASCII character
from a unibyte string produces a non-ASCII multibyte character,
disregard any locale-specific case-conversion and use US ASCII rules.
That at least has the chance of not adversely affecting anything,
whereas producing non-ASCII multibyte string instead is IMO much
worse.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 15:41                               ` Eli Zaretskii
@ 2021-10-19 15:57                                 ` Lars Ingebrigtsen
  2021-10-19 16:12                                   ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 15:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> I'd actually prefer to ignore any locale-specific behavior that take
> an ASCII character and downcases (or upcases) it to a non-ASCII one,
> in the unibyte case.  IOW, if changing a case of an ASCII character
> from a unibyte string produces a non-ASCII multibyte character,
> disregard any locale-specific case-conversion and use US ASCII rules.
> That at least has the chance of not adversely affecting anything,
> whereas producing non-ASCII multibyte string instead is IMO much
> worse.

For the vast majority of cases, that would indeed produce the result
that's probably expected.  (I mean, somebody doing (downcase "LATIN-1")
in code doesn't want the locale, anyway.)

But it means that downcasing a string in a buffer and saying (downcase
"THAT SAME STRING") gives us different results.

But perhaps that's the least bad solution?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 13:24                               ` Lars Ingebrigtsen
@ 2021-10-19 16:01                                 ` Eli Zaretskii
  0 siblings, 0 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 16:01 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 15:24:12 +0200
> 
> +      /* If downcasing changed an ASCII character into a non-ASCII
> +	 character (this can happen in some locales, like the Turkish
> +	 "I"), use the multibyte algorithm.  */
> +      if (SINGLE_BYTE_CHAR_P (ch) && !SINGLE_BYTE_CHAR_P (cased))
> +	return do_casify_multibyte_string (ctx, obj);
> +      SSET (obj, i, make_char_unibyte (cased));

Like I said elsewhere, I'd prefer to use ASCII rules in that case.
It's safer, and definitely less surprising.  Whoever wants Turkish
rules will need to submit multibyte strings, even for ASCII
characters.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 15:57                                 ` Lars Ingebrigtsen
@ 2021-10-19 16:12                                   ` Eli Zaretskii
  2021-10-19 16:15                                     ` Lars Ingebrigtsen
  2021-10-19 16:21                                     ` Lars Ingebrigtsen
  0 siblings, 2 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 16:12 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 17:57:09 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > I'd actually prefer to ignore any locale-specific behavior that take
> > an ASCII character and downcases (or upcases) it to a non-ASCII one,
> > in the unibyte case.  IOW, if changing a case of an ASCII character
> > from a unibyte string produces a non-ASCII multibyte character,
> > disregard any locale-specific case-conversion and use US ASCII rules.
> > That at least has the chance of not adversely affecting anything,
> > whereas producing non-ASCII multibyte string instead is IMO much
> > worse.
> 
> For the vast majority of cases, that would indeed produce the result
> that's probably expected.  (I mean, somebody doing (downcase "LATIN-1")
> in code doesn't want the locale, anyway.)
> 
> But it means that downcasing a string in a buffer and saying (downcase
> "THAT SAME STRING") gives us different results.

If the buffer is unibyte, the results will be the same.

> But perhaps that's the least bad solution?

I think so, yes.  _If_ we are going to change the current behavior,
that is.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 16:12                                   ` Eli Zaretskii
@ 2021-10-19 16:15                                     ` Lars Ingebrigtsen
  2021-10-19 16:21                                     ` Lars Ingebrigtsen
  1 sibling, 0 replies; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 16:15 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> I think so, yes.  _If_ we are going to change the current behavior,
> that is.

Well, the current behaviour is clearly a bug.  So it should be fixed in
one way or another.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 16:12                                   ` Eli Zaretskii
  2021-10-19 16:15                                     ` Lars Ingebrigtsen
@ 2021-10-19 16:21                                     ` Lars Ingebrigtsen
  2021-10-19 16:30                                       ` Eli Zaretskii
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 16:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

>> But perhaps that's the least bad solution?
>
> I think so, yes.

As for the implementation...  do you happen to know whether there are
any locales that makes up/downcase behave differently from the "C"
locale on ASCII characters, but does produce ASCII characters?

I'm just wondering whether the unibyte version of down/upcase should
just explicitly be documented to only do "C" locale stuff on unibyte
strings?  That's easy to explain, at least, but I don't know what the
practical repercussions would be.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 16:21                                     ` Lars Ingebrigtsen
@ 2021-10-19 16:30                                       ` Eli Zaretskii
  2021-10-19 17:12                                         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 16:30 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 18:21:35 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> But perhaps that's the least bad solution?
> >
> > I think so, yes.
> 
> As for the implementation...  do you happen to know whether there are
> any locales that makes up/downcase behave differently from the "C"
> locale on ASCII characters, but does produce ASCII characters?

Not off the top of my head, no.

> I'm just wondering whether the unibyte version of down/upcase should
> just explicitly be documented to only do "C" locale stuff on unibyte
> strings?  That's easy to explain, at least, but I don't know what the
> practical repercussions would be.

This would be an unnecessary loss of functionality.  Right now, one
can arrange a case-conversion table for raw bytes, and it will work
with the current code.  We don't have to lose that, although the
utility of it is questionable.

I think we can leave the behavior with raw bytes as it is, and still
document this use case as being meant for ASCII conversions, leaving
the subtle case of raw bytes ... subtle.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 16:30                                       ` Eli Zaretskii
@ 2021-10-19 17:12                                         ` Lars Ingebrigtsen
  2021-10-19 17:37                                           ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 17:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> I think we can leave the behavior with raw bytes as it is, and still
> document this use case as being meant for ASCII conversions, leaving
> the subtle case of raw bytes ... subtle.

Yup.

The following patch seems to do the trick, and should be conservative
enough for emacs-28, I think.

diff --git a/src/casefiddle.c b/src/casefiddle.c
index a7a2541490..edc9dec2d7 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -297,6 +297,16 @@ do_casify_multibyte_string (struct casing_context *ctx, Lisp_Object obj)
   return obj;
 }
 
+static int
+ascii_casify_character (bool downcase, int c)
+{
+  Lisp_Object cased = CHAR_TABLE_REF (downcase?
+				      uniprop_table (Qlowercase) :
+				      uniprop_table (Quppercase),
+				      c);
+  return FIXNATP (cased) ? XFIXNAT (cased) : c;
+}
+
 static Lisp_Object
 do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
 {
@@ -310,11 +320,12 @@ do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
       cased = case_single_character (ctx, ch);
       if (ch == cased)
 	continue;
-      cased = make_char_unibyte (cased);
-      /* If the char can't be converted to a valid byte, just don't
-	 change it.  */
-      if (SINGLE_BYTE_CHAR_P (cased))
-	SSET (obj, i, cased);
+      /* If down/upcasing changed an ASCII character into a non-ASCII
+	 character (this can happen in some locales, like the Turkish
+	 "I"), downcase using the ASCII char table.  */
+      if (SINGLE_BYTE_CHAR_P (ch) && !SINGLE_BYTE_CHAR_P (cased))
+	cased = ascii_casify_character (ctx->flag == CASE_DOWN, ch);
+      SSET (obj, i, make_char_unibyte (cased));
     }
   return obj;
 }
@@ -651,6 +662,8 @@ syms_of_casefiddle (void)
   DEFSYM (Qbounds, "bounds");
   DEFSYM (Qidentity, "identity");
   DEFSYM (Qtitlecase, "titlecase");
+  DEFSYM (Qlowercase, "lowercase");
+  DEFSYM (Quppercase, "uppercase");
   DEFSYM (Qspecial_uppercase, "special-uppercase");
   DEFSYM (Qspecial_lowercase, "special-lowercase");
   DEFSYM (Qspecial_titlecase, "special-titlecase");

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 17:12                                         ` Lars Ingebrigtsen
@ 2021-10-19 17:37                                           ` Eli Zaretskii
  2021-10-19 18:21                                             ` Lars Ingebrigtsen
  2021-10-20  7:45                                             ` Lars Ingebrigtsen
  0 siblings, 2 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-19 17:37 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 19:12:20 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > I think we can leave the behavior with raw bytes as it is, and still
> > document this use case as being meant for ASCII conversions, leaving
> > the subtle case of raw bytes ... subtle.
> 
> Yup.
> 
> The following patch seems to do the trick, and should be conservative
> enough for emacs-28, I think.

I wouldn't start such experiments on the release branch.  It's not an
urgent problem.

> +static int
> +ascii_casify_character (bool downcase, int c)
> +{
> +  Lisp_Object cased = CHAR_TABLE_REF (downcase?
> +				      uniprop_table (Qlowercase) :
> +				      uniprop_table (Quppercase),
> +				      c);
> +  return FIXNATP (cased) ? XFIXNAT (cased) : c;
> +}

uniprop_table is somewhat expensive, and is definitely an overkill for
converting pure ASCII characters.  Why not just set/reset the 0x20
bit?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 17:37                                           ` Eli Zaretskii
@ 2021-10-19 18:21                                             ` Lars Ingebrigtsen
  2021-10-20 11:28                                               ` Eli Zaretskii
  2021-10-20  7:45                                             ` Lars Ingebrigtsen
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-19 18:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

>> The following patch seems to do the trick, and should be conservative
>> enough for emacs-28, I think.
>
> I wouldn't start such experiments on the release branch.  It's not an
> urgent problem.

Yeah, it's pretty obscure.

> uniprop_table is somewhat expensive, and is definitely an overkill for
> converting pure ASCII characters.  Why not just set/reset the 0x20
> bit?

I thought it made sense to be conservative here and do it "properly",
instead of open-coding an A-Za-z upcase/downcase ourselves.  And doesn't
uniprop_table just return the table from char-code-property-alist here?
So it's an assq from a short list.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 11:43                   ` Eli Zaretskii
@ 2021-10-19 21:54                     ` Stefan Kangas
  2021-10-20 12:59                       ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-19 21:54 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: shuguang79, larsi, 50752

[-- Attachment #1: Type: text/plain, Size: 301 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

> Don't give up, you are close.

Thank you!  Your feedback so far has been extremely useful and much
appreciated.

Based on your comments, I have been able to come up with the attached
patch.  It bootstraps and all tests pass.

Please let me know what you think.

[-- Attachment #2: 0001-Be-more-allowing-when-looking-for-menu-bar-items.patch --]
[-- Type: text/x-diff, Size: 11250 bytes --]

From 67d08470b9a07da2053a562879e222a456098e2b Mon Sep 17 00:00:00 2001
From: Stefan Kangas <stefan@marxist.se>
Date: Wed, 13 Oct 2021 00:04:23 +0200
Subject: [PATCH] Be more allowing when looking for menu-bar items

* src/keymap.c (lookup_key_1): Factor out function from
Flookup_key.
(Flookup_key): Be case insensitive, and treat spaces as dashes,
when looking for Qmenu_bar items.  (Bug#50752)

* test/src/keymap-tests.el
(keymap-lookup-key/mixed-case)
(keymap-lookup-key/mixed-case-multibyte)
(keymap-lookup-keymap/with-spaces)
(keymap-lookup-keymap/with-spaces-multibyte)
(keymap-lookup-keymap/with-spaces-multibyte-lang-env): New tests.
---
 etc/NEWS                 |   8 ++
 src/keymap.c             | 162 ++++++++++++++++++++++++++++++++++-----
 test/src/keymap-tests.el |  43 +++++++++++
 3 files changed, 192 insertions(+), 21 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 7031be311e..b47939305f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -4320,6 +4320,14 @@ The new optional "," parameter has been added, and
 ** 'parse-time-string' can now parse ISO 8601 format strings.
 These have a format like "2020-01-15T16:12:21-08:00".
 
+---
+** 'lookup-key' is more allowing when searching for extended menu items.
+When looking for a menu item '[menu-bar Foo-Bar]', first try to find
+an exact match, then look for the lowercased '[menu-bar foo-bar]'.
+When looking for a menu item with a symbol containing spaces, as in
+'[menu-bar Foo\ Bar]', look for an exact match , then look for both
+'[menu-bar foo\ bar]' and '[menu-bar foo-bar]'.
+
 ---
 ** 'make-network-process', 'make-serial-process' ':coding' behavior change.
 Previously, passing ':coding nil' to either of these functions would
diff --git a/src/keymap.c b/src/keymap.c
index be45d2be1e..75422caf48 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -65,6 +65,9 @@
 /* Pre-allocated 2-element vector for Fcommand_remapping to use.  */
 static Lisp_Object command_remapping_vector;
 
+/* Char table for the backwards-compatibility part in Flookup_key.  */
+Lisp_Object unicode_case_table;
+
 /* Hash table used to cache a reverse-map to speed up calls to where-is.  */
 static Lisp_Object where_is_cache;
 /* Which keymaps are reverse-stored in the cache.  */
@@ -1180,27 +1183,8 @@ DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1240,6 +1224,140 @@ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define'), or use " " instead of "-".
+     The rest of this function is about accepting these variations for
+     backwards-compatibility.  (Bug#50752) */
+
+  /* Just skip everything below unless this is a menu item.  */
+  if (!VECTORP (key) || !(ASIZE (key) > 0)
+      || !EQ (AREF (key, 0), Qmenu_bar))
+    return found;
+
+  /* Initialize the unicode case table, if it wasn't already.  */
+  if (NILP (unicode_case_table))
+    unicode_case_table = uniprop_table (intern ("lowercase"));
+
+  ptrdiff_t key_len = ASIZE (key);
+  Lisp_Object new_key = make_vector (key_len, Qnil);
+
+  /* Try both the Unicode case table, and the buffer local one.
+     Otherwise, we will fail for e.g. the "Turkish" language
+     environment where 'I' does not downcase to 'i'.  */
+  Lisp_Object tables[2] = {unicode_case_table, Fcurrent_case_table ()};
+  for (int tbl_num = 0; tbl_num < 2; tbl_num++)
+    {
+      /* First, let's try converting all symbols like "Foo-Bar-Baz" to
+	 "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+	{
+	  Lisp_Object key_item = Fsymbol_name (AREF (key, i));
+	  Lisp_Object new_item;
+	  if (!STRING_MULTIBYTE (key_item))
+	    {
+	      new_item = Fdowncase (key_item);
+	    }
+	  else
+	    {
+	      USE_SAFE_ALLOCA;
+	      ptrdiff_t size = SCHARS (key_item), n;
+	      if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+		n = PTRDIFF_MAX;
+	      unsigned char *dst = SAFE_ALLOCA (n);
+	      unsigned char *p = dst;
+	      ptrdiff_t j_char = 0, j_byte = 0;
+
+	      while (j_char < size)
+		{
+		  int ch = fetch_string_char_advance (key_item, &j_char, &j_byte);
+		  Lisp_Object ch_conv = CHAR_TABLE_REF (tables[tbl_num], ch);
+		  if (!NILP (ch_conv))
+		    CHAR_STRING (XFIXNUM (ch_conv), p);
+		  else
+		    CHAR_STRING (ch, p);
+		  p = dst + j_byte;
+		}
+	      new_item = make_multibyte_string ((char *) dst,
+						SCHARS (key_item),
+						SBYTES (key_item));
+	      SAFE_FREE ();
+	    }
+	  ASET (new_key, i, Fintern (new_item, Qnil));
+	}
+
+      /* Check for match.  */
+      found = lookup_key_1 (keymap, new_key, accept_default);
+      if (!NILP (found) && !NUMBERP (found))
+	break;
+
+      /* If we still don't have a match, let's convert any spaces in
+	 our lowercased string into dashes, e.g. "foo bar baz" to
+	 "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+	{
+	  Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));
+
+	  /* If there are no spaces in this symbol, just skip it.  */
+	  if (!strstr (SSDATA (lc_key), " "))
+	    continue;
+
+	  USE_SAFE_ALLOCA;
+	  ptrdiff_t size = SCHARS (lc_key), n;
+	  if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+	    n = PTRDIFF_MAX;
+	  unsigned char *dst = SAFE_ALLOCA (n);
+
+	  /* We can walk the string data byte by byte, because UTF-8
+	     encoding ensures that no other byte of any multibyte
+	     sequence will ever include a 7-bit byte equal to an ASCII
+	     single-byte character.  */
+	  memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
+	  for (int i = 0; i < SBYTES (lc_key); ++i)
+	    {
+	      if (dst[i] == ' ')
+		dst[i] = '-';
+	    }
+	  Lisp_Object
+	    new_it = make_multibyte_string ((char *) dst, SCHARS (lc_key), SBYTES (lc_key));
+	  ASET (new_key, i, Fintern (new_it, Qnil));
+	  SAFE_FREE ();
+	}
+
+      /* Check for match.  */
+      found = lookup_key_1 (keymap, new_key, accept_default);
+      if (!NILP (found) && !NUMBERP (found))
+	break;
+    }
+
+  return found;
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
@@ -3210,6 +3328,8 @@ syms_of_keymap (void)
 			     intern_c_string ("mouse-4"),
 			     intern_c_string ("mouse-5"));
 
+  staticpro (&unicode_case_table);
+
   /* Keymap used for minibuffers when doing completion.  */
   /* Keymap used for minibuffers when doing completion and require a match.  */
   DEFSYM (Qkeymapp, "keymapp");
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..a7480fe5cc 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,49 @@ keymap-lookup-key/too-long
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo)))
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar i-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
+
+(ert-deftest keymap-lookup-key/mixed-case-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    ;; (downcase "Åäö") => "åäö"
+    (define-key map [menu-bar åäö bar] 'foo)
+    (should (eq (lookup-key map [menu-bar åäö bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Åäö Bar]) 'foo))
+    ;; (downcase "Γ") => "γ"
+    (define-key map [menu-bar γ bar] 'baz)
+    (should (eq (lookup-key map [menu-bar γ bar]) 'baz))
+    (should (eq (lookup-key map [menu-bar Γ Bar]) 'baz))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar åäö-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Åäö\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte-lang-env ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((lang-env current-language-environment))
+    (set-language-environment "Turkish")
+    (let ((map (make-keymap)))
+      (define-key map [menu-bar i-bar] 'foo)
+      (should (eq (lookup-key map [menu-bar I-bar]) 'foo)))
+    (set-language-environment lang-env)))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31"
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 17:37                                           ` Eli Zaretskii
  2021-10-19 18:21                                             ` Lars Ingebrigtsen
@ 2021-10-20  7:45                                             ` Lars Ingebrigtsen
  2021-10-20 12:24                                               ` Eli Zaretskii
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-20  7:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

I'm still seeing some oddities in the case stuff tr_TR.UTF-8.

If you have

india
ındıa

in a (multibyte) buffer and hit `M-u M-u', I get

İNDİA
INDIA

which is expected.  However, `M-c M-c' gets me

India
Indıa

I tried googling whether dotted lower-case i should be upcased
differently when capitalising, but I couldn't find anything...

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no






^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 18:21                                             ` Lars Ingebrigtsen
@ 2021-10-20 11:28                                               ` Eli Zaretskii
  2021-10-20 11:55                                                 ` Glenn Morris
  2021-10-21  2:45                                                 ` Lars Ingebrigtsen
  0 siblings, 2 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-20 11:28 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Tue, 19 Oct 2021 20:21:42 +0200
> 
> > uniprop_table is somewhat expensive, and is definitely an overkill for
> > converting pure ASCII characters.  Why not just set/reset the 0x20
> > bit?
> 
> I thought it made sense to be conservative here and do it "properly",
> instead of open-coding an A-Za-z upcase/downcase ourselves.

Why is it a problem to do it ourselves?  It's a simple and very
efficient operation, and it will always be correct.

> And doesn't
> uniprop_table just return the table from char-code-property-alist here?
> So it's an assq from a short list.

It returns a char-table (so not really a short list), and it loads a
file when first called.  It isn't incorrect, just too heavy for such a
simple job.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-20 11:28                                               ` Eli Zaretskii
@ 2021-10-20 11:55                                                 ` Glenn Morris
  2021-10-24 20:11                                                   ` Stefan Kangas
  2021-10-21  2:45                                                 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 63+ messages in thread
From: Glenn Morris @ 2021-10-20 11:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, Lars Ingebrigtsen, shuguang79, 50752


This all seems rather complicated to me.

It's very late to comment, but was the approach of adding an optional
argument to easy-menu-define that specifies the precise string to intern
(in place of "(downcase (car menu))"), and using that argument where
needed in those Emacs files that were converted to use easymenu,
rejected?

Basically the last paragraph from
https://lists.gnu.org/r/emacs-devel/2021-03/msg00046.html





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-20  7:45                                             ` Lars Ingebrigtsen
@ 2021-10-20 12:24                                               ` Eli Zaretskii
  0 siblings, 0 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-20 12:24 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Michal Nazarewicz; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Wed, 20 Oct 2021 09:45:44 +0200
> 
> I'm still seeing some oddities in the case stuff tr_TR.UTF-8.
> 
> If you have
> 
> india
> ındıa
> 
> in a (multibyte) buffer and hit `M-u M-u', I get
> 
> İNDİA
> INDIA
> 
> which is expected.  However, `M-c M-c' gets me
> 
> India
> Indıa
> 
> I tried googling whether dotted lower-case i should be upcased
> differently when capitalising, but I couldn't find anything...

Michal, could you perhaps help us out here?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-19 21:54                     ` Stefan Kangas
@ 2021-10-20 12:59                       ` Eli Zaretskii
  0 siblings, 0 replies; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-20 12:59 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: shuguang79, larsi, 50752

> From: Stefan Kangas <stefan@marxist.se>
> Date: Tue, 19 Oct 2021 14:54:59 -0700
> Cc: larsi@gnus.org, shuguang79@qq.com, 50752@debbugs.gnu.org
> 
> +/* Char table for the backwards-compatibility part in Flookup_key.  */
> +Lisp_Object unicode_case_table;

Should be static, I guess.

> +  /* Initialize the unicode case table, if it wasn't already.  */
> +  if (NILP (unicode_case_table))
> +    unicode_case_table = uniprop_table (intern ("lowercase"));

This is okay, but the call to staticpro should be immediately after
you call uniprop_table, so that you protect the value of the table as
it was created.  It won't work to staticpro it in syms_of_keymap,
which runs in temacs at build time.

> +	  if (!STRING_MULTIBYTE (key_item))
> +	    {
> +	      new_item = Fdowncase (key_item);
> +	    }

Style: a single statement in a block doesn't need braces.

And I guess the above assumes we resolve the issue with Turkish
locales when unibyte strings are downcased?

Otherwise, LGTM (but I didn't try applying and running the code).





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-20 11:28                                               ` Eli Zaretskii
  2021-10-20 11:55                                                 ` Glenn Morris
@ 2021-10-21  2:45                                                 ` Lars Ingebrigtsen
  2021-10-21  7:26                                                   ` Eli Zaretskii
  1 sibling, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-21  2:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

>> I thought it made sense to be conservative here and do it "properly",
>> instead of open-coding an A-Za-z upcase/downcase ourselves.
>
> Why is it a problem to do it ourselves?  It's a simple and very
> efficient operation, and it will always be correct.

Hopefully.

>> And doesn't
>> uniprop_table just return the table from char-code-property-alist here?
>> So it's an assq from a short list.
>
> It returns a char-table (so not really a short list), and it loads a
> file when first called.  It isn't incorrect, just too heavy for such a
> simple job.

These case tables are predefined (they're in `char-code-property-alist'
on startup with -Q), so calling uniprop_table here doesn't load
anything, and it doesn't cons anything -- it just does an assq on
char-code-property-alist and returns the char table.

Unless I'm misreading the code completely.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-21  2:45                                                 ` Lars Ingebrigtsen
@ 2021-10-21  7:26                                                   ` Eli Zaretskii
  2021-10-21 13:04                                                     ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-21  7:26 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: stefan, shuguang79, 50752

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  shuguang79@qq.com,  50752@debbugs.gnu.org
> Date: Thu, 21 Oct 2021 04:45:36 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> And doesn't
> >> uniprop_table just return the table from char-code-property-alist here?
> >> So it's an assq from a short list.
> >
> > It returns a char-table (so not really a short list), and it loads a
> > file when first called.  It isn't incorrect, just too heavy for such a
> > simple job.
> 
> These case tables are predefined (they're in `char-code-property-alist'
> on startup with -Q)

Right, we do that when dumping (loading charprop.el does it).

Still, I think using Unicode properties is overkill for this.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-21  7:26                                                   ` Eli Zaretskii
@ 2021-10-21 13:04                                                     ` Lars Ingebrigtsen
  0 siblings, 0 replies; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-21 13:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefan, shuguang79, 50752

Eli Zaretskii <eliz@gnu.org> writes:

> Still, I think using Unicode properties is overkill for this.

Sure.  And having a fast and efficient ASCII-only up/downcaser may be
generally useful.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-20 11:55                                                 ` Glenn Morris
@ 2021-10-24 20:11                                                   ` Stefan Kangas
  2021-10-25 13:06                                                     ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-24 20:11 UTC (permalink / raw)
  To: Glenn Morris, Eli Zaretskii; +Cc: 50752, Lars Ingebrigtsen, shuguang79

Glenn Morris <rgm@gnu.org> writes:

> It's very late to comment, but was the approach of adding an optional
> argument to easy-menu-define that specifies the precise string to intern
> (in place of "(downcase (car menu))"), and using that argument where
> needed in those Emacs files that were converted to use easymenu,
> rejected?

I think at this point, the main counter-argument is that we have one of
the fixes ready, whereas the other one isn't.  I have been mulling your
message over the past couple of days, and I can't really see that your
proposed solution is significantly better.  The chosen solution allows
us to side-step the issue with a small and localized change.

Furthermore, the approach we have chosen here is IMO not that
complicated, at least not on a basic level.  Written in Lisp, it would
be very straight-forward indeed, but it turned out that with the
structure of our code it was easier to just write it in C.

So I would suggest pushing my fix to emacs-28, so that we can give it as
much testing as possible.  At this stage, it feels important to make
sure there is some fix on the emacs-28 branch so that we can start
testing it and gather feedback.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-24 20:11                                                   ` Stefan Kangas
@ 2021-10-25 13:06                                                     ` Lars Ingebrigtsen
  2021-10-25 13:19                                                       ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-25 13:06 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Glenn Morris, 50752, shuguang79

Stefan Kangas <stefan@marxist.se> writes:

> So I would suggest pushing my fix to emacs-28, so that we can give it as
> much testing as possible.  At this stage, it feels important to make
> sure there is some fix on the emacs-28 branch so that we can start
> testing it and gather feedback.

Yup.  (And I think your fix is the right one.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-25 13:06                                                     ` Lars Ingebrigtsen
@ 2021-10-25 13:19                                                       ` Eli Zaretskii
  2021-10-25 13:21                                                         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-25 13:19 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: rgm, stefan, 50752, shuguang79

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: Glenn Morris <rgm@gnu.org>,  Eli Zaretskii <eliz@gnu.org>,
>   50752@debbugs.gnu.org,  shuguang79@qq.com
> Date: Mon, 25 Oct 2021 15:06:15 +0200
> 
> Stefan Kangas <stefan@marxist.se> writes:
> 
> > So I would suggest pushing my fix to emacs-28, so that we can give it as
> > much testing as possible.  At this stage, it feels important to make
> > sure there is some fix on the emacs-28 branch so that we can start
> > testing it and gather feedback.
> 
> Yup.  (And I think your fix is the right one.)

Sorry, I see no reason to put this on the release branch.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-25 13:19                                                       ` Eli Zaretskii
@ 2021-10-25 13:21                                                         ` Lars Ingebrigtsen
  2021-10-25 13:51                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-25 13:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, stefan, 50752, shuguang79

Eli Zaretskii <eliz@gnu.org> writes:

> Sorry, I see no reason to put this on the release branch.

It fixes real interoperability problems -- there are packages out there
that break with the current emacs-28 because of the previous
easy-menu-define changes.  Stefan's patch unbreaks those, but should
otherwise not affect operation.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-25 13:21                                                         ` Lars Ingebrigtsen
@ 2021-10-25 13:51                                                           ` Eli Zaretskii
  2021-10-25 13:55                                                             ` Lars Ingebrigtsen
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-25 13:51 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: rgm, stefan, 50752, shuguang79

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  rgm@gnu.org,  50752@debbugs.gnu.org,  shuguang79@qq.com
> Date: Mon, 25 Oct 2021 15:21:56 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Sorry, I see no reason to put this on the release branch.
> 
> It fixes real interoperability problems -- there are packages out there
> that break with the current emacs-28 because of the previous
> easy-menu-define changes.  Stefan's patch unbreaks those, but should
> otherwise not affect operation.

Can we come up with a much simpler and safer variant that could
perhaps solve 85% of the problem? like perhaps only the letter-case,
and disregarding the Turkish issue somehow?  Then I could agree to
have that on the release branch.  The code on master is complex and
non-trivial, so having that on the release branch scares me.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-25 13:51                                                           ` Eli Zaretskii
@ 2021-10-25 13:55                                                             ` Lars Ingebrigtsen
  2021-10-25 14:12                                                               ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-25 13:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, stefan, 50752, shuguang79

Eli Zaretskii <eliz@gnu.org> writes:

> Can we come up with a much simpler and safer variant that could
> perhaps solve 85% of the problem? like perhaps only the letter-case,
> and disregarding the Turkish issue somehow?  Then I could agree to
> have that on the release branch.

Sure, I think that's what Stefan went for at the start (and which I was
thinking of, too), but it sounded like you wanted this to be more
ambitious.

I think just downcasing ASCII would get use more than 99%, really.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-25 13:55                                                             ` Lars Ingebrigtsen
@ 2021-10-25 14:12                                                               ` Eli Zaretskii
  2021-10-26  8:38                                                                 ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-25 14:12 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: rgm, stefan, 50752, shuguang79

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: stefan@marxist.se,  rgm@gnu.org,  50752@debbugs.gnu.org,  shuguang79@qq.com
> Date: Mon, 25 Oct 2021 15:55:03 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Can we come up with a much simpler and safer variant that could
> > perhaps solve 85% of the problem? like perhaps only the letter-case,
> > and disregarding the Turkish issue somehow?  Then I could agree to
> > have that on the release branch.
> 
> Sure, I think that's what Stefan went for at the start (and which I was
> thinking of, too), but it sounded like you wanted this to be more
> ambitious.
> 
> I think just downcasing ASCII would get use more than 99%, really.

Then let's go with this variant on emacs-28, and leave the full
solution for master.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-25 14:12                                                               ` Eli Zaretskii
@ 2021-10-26  8:38                                                                 ` Stefan Kangas
  2021-10-26 13:04                                                                   ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-26  8:38 UTC (permalink / raw)
  To: Eli Zaretskii, Lars Ingebrigtsen; +Cc: rgm, 50752, shuguang79

[-- Attachment #1: Type: text/plain, Size: 639 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> I think just downcasing ASCII would get use more than 99%, really.
>
> Then let's go with this variant on emacs-28, and leave the full
> solution for master.

OK.  I'm not sure if you just mean my previous patch, but without Lars'
fixes for the Turkish language environment, or if you mean a stripped
down version of my patch.

So I have attached two versions of the patch, one minimal one and the
one you've already seen with the additional fixes for language
environments.

Please let me know which of these is acceptable for emacs-28, and I will
push it as soon as possible.

Thanks in advance.

[-- Attachment #2: minimal-0001-Be-more-allowing-when-looking-for-menu-bar-items.patch --]
[-- Type: text/x-diff, Size: 8647 bytes --]

From f4a8cff7ee0ef09f5b95496dccc5fbcfc2a99d18 Mon Sep 17 00:00:00 2001
From: Stefan Kangas <stefan@marxist.se>
Date: Wed, 13 Oct 2021 00:04:23 +0200
Subject: [PATCH] Be more allowing when looking for menu-bar items

* src/keymap.c (lookup_key_1): Factor out function from
Flookup_key.
(Flookup_key): Be case insensitive, and treat spaces as dashes,
when looking for Qmenu_bar items.  (Bug#50752)

* test/src/keymap-tests.el
(keymap-lookup-key/mixed-case)
(keymap-lookup-key/mixed-case-multibyte)
(keymap-lookup-keymap/with-spaces)
(keymap-lookup-keymap/with-spaces-multibyte): New tests.
---
 etc/NEWS                 |   8 +++
 src/keymap.c             | 112 +++++++++++++++++++++++++++++++--------
 test/src/keymap-tests.el |  34 ++++++++++++
 3 files changed, 133 insertions(+), 21 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 7f9797e1fa..60dfff60ab 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -4348,6 +4348,14 @@ The new optional "," parameter has been added, and
 ** 'parse-time-string' can now parse ISO 8601 format strings.
 These have a format like "2020-01-15T16:12:21-08:00".
 
+---
+** 'lookup-key' is more allowing when searching for extended menu items.
+When looking for a menu item '[menu-bar Foo-Bar]', first try to find
+an exact match, then look for the lowercased '[menu-bar foo-bar]'.
+When looking for a menu item with a symbol containing spaces, as in
+'[menu-bar Foo\ Bar]', look for an exact match , then look for both
+'[menu-bar foo\ bar]' and '[menu-bar foo-bar]'.
+
 ---
 ** 'make-network-process', 'make-serial-process' ':coding' behavior change.
 Previously, passing ':coding nil' to either of these functions would
diff --git a/src/keymap.c b/src/keymap.c
index 940a6f492e..5955b73c63 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1183,27 +1183,8 @@ DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1243,6 +1224,95 @@ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define'), or use " " instead of "-".
+     The rest of this function is about accepting these variations for
+     backwards-compatibility.  (Bug#50752) */
+
+  /* Just skip everything below unless this is a menu item.  */
+  if (!VECTORP (key) || !(ASIZE (key) > 0)
+      || !EQ (AREF (key, 0), Qmenu_bar))
+    return found;
+
+  ptrdiff_t key_len = ASIZE (key);
+  Lisp_Object new_key = make_vector (key_len, Qnil);
+
+  /* First, let's try converting all symbols like "Foo-Bar-Baz" to
+     "foo-bar-baz".  */
+  for (int i = 0; i < key_len; i++)
+    {
+      Lisp_Object new_item = Fdowncase (Fsymbol_name (AREF (key, i)));
+      ASET (new_key, i, Fintern (new_item, Qnil));
+    }
+
+  /* Check for match.  */
+  found = lookup_key_1 (keymap, new_key, accept_default);
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* If we still don't have a match, let's convert any spaces in
+     our lowercased string into dashes, e.g. "foo bar baz" to
+     "foo-bar-baz".  */
+  for (int i = 0; i < key_len; i++)
+    {
+      Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));
+
+      /* If there are no spaces in this symbol, just skip it.  */
+      if (!strstr (SSDATA (lc_key), " "))
+	continue;
+
+      USE_SAFE_ALLOCA;
+      ptrdiff_t size = SCHARS (lc_key), n;
+      if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+	n = PTRDIFF_MAX;
+      unsigned char *dst = SAFE_ALLOCA (n);
+
+      /* We can walk the string data byte by byte, because UTF-8
+	 encoding ensures that no other byte of any multibyte
+	 sequence will ever include a 7-bit byte equal to an ASCII
+	 single-byte character.  */
+      memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
+      for (int i = 0; i < SBYTES (lc_key); ++i)
+	{
+	  if (dst[i] == ' ')
+	    dst[i] = '-';
+	}
+      Lisp_Object
+	new_it = make_multibyte_string ((char *) dst, SCHARS (lc_key), SBYTES (lc_key));
+      ASET (new_key, i, Fintern (new_it, Qnil));
+      SAFE_FREE ();
+    }
+
+  /* Check for match.  */
+  return lookup_key_1 (keymap, new_key, accept_default);
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..e835af4890 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,40 @@ keymap-lookup-key/too-long
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo)))
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar i-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
+
+(ert-deftest keymap-lookup-key/mixed-case-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    ;; (downcase "Åäö") => "åäö"
+    (define-key map [menu-bar åäö bar] 'foo)
+    (should (eq (lookup-key map [menu-bar åäö bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Åäö Bar]) 'foo))
+    ;; (downcase "Γ") => "γ"
+    (define-key map [menu-bar γ bar] 'baz)
+    (should (eq (lookup-key map [menu-bar γ bar]) 'baz))
+    (should (eq (lookup-key map [menu-bar Γ Bar]) 'baz))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar åäö-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Åäö\ Bar]) 'foo))))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31"
-- 
2.30.2


[-- Attachment #3: full-0001-Be-more-allowing-when-looking-for-menu-bar-items.patch --]
[-- Type: text/x-diff, Size: 10959 bytes --]

From 7a3d5eacf20a2ee1cf732a850c8e0283e591aaa7 Mon Sep 17 00:00:00 2001
From: Stefan Kangas <stefan@marxist.se>
Date: Wed, 13 Oct 2021 00:04:23 +0200
Subject: [PATCH] Be more allowing when looking for menu-bar items

* src/keymap.c (lookup_key_1): Factor out function from
Flookup_key.
(Flookup_key): Be case insensitive, and treat spaces as dashes,
when looking for Qmenu_bar items.  (Bug#50752)

* test/src/keymap-tests.el
(keymap-lookup-key/mixed-case)
(keymap-lookup-key/mixed-case-multibyte)
(keymap-lookup-keymap/with-spaces)
(keymap-lookup-keymap/with-spaces-multibyte)
(keymap-lookup-keymap/with-spaces-multibyte-lang-env): New tests.
---
 etc/NEWS                 |   8 ++
 src/keymap.c             | 161 ++++++++++++++++++++++++++++++++++-----
 test/src/keymap-tests.el |  43 +++++++++++
 3 files changed, 191 insertions(+), 21 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 7f9797e1fa..60dfff60ab 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -4348,6 +4348,14 @@ The new optional "," parameter has been added, and
 ** 'parse-time-string' can now parse ISO 8601 format strings.
 These have a format like "2020-01-15T16:12:21-08:00".
 
+---
+** 'lookup-key' is more allowing when searching for extended menu items.
+When looking for a menu item '[menu-bar Foo-Bar]', first try to find
+an exact match, then look for the lowercased '[menu-bar foo-bar]'.
+When looking for a menu item with a symbol containing spaces, as in
+'[menu-bar Foo\ Bar]', look for an exact match , then look for both
+'[menu-bar foo\ bar]' and '[menu-bar foo-bar]'.
+
 ---
 ** 'make-network-process', 'make-serial-process' ':coding' behavior change.
 Previously, passing ':coding nil' to either of these functions would
diff --git a/src/keymap.c b/src/keymap.c
index 940a6f492e..e4e5065f26 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -65,6 +65,9 @@
 /* Pre-allocated 2-element vector for Fcommand_remapping to use.  */
 static Lisp_Object command_remapping_vector;
 
+/* Char table for the backwards-compatibility part in Flookup_key.  */
+static Lisp_Object unicode_case_table;
+
 /* Hash table used to cache a reverse-map to speed up calls to where-is.  */
 static Lisp_Object where_is_cache;
 /* Which keymaps are reverse-stored in the cache.  */
@@ -1183,27 +1186,8 @@ DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1243,6 +1227,141 @@ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define'), or use " " instead of "-".
+     The rest of this function is about accepting these variations for
+     backwards-compatibility.  (Bug#50752) */
+
+  /* Just skip everything below unless this is a menu item.  */
+  if (!VECTORP (key) || !(ASIZE (key) > 0)
+      || !EQ (AREF (key, 0), Qmenu_bar))
+    return found;
+
+  /* Initialize the unicode case table, if it wasn't already.  */
+  if (NILP (unicode_case_table))
+    {
+      unicode_case_table = uniprop_table (intern ("lowercase"));
+      staticpro (&unicode_case_table);
+    }
+
+  ptrdiff_t key_len = ASIZE (key);
+  Lisp_Object new_key = make_vector (key_len, Qnil);
+
+  /* Try both the Unicode case table, and the buffer local one.
+     Otherwise, we will fail for e.g. the "Turkish" language
+     environment where 'I' does not downcase to 'i'.  */
+  Lisp_Object tables[2] = {unicode_case_table, Fcurrent_case_table ()};
+  for (int tbl_num = 0; tbl_num < 2; tbl_num++)
+    {
+      /* First, let's try converting all symbols like "Foo-Bar-Baz" to
+	 "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+	{
+	  Lisp_Object key_item = Fsymbol_name (AREF (key, i));
+	  Lisp_Object new_item;
+	  if (!STRING_MULTIBYTE (key_item))
+	    new_item = Fdowncase (key_item);
+	  else
+	    {
+	      USE_SAFE_ALLOCA;
+	      ptrdiff_t size = SCHARS (key_item), n;
+	      if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+		n = PTRDIFF_MAX;
+	      unsigned char *dst = SAFE_ALLOCA (n);
+	      unsigned char *p = dst;
+	      ptrdiff_t j_char = 0, j_byte = 0;
+
+	      while (j_char < size)
+		{
+		  int ch = fetch_string_char_advance (key_item, &j_char, &j_byte);
+		  Lisp_Object ch_conv = CHAR_TABLE_REF (tables[tbl_num], ch);
+		  if (!NILP (ch_conv))
+		    CHAR_STRING (XFIXNUM (ch_conv), p);
+		  else
+		    CHAR_STRING (ch, p);
+		  p = dst + j_byte;
+		}
+	      new_item = make_multibyte_string ((char *) dst,
+						SCHARS (key_item),
+						SBYTES (key_item));
+	      SAFE_FREE ();
+	    }
+	  ASET (new_key, i, Fintern (new_item, Qnil));
+	}
+
+      /* Check for match.  */
+      found = lookup_key_1 (keymap, new_key, accept_default);
+      if (!NILP (found) && !NUMBERP (found))
+	break;
+
+      /* If we still don't have a match, let's convert any spaces in
+	 our lowercased string into dashes, e.g. "foo bar baz" to
+	 "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+	{
+	  Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));
+
+	  /* If there are no spaces in this symbol, just skip it.  */
+	  if (!strstr (SSDATA (lc_key), " "))
+	    continue;
+
+	  USE_SAFE_ALLOCA;
+	  ptrdiff_t size = SCHARS (lc_key), n;
+	  if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+	    n = PTRDIFF_MAX;
+	  unsigned char *dst = SAFE_ALLOCA (n);
+
+	  /* We can walk the string data byte by byte, because UTF-8
+	     encoding ensures that no other byte of any multibyte
+	     sequence will ever include a 7-bit byte equal to an ASCII
+	     single-byte character.  */
+	  memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
+	  for (int i = 0; i < SBYTES (lc_key); ++i)
+	    {
+	      if (dst[i] == ' ')
+		dst[i] = '-';
+	    }
+	  Lisp_Object
+	    new_it = make_multibyte_string ((char *) dst, SCHARS (lc_key), SBYTES (lc_key));
+	  ASET (new_key, i, Fintern (new_it, Qnil));
+	  SAFE_FREE ();
+	}
+
+      /* Check for match.  */
+      found = lookup_key_1 (keymap, new_key, accept_default);
+      if (!NILP (found) && !NUMBERP (found))
+	break;
+    }
+
+  return found;
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..a7480fe5cc 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,49 @@ keymap-lookup-key/too-long
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo)))
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar i-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
+
+(ert-deftest keymap-lookup-key/mixed-case-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    ;; (downcase "Åäö") => "åäö"
+    (define-key map [menu-bar åäö bar] 'foo)
+    (should (eq (lookup-key map [menu-bar åäö bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Åäö Bar]) 'foo))
+    ;; (downcase "Γ") => "γ"
+    (define-key map [menu-bar γ bar] 'baz)
+    (should (eq (lookup-key map [menu-bar γ bar]) 'baz))
+    (should (eq (lookup-key map [menu-bar Γ Bar]) 'baz))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar åäö-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Åäö\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte-lang-env ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((lang-env current-language-environment))
+    (set-language-environment "Turkish")
+    (let ((map (make-keymap)))
+      (define-key map [menu-bar i-bar] 'foo)
+      (should (eq (lookup-key map [menu-bar I-bar]) 'foo)))
+    (set-language-environment lang-env)))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31"
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-26  8:38                                                                 ` Stefan Kangas
@ 2021-10-26 13:04                                                                   ` Eli Zaretskii
  2021-10-26 20:24                                                                     ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-26 13:04 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: rgm, larsi, 50752, shuguang79

> From: Stefan Kangas <stefan@marxist.se>
> Date: Tue, 26 Oct 2021 01:38:32 -0700
> Cc: rgm@gnu.org, 50752@debbugs.gnu.org, shuguang79@qq.com
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> I think just downcasing ASCII would get use more than 99%, really.
> >
> > Then let's go with this variant on emacs-28, and leave the full
> > solution for master.
> 
> OK.  I'm not sure if you just mean my previous patch, but without Lars'
> fixes for the Turkish language environment, or if you mean a stripped
> down version of my patch.

Unfortunately, I meant neither of these two, because they both are
quite non-trivial.  I meant a much simpler patch which only downcases
ASCII letters, and that's all.  Such a change doesn't need to call
Fdowncase, and definitely doesn't need to futz with multibyte
characters.  It should be a simple copy and a single loop downcasing
the characters.  (The NEWS entry for emacs-28 should thus say that we
only handle this simple class of problems.)

The log message should say "don't merge to master".

Sorry for not expressing myself clearly enough.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-26 13:04                                                                   ` Eli Zaretskii
@ 2021-10-26 20:24                                                                     ` Stefan Kangas
  2021-10-27 14:00                                                                       ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-26 20:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, larsi, 50752, shuguang79

Eli Zaretskii <eliz@gnu.org> writes:

> Unfortunately, I meant neither of these two, because they both are
> quite non-trivial.  I meant a much simpler patch which only downcases
> ASCII letters, and that's all.  Such a change doesn't need to call
> Fdowncase, and definitely doesn't need to futz with multibyte
> characters.  It should be a simple copy and a single loop downcasing
> the characters.  (The NEWS entry for emacs-28 should thus say that we
> only handle this simple class of problems.)

OK, let me just double check that you mean to memcpy and then just loop
over the memory byte by bite and update them like so:

    int new_ch = XFIXNUM (CHAR_TABLE_REF (Vascii_downcase_table, ch))

Or do you mean something even simpler like this?

    if (ch >= 'A' && ch <= 'Z')
        new_ch = c + ('A' - 'a');

> The log message should say "don't merge to master".

Hmm.  If we can live with a simpler fix on emacs-28, can we not live
with it on master as well?

Or at least live with it until we can evaluate if the simpler fix did
the job well enough?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-26 20:24                                                                     ` Stefan Kangas
@ 2021-10-27 14:00                                                                       ` Eli Zaretskii
  2021-10-28  5:29                                                                         ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-27 14:00 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: rgm, larsi, 50752, shuguang79

> From: Stefan Kangas <stefan@marxist.se>
> Date: Tue, 26 Oct 2021 22:24:10 +0200
> Cc: larsi@gnus.org, rgm@gnu.org, 50752@debbugs.gnu.org, shuguang79@qq.com
> 
> OK, let me just double check that you mean to memcpy and then just loop
> over the memory byte by bite and update them like so:
> 
>     int new_ch = XFIXNUM (CHAR_TABLE_REF (Vascii_downcase_table, ch))
> 
> Or do you mean something even simpler like this?
> 
>     if (ch >= 'A' && ch <= 'Z')
>         new_ch = c + ('A' - 'a');

The latter.

> > The log message should say "don't merge to master".
> 
> Hmm.  If we can live with a simpler fix on emacs-28, can we not live
> with it on master as well?

On master, I'd prefer to have the full solution, which you already
coded.  There's no need to give up a complete solution there.  It just
is too complex to safely backport it to the release branch, so Emacs
28 will have to do with a 99% solution, not 100%.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-27 14:00                                                                       ` Eli Zaretskii
@ 2021-10-28  5:29                                                                         ` Stefan Kangas
  2021-10-28  7:33                                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-28  5:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, larsi, 50752, shuguang79

[-- Attachment #1: Type: text/plain, Size: 247 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> Or do you mean something even simpler like this?
>>
>>     if (ch >= 'A' && ch <= 'Z')
>>         new_ch = c + ('A' - 'a');
>
> The latter.

OK, I guess that should be the attached.  I hope I got it right.

[-- Attachment #2: 0001-Be-more-allowing-when-looking-for-menu-bar-items.patch --]
[-- Type: text/x-diff, Size: 6503 bytes --]

From 669efa1b066f15a4550ab00e1020d23e2581fda5 Mon Sep 17 00:00:00 2001
From: Stefan Kangas <stefan@marxist.se>
Date: Wed, 13 Oct 2021 00:04:23 +0200
Subject: [PATCH] Be more allowing when looking for menu-bar items

* src/keymap.c (lookup_key_1): Factor out function from
Flookup_key.
(Flookup_key): Be case insensitive when looking for Qmenu_bar
items.  (Bug#50752)

* test/src/keymap-tests.el
(keymap-lookup-key/mixed-case)
(keymap-lookup-key/mixed-case-multibyte): New tests.

Don't merge to master.
---
 etc/NEWS                 |  8 ++++
 src/keymap.c             | 80 +++++++++++++++++++++++++++++-----------
 test/src/keymap-tests.el | 10 +++++
 3 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index a2b7baf1ad..9f1a00134d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -4343,6 +4343,14 @@ The new optional "," parameter has been added, and
 ** 'parse-time-string' can now parse ISO 8601 format strings.
 These have a format like "2020-01-15T16:12:21-08:00".
 
+---
+** 'lookup-key' is more allowing when searching for extended menu items.
+When looking for a menu item '[menu-bar Foo-Bar]', first try to find
+an exact match, then look for the lowercased '[menu-bar foo-bar]'.
+It will only try to downcase ASCII characters in the range "A-Z".
+This improves backwards-compatibility when converting menus to use
+'easy-menu-define'.
+
 ---
 ** 'make-network-process', 'make-serial-process' ':coding' behavior change.
 Previously, passing ':coding nil' to either of these functions would
diff --git a/src/keymap.c b/src/keymap.c
index 940a6f492e..f7529f808b 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1183,27 +1183,8 @@ DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1243,6 +1224,63 @@ DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define').  We accept this variation for
+     backwards-compatibility.  (Bug#50752)  */
+  ptrdiff_t key_len = ASIZE (key);
+  if (VECTORP (key) && key_len > 0 && EQ (AREF (key, 0), Qmenu_bar))
+    {
+      Lisp_Object new_key = make_vector (key_len, Qnil);
+      for (int i = 0; i < key_len; ++i)
+	{
+	  Lisp_Object sym = Fsymbol_name (AREF (key, i));
+	  USE_SAFE_ALLOCA;
+	  unsigned char *dst = SAFE_ALLOCA (SBYTES (sym) + 1);
+	  memcpy (dst, SSDATA (sym), SBYTES (sym));
+	  /* We can walk the string data byte by byte, because UTF-8
+	     encoding ensures that no other byte of any multibyte
+	     sequence will ever include a 7-bit byte equal to an ASCII
+	     single-byte character.  */
+	  for (int j = 0; j < SBYTES (sym); ++j)
+	    if (dst[j] >= 'A' && dst[j] <= 'Z')
+	      dst[j] += 'a' - 'A';  /* Convert to lower case.  */
+	  ASET (new_key, i, Fintern (make_multibyte_string ((char *) dst,
+							    SCHARS (sym),
+							    SBYTES (sym)),
+				     Qnil));
+	  SAFE_FREE ();
+	}
+      found = lookup_key_1 (keymap, new_key, accept_default);
+    }
+  return found;
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..1943e719ab 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,16 @@ keymap-lookup-key/too-long
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo)))
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar i-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31"
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-28  5:29                                                                         ` Stefan Kangas
@ 2021-10-28  7:33                                                                           ` Eli Zaretskii
  2021-10-28  8:06                                                                             ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-28  7:33 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: rgm, larsi, 50752, shuguang79

> From: Stefan Kangas <stefan@marxist.se>
> Date: Wed, 27 Oct 2021 22:29:48 -0700
> Cc: larsi@gnus.org, rgm@gnu.org, 50752@debbugs.gnu.org, shuguang79@qq.com
> 
> >>     if (ch >= 'A' && ch <= 'Z')
> >>         new_ch = c + ('A' - 'a');
> >
> > The latter.
> 
> OK, I guess that should be the attached.  I hope I got it right.

Yes, thanks.  But you still didn't say "don't merge to master", for
some reason.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-28  7:33                                                                           ` Eli Zaretskii
@ 2021-10-28  8:06                                                                             ` Stefan Kangas
  2021-10-28  9:35                                                                               ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-28  8:06 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, larsi, 50752, shuguang79

Eli Zaretskii <eliz@gnu.org> writes:

> Yes, thanks.  But you still didn't say "don't merge to master", for
> some reason.

AFAICT, the commit message in the patch I sent does say so, right at the end.

Is it not in the correct format?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-28  8:06                                                                             ` Stefan Kangas
@ 2021-10-28  9:35                                                                               ` Eli Zaretskii
  2021-10-28 10:49                                                                                 ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-28  9:35 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: rgm, larsi, 50752, shuguang79

> From: Stefan Kangas <stefan@marxist.se>
> Date: Thu, 28 Oct 2021 01:06:45 -0700
> Cc: larsi@gnus.org, rgm@gnu.org, 50752@debbugs.gnu.org, shuguang79@qq.com
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Yes, thanks.  But you still didn't say "don't merge to master", for
> > some reason.
> 
> AFAICT, the commit message in the patch I sent does say so, right at the end.

It does indeed, sorry for being blind.

> Is it not in the correct format?

Not wrong, just not easy to read.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-28  9:35                                                                               ` Eli Zaretskii
@ 2021-10-28 10:49                                                                                 ` Stefan Kangas
  2021-10-28 12:49                                                                                   ` Eli Zaretskii
  0 siblings, 1 reply; 63+ messages in thread
From: Stefan Kangas @ 2021-10-28 10:49 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, larsi, 50752, shuguang79

Eli Zaretskii <eliz@gnu.org> writes:

> Not wrong, just not easy to read.

Indeed, it's sort of easy to miss.  Noam seems to have used this more
visible format before that I chose to copy:

    Don't merge to master.  This is a safe-for-release fix for Bug#40727.

(I also moved it to the third line for good measure.)

With that change, this fix is now pushed to emacs-28 (commit
0f8417d597).  Should I go ahead and push the patch for master as well?





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-28 10:49                                                                                 ` Stefan Kangas
@ 2021-10-28 12:49                                                                                   ` Eli Zaretskii
  2021-10-28 20:44                                                                                     ` Stefan Kangas
  0 siblings, 1 reply; 63+ messages in thread
From: Eli Zaretskii @ 2021-10-28 12:49 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: rgm, larsi, 50752, shuguang79

> From: Stefan Kangas <stefan@marxist.se>
> Date: Thu, 28 Oct 2021 06:49:12 -0400
> Cc: larsi@gnus.org, rgm@gnu.org, 50752@debbugs.gnu.org, shuguang79@qq.com
> 
> With that change, this fix is now pushed to emacs-28 (commit
> 0f8417d597).  Should I go ahead and push the patch for master as well?

The more thorough one, which also supported spaces instead of dashes?
Yes, I think so.

Thanks.





^ permalink raw reply	[flat|nested] 63+ messages in thread

* bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key
  2021-10-28 12:49                                                                                   ` Eli Zaretskii
@ 2021-10-28 20:44                                                                                     ` Stefan Kangas
  0 siblings, 0 replies; 63+ messages in thread
From: Stefan Kangas @ 2021-10-28 20:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rgm, larsi, 50752, shuguang79

close 50752 28.1
thanks

Eli Zaretskii <eliz@gnu.org> writes:

> The more thorough one, which also supported spaces instead of dashes?
> Yes, I think so.

OK, now done (commit 2671ea0de8).  I'm consequently closing this bug
report, and marking it as done in "28.1" (as the recipe in the original
bug report was fixed in that version).

BTW, thanks for the assertion fix on emacs-28.  I had somehow forgotten
to re-enable the assertion flags after disabling them to try something
out the other day.  I'll try to remember to double check that next time.





^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, other threads:[~2021-10-28 20:44 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-23  8:39 bug#50752: 28.0.50; easy-menu-define lowers the menu-bar key Shuguang Sun via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-23 17:15 ` Juri Linkov
2021-09-23 21:45 ` Lars Ingebrigtsen
2021-10-12 22:22   ` Stefan Kangas
2021-10-13 11:28     ` Lars Ingebrigtsen
2021-10-13 11:59     ` Eli Zaretskii
2021-10-13 12:04       ` Lars Ingebrigtsen
2021-10-13 12:19         ` Stefan Kangas
2021-10-13 12:58           ` Lars Ingebrigtsen
2021-10-13 15:26             ` Stefan Kangas
2021-10-13 15:42               ` Lars Ingebrigtsen
2021-10-19  3:22                 ` Stefan Kangas
2021-10-19  3:40                   ` Lars Ingebrigtsen
2021-10-19  3:52                     ` Lars Ingebrigtsen
2021-10-19 11:56                       ` Eli Zaretskii
2021-10-19 12:07                         ` Lars Ingebrigtsen
2021-10-19 12:17                           ` Lars Ingebrigtsen
2021-10-19 12:37                           ` Eli Zaretskii
2021-10-19 12:45                             ` Lars Ingebrigtsen
2021-10-19 13:24                               ` Lars Ingebrigtsen
2021-10-19 16:01                                 ` Eli Zaretskii
2021-10-19 15:41                               ` Eli Zaretskii
2021-10-19 15:57                                 ` Lars Ingebrigtsen
2021-10-19 16:12                                   ` Eli Zaretskii
2021-10-19 16:15                                     ` Lars Ingebrigtsen
2021-10-19 16:21                                     ` Lars Ingebrigtsen
2021-10-19 16:30                                       ` Eli Zaretskii
2021-10-19 17:12                                         ` Lars Ingebrigtsen
2021-10-19 17:37                                           ` Eli Zaretskii
2021-10-19 18:21                                             ` Lars Ingebrigtsen
2021-10-20 11:28                                               ` Eli Zaretskii
2021-10-20 11:55                                                 ` Glenn Morris
2021-10-24 20:11                                                   ` Stefan Kangas
2021-10-25 13:06                                                     ` Lars Ingebrigtsen
2021-10-25 13:19                                                       ` Eli Zaretskii
2021-10-25 13:21                                                         ` Lars Ingebrigtsen
2021-10-25 13:51                                                           ` Eli Zaretskii
2021-10-25 13:55                                                             ` Lars Ingebrigtsen
2021-10-25 14:12                                                               ` Eli Zaretskii
2021-10-26  8:38                                                                 ` Stefan Kangas
2021-10-26 13:04                                                                   ` Eli Zaretskii
2021-10-26 20:24                                                                     ` Stefan Kangas
2021-10-27 14:00                                                                       ` Eli Zaretskii
2021-10-28  5:29                                                                         ` Stefan Kangas
2021-10-28  7:33                                                                           ` Eli Zaretskii
2021-10-28  8:06                                                                             ` Stefan Kangas
2021-10-28  9:35                                                                               ` Eli Zaretskii
2021-10-28 10:49                                                                                 ` Stefan Kangas
2021-10-28 12:49                                                                                   ` Eli Zaretskii
2021-10-28 20:44                                                                                     ` Stefan Kangas
2021-10-21  2:45                                                 ` Lars Ingebrigtsen
2021-10-21  7:26                                                   ` Eli Zaretskii
2021-10-21 13:04                                                     ` Lars Ingebrigtsen
2021-10-20  7:45                                             ` Lars Ingebrigtsen
2021-10-20 12:24                                               ` Eli Zaretskii
2021-10-19 11:43                   ` Eli Zaretskii
2021-10-19 21:54                     ` Stefan Kangas
2021-10-20 12:59                       ` Eli Zaretskii
2021-10-13 16:09               ` Eli Zaretskii
2021-10-15  5:59       ` Eli Zaretskii
2021-10-15 18:34         ` Stefan Kangas
2021-10-19  3:18       ` Stefan Kangas
2021-09-23 22:28 ` Glenn Morris

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).