Correct last commit which by mistake included some completely
authorKim F. Storm <storm@cua.dk>
Sun, 14 Jul 2002 22:52:48 +0000 (22:52 +0000)
committerKim F. Storm <storm@cua.dk>
Sun, 14 Jul 2002 22:52:48 +0000 (22:52 +0000)
unrelated changed.  Now it really only inverts the check
on Vmemory_full.

src/keyboard.c

index db9e9ad..6006d92 100644 (file)
@@ -660,11 +660,6 @@ Lisp_Object Vdisable_point_adjustment;
 
 Lisp_Object Vglobal_disable_point_adjustment;
 
-/* A function to display keyboard-menus, and read the user's response.
-   If nil, keyboard menus are disabled.  */
-
-Lisp_Object Vkey_menu_prompt_function;
-
 /* The time when Emacs started being idle.  */
 
 static EMACS_TIME timer_idleness_start_time;
@@ -7671,6 +7666,12 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   return Qnil ;
 }
 
+/* Buffer in use so far for the minibuf prompts for menu keymaps.
+   We make this bigger when necessary, and never free it.  */
+static char *read_char_minibuf_menu_text;
+/* Size of that buffer.  */
+static int read_char_minibuf_menu_width;
+
 static Lisp_Object
 read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
      int commandflag ;
@@ -7679,13 +7680,12 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
 {
   int mapno;
   register Lisp_Object name;
+  int nlength;
+  int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
   int idx = -1;
+  int nobindings = 1;
   Lisp_Object rest, vector;
-  /* This is a list of the prompt and individual menu entries passed to
-     lisp for formatting and display.  The format is:
-       MENU_LIST : (MENU_PROMPT ENTRY...)
-       ENTRY     : (EVENT PROMPT [BINDING [TOGGLE_TYPE TOGGLE_STATE]])   */
-  Lisp_Object menu_list = Qnil;
+  char *menu;
 
   vector = Qnil;
   name = Qnil;
@@ -7693,6 +7693,20 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   if (! menu_prompting)
     return Qnil;
 
+  /* Make sure we have a big enough buffer for the menu text.  */
+  if (read_char_minibuf_menu_text == 0)
+    {
+      read_char_minibuf_menu_width = width + 4;
+      read_char_minibuf_menu_text = (char *) xmalloc (width + 4);
+    }
+  else if (width + 4 > read_char_minibuf_menu_width)
+    {
+      read_char_minibuf_menu_width = width + 4;
+      read_char_minibuf_menu_text
+       = (char *) xrealloc (read_char_minibuf_menu_text, width + 4);
+    }
+  menu = read_char_minibuf_menu_text;
+
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
@@ -7705,109 +7719,204 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   if (!STRINGP (name))
     return Qnil;
 
+  /* Prompt string always starts with map's prompt, and a space.  */
+  strcpy (menu, XSTRING (name)->data);
+  nlength = STRING_BYTES (XSTRING (name));
+  menu[nlength++] = ':';
+  menu[nlength++] = ' ';
+  menu[nlength] = 0;
+
   /* Start prompting at start of first map.  */
   mapno = 0;
   rest = maps[mapno];
 
-  /* Loop over elements of map.  */
-  for (;;)
+  /* Present the documented bindings, a line at a time.  */
+  while (1)
     {
-      Lisp_Object elt;
+      int notfirst = 0;
+      int i = nlength;
+      Lisp_Object obj;
+      int ch;
+      Lisp_Object orig_defn_macro;
 
-      /* If reached end of map, start at beginning of next map.  */
-      if (NILP (rest))
+      /* Loop over elements of map.  */
+      while (i < width)
        {
-         mapno++;
-         if (mapno == nmaps)
-           /* Done with all maps.  */
-           break;
-         rest = maps[mapno];
-       }
+         Lisp_Object elt;
 
-      /* Look at the next element of the map.  */
-      if (idx >= 0)
-       elt = AREF (vector, idx);
-      else
-       elt = Fcar_safe (rest);
+         /* If reached end of map, start at beginning of next map.  */
+         if (NILP (rest))
+           {
+             mapno++;
+             /* At end of last map, wrap around to first map if just starting,
+                or end this line if already have something on it.  */
+             if (mapno == nmaps)
+               {
+                 mapno = 0;
+                 if (notfirst || nobindings) break;
+               }
+             rest = maps[mapno];
+           }
 
-      if (idx < 0 && VECTORP (elt))
-       {
-         /* If we found a dense table in the keymap,
-            advanced past it, but start scanning its contents.  */
-         rest = Fcdr_safe (rest);
-         vector = elt;
-         idx = 0;
-       }
-      else
-       {
-         /* An ordinary element.  */
-         Lisp_Object event, tem;
+         /* Look at the next element of the map.  */
+         if (idx >= 0)
+           elt = XVECTOR (vector)->contents[idx];
+         else
+           elt = Fcar_safe (rest);
 
-         if (idx < 0)
+         if (idx < 0 && VECTORP (elt))
            {
-             event = Fcar_safe (elt); /* alist */
-             elt = Fcdr_safe (elt);
+             /* If we found a dense table in the keymap,
+                advanced past it, but start scanning its contents.  */
+             rest = Fcdr_safe (rest);
+             vector = elt;
+             idx = 0;
            }
          else
            {
-             XSETINT (event, idx); /* vector */
-           }
+             /* An ordinary element.  */
+             Lisp_Object event, tem;
 
-         /* Ignore the element if it has no prompt string.  */
-         if (INTEGERP (event) && parse_menu_item (elt, 0, -1))
-           {
-             /* The list describing this entry.  */
-             Lisp_Object entry = Qnil;
-             Lisp_Object prop_val;
-
-             prop_val = AREF (item_properties, ITEM_PROPERTY_TYPE);
-             if (EQ (prop_val, QCradio) || EQ (prop_val, QCtoggle))
-               /* This is a `toggle-able' menu-entry, make the
-                  tail of the list describe it.  */
-               entry
-                 = Fcons (prop_val,
-                          Fcons (AREF (item_properties,
-                                       ITEM_PROPERTY_SELECTED),
-                                 entry));
-
-             /* Equivalent keybinding.  */
-             prop_val = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
-             if (!NILP (entry) || !NILP (prop_val))
-               entry = Fcons (prop_val, entry);
-
-             /* The string prompt.  */
-             prop_val = AREF (item_properties, ITEM_PROPERTY_NAME);
-             entry = Fcons (prop_val, entry);
-
-             /* Finally, the car of the list is the event.  */
-             entry = Fcons (event, entry);
-
-             /* Push this entry on the the list of entries.  */
-             menu_list = Fcons (entry, menu_list);
-           }
+             if (idx < 0)
+               {
+                 event = Fcar_safe (elt); /* alist */
+                 elt = Fcdr_safe (elt);
+               }
+             else
+               {
+                 XSETINT (event, idx); /* vector */
+               }
 
-         /* Move past this element.  */
-         if (idx >= 0 && idx + 1 >= XVECTOR (vector)->size)
-           /* Handle reaching end of dense table.  */
-           idx = -1;
-         if (idx >= 0)
-           idx++;
-         else
-           rest = Fcdr_safe (rest);
+             /* Ignore the element if it has no prompt string.  */
+             if (INTEGERP (event) && parse_menu_item (elt, 0, -1))
+               {
+                 /* 1 if the char to type matches the string.  */
+                 int char_matches;
+                 Lisp_Object upcased_event, downcased_event;
+                 Lisp_Object desc = Qnil;
+                 Lisp_Object s
+                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+
+                 upcased_event = Fupcase (event);
+                 downcased_event = Fdowncase (event);
+                 char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
+                                 || XINT (downcased_event) == XSTRING (s)->data[0]);
+                 if (! char_matches)
+                   desc = Fsingle_key_description (event, Qnil);
+
+#if 0  /* It is redundant to list the equivalent key bindings because
+         the prefix is what the user has already typed.  */
+                 tem
+                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+                 if (!NILP (tem))
+                   /* Insert equivalent keybinding. */
+                   s = concat2 (s, tem);
+#endif
+                 tem
+                   = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
+                 if (EQ (tem, QCradio) || EQ (tem, QCtoggle))
+                   {
+                     /* Insert button prefix. */
+                     Lisp_Object selected
+                       = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+                     if (EQ (tem, QCradio))
+                       tem = build_string (NILP (selected) ? "(*) " : "( ) ");
+                     else
+                       tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
+                     s = concat2 (tem, s);
+                   }
+                 
+
+                 /* If we have room for the prompt string, add it to this line.
+                    If this is the first on the line, always add it.  */
+                 if ((XSTRING (s)->size + i + 2
+                      + (char_matches ? 0 : XSTRING (desc)->size + 3))
+                     < width
+                     || !notfirst)
+                   {
+                     int thiswidth;
+
+                     /* Punctuate between strings.  */
+                     if (notfirst)
+                       {
+                         strcpy (menu + i, ", ");
+                         i += 2;
+                       }
+                     notfirst = 1;
+                     nobindings = 0 ;
+
+                     /* If the char to type doesn't match the string's
+                        first char, explicitly show what char to type.  */
+                     if (! char_matches)
+                       {
+                         /* Add as much of string as fits.  */
+                         thiswidth = XSTRING (desc)->size;
+                         if (thiswidth + i > width)
+                           thiswidth = width - i;
+                         bcopy (XSTRING (desc)->data, menu + i, thiswidth);
+                         i += thiswidth;
+                         strcpy (menu + i, " = ");
+                         i += 3;
+                       }
+
+                     /* Add as much of string as fits.  */
+                     thiswidth = XSTRING (s)->size;
+                     if (thiswidth + i > width)
+                       thiswidth = width - i;
+                     bcopy (XSTRING (s)->data, menu + i, thiswidth);
+                     i += thiswidth;
+                     menu[i] = 0;
+                   }
+                 else
+                   {
+                     /* If this element does not fit, end the line now,
+                        and save the element for the next line.  */
+                     strcpy (menu + i, "...");
+                     break;
+                   }
+               }
+
+             /* Move past this element.  */
+             if (idx >= 0 && idx + 1 >= XVECTOR (vector)->size)
+               /* Handle reaching end of dense table.  */
+               idx = -1;
+             if (idx >= 0)
+               idx++;
+             else
+               rest = Fcdr_safe (rest);
+           }
        }
-    }
 
-  /* Put the entries in the proper order for the display function.  */
-  menu_list = Fnreverse (menu_list);
+      /* Prompt with that and read response.  */
+      message2_nolog (menu, strlen (menu), 
+                     ! NILP (current_buffer->enable_multibyte_characters));
 
-  /* The car of the entries list is the prompt for the whole menu.  */
-  menu_list = Fcons (name, menu_list);
+      /* Make believe its not a keyboard macro in case the help char
+        is pressed.  Help characters are not recorded because menu prompting
+        is not used on replay.
+        */
+      orig_defn_macro = current_kboard->defining_kbd_macro;
+      current_kboard->defining_kbd_macro = Qnil;
+      do
+       obj = read_char (commandflag, 0, 0, Qt, 0);
+      while (BUFFERP (obj));
+      current_kboard->defining_kbd_macro = orig_defn_macro;
 
-  /* Display the menu, and prompt for a key.  */
-  if (NILP (Vkey_menu_prompt_function))
-    return Qnil;
-  else
-    return call1 (Vkey_menu_prompt_function, menu_list);
+      if (!INTEGERP (obj))
+       return obj;
+      else
+       ch = XINT (obj);
+
+      if (! EQ (obj, menu_prompt_more_char)
+         && (!INTEGERP (menu_prompt_more_char)
+             || ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char))))))
+       {
+         if (!NILP (current_kboard->defining_kbd_macro))
+           store_kbd_macro_char (obj);
+         return obj;
+       }
+      /* Help char - go round again */
+    }
 }
 \f
 /* Reading key sequences.  */
@@ -10903,23 +11012,6 @@ Used during Emacs' startup.  */);
               doc: /* *How long to display an echo-area message when the minibuffer is active.
 If the value is not a number, such messages don't time out.  */);
   Vminibuffer_message_timeout = make_number (2);
-
-  DEFVAR_LISP ("key-menu-prompt-function", &Vkey_menu_prompt_function,
-              doc: /* A function to display keyboard-menus, and read the user's response.
-If nil, keyboard menus are disabled.
-
-It is called with single argument, which is a list describing the keyboard menu
-and should return the key the user types.
-
-The argument is a list of the prompt and individual menu entries.
-The format is as follows:
-
-       MENU  : (PROMPT ENTRY...)
-       ENTRY : (EVENT PROMPT [BINDING [TOGGLE_TYPE TOGGLE_STATE]])
-
-Note that there is a prompt for the whole menu, and one for each
-individual entry.  */);
-  Vkey_menu_prompt_function = Qnil;
 }
 
 void