(read_minibuf_unwind): Clear last_overlay_modified field.
[bpt/emacs.git] / src / minibuf.c
index 94d0b84..de40403 100644 (file)
@@ -1,5 +1,5 @@
 /* Minibuffer input and completion.
-   Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 93, 94, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -46,9 +46,12 @@ Lisp_Object minibuf_save_list;
 /* Depth in minibuffer invocations.  */
 int minibuf_level;
 
-/* Nonzero means display completion help for invalid input */
+/* Nonzero means display completion help for invalid input */
 int auto_help;
 
+/* The maximum length of a minibuffer history.  */
+Lisp_Object Qhistory_length, Vhistory_length;
+
 /* Fread_minibuffer leaves the input here as a string. */
 Lisp_Object last_minibuf_string;
 
@@ -113,9 +116,6 @@ choose_minibuf_frame ()
   if (selected_frame != 0
       && !EQ (minibuf_window, selected_frame->minibuffer_window))
     {
-#if defined(MSDOS) && !defined(HAVE_X_WINDOWS)
-      selected_frame->minibuffer_window = minibuf_window;
-#else
       /* I don't think that any frames may validly have a null minibuffer
         window anymore.  */
       if (NILP (selected_frame->minibuffer_window))
@@ -124,9 +124,26 @@ choose_minibuf_frame ()
       Fset_window_buffer (selected_frame->minibuffer_window,
                          XWINDOW (minibuf_window)->buffer);
       minibuf_window = selected_frame->minibuffer_window;
-#endif
     }
 }
+
+DEFUN ("set-minibuffer-window", Fset_minibuffer_window,
+       Sset_minibuffer_window, 1, 1, 0,
+  "Specify which minibuffer window to use for the minibuffer.\n\
+This effects where the minibuffer is displayed if you put text in it\n\
+without invoking the usual minibuffer commands.")
+  (window)
+     Lisp_Object window;
+{
+  CHECK_WINDOW (window, 1);
+  if (! MINI_WINDOW_P (XWINDOW (window)))
+    error ("Window is not a minibuffer window");
+
+  minibuf_window = window;
+
+  return window;
+}
+
 \f
 /* Actual minibuffer invocation. */
 
@@ -157,42 +174,34 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
 {
   Lisp_Object val;
   int count = specpdl_ptr - specpdl;
-  Lisp_Object mini_frame;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  Lisp_Object mini_frame, ambient_dir;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
   single_kboard_state ();
 
   val = Qnil;
+  ambient_dir = current_buffer->directory;
+
   /* Don't need to protect PROMPT, HISTVAR, and HISTPOS because we
      store them away before we can GC.  Don't need to protect
      BACKUP_N because we use the value only if it is an integer.  */
-  GCPRO3 (map, initial, val);
+  GCPRO4 (map, initial, val, ambient_dir);
 
   if (!STRINGP (prompt))
     prompt = build_string ("");
 
   if (!enable_recursive_minibuffers
-      && minibuf_level > 0
-      && (EQ (selected_window, minibuf_window)))
-    error ("Command attempted to use minibuffer while in minibuffer");
-
-  /* Could we simply bind these variables instead?  */
-  minibuf_save_list
-    = Fcons (Voverriding_local_map,
-            Fcons (minibuf_window, minibuf_save_list));
-  minibuf_save_list
-    = Fcons (minibuf_prompt,
-            Fcons (make_number (minibuf_prompt_width),
-                   Fcons (Vhelp_form,
-                          Fcons (Vcurrent_prefix_arg,
-                                 Fcons (Vminibuffer_history_position,
-                                        Fcons (Vminibuffer_history_variable,
-                                               minibuf_save_list))))));
+      && minibuf_level > 0)
+    {
+      if (EQ (selected_window, minibuf_window))
+       error ("Command attempted to use minibuffer while in minibuffer");
+      else
+       /* If we're in another window, cancel the minibuffer that's active.  */
+       Fthrow (Qexit,
+               build_string ("Command attempted to use minibuffer while in minibuffer"));
+    }
 
-  minibuf_prompt_width = 0;    /* xdisp.c puts in the right value.  */
-  minibuf_prompt = Fcopy_sequence (prompt);
-  Vminibuffer_history_position = histpos;
-  Vminibuffer_history_variable = histvar;
+  /* Choose the minibuffer window and frame, and take action on them.  */
 
   choose_minibuf_frame ();
 
@@ -201,7 +210,6 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
 
   /* If the minibuffer window is on a different frame, save that
      frame's configuration too.  */
-#ifdef MULTI_FRAME
   mini_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
   if (XFRAME (mini_frame) != selected_frame)
     record_unwind_protect (Fset_window_configuration,
@@ -213,9 +221,38 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
 
   if (minibuffer_auto_raise)
     Fraise_frame (mini_frame);
-#endif
 
-  val = current_buffer->directory;
+  /* We have to do this after saving the window configuration
+     since that is what restores the current buffer.  */
+
+  /* Arrange to restore a number of minibuffer-related variables.
+     We could bind each variable separately, but that would use lots of
+     specpdl slots.  */
+  minibuf_save_list
+    = Fcons (Voverriding_local_map,
+            Fcons (minibuf_window, minibuf_save_list));
+  minibuf_save_list
+    = Fcons (minibuf_prompt,
+            Fcons (make_number (minibuf_prompt_width),
+                   Fcons (Vhelp_form,
+                          Fcons (Vcurrent_prefix_arg,
+                                 Fcons (Vminibuffer_history_position,
+                                        Fcons (Vminibuffer_history_variable,
+                                               minibuf_save_list))))));
+
+  record_unwind_protect (read_minibuf_unwind, Qnil);
+  minibuf_level++;
+
+  /* Now that we can restore all those variables, start changing them.  */
+
+  minibuf_prompt_width = 0;    /* xdisp.c puts in the right value.  */
+  minibuf_prompt = Fcopy_sequence (prompt);
+  Vminibuffer_history_position = histpos;
+  Vminibuffer_history_variable = histvar;
+  Vhelp_form = Vminibuffer_help_form;
+
+  /* Switch to the minibuffer.  */
+
   Fset_buffer (get_minibuffer (minibuf_level));
 
   /* The current buffer's default directory is usually the right thing
@@ -226,8 +263,8 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
      up Emacs and buf's default directory is Qnil.  Here's a hack; can
      you think of something better to do?  Find another buffer with a
      better directory, and use that one instead.  */
-  if (STRINGP (val))
-    current_buffer->directory = val;
+  if (STRINGP (ambient_dir))
+    current_buffer->directory = ambient_dir;
   else
     {
       Lisp_Object buf_list;
@@ -247,23 +284,26 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
        }
     }
 
-#ifdef MULTI_FRAME
   if (XFRAME (mini_frame) != selected_frame)
     Fredirect_frame_focus (Fselected_frame (), mini_frame);
-#endif
-  Fmake_local_variable (Qprint_escape_newlines);
-  print_escape_newlines = 1;
-
-  record_unwind_protect (read_minibuf_unwind, Qnil);
 
   Vminibuf_scroll_window = selected_window;
   Fset_window_buffer (minibuf_window, Fcurrent_buffer ());
   Fselect_window (minibuf_window);
   XSETFASTINT (XWINDOW (minibuf_window)->hscroll, 0);
 
-  Ferase_buffer ();
-  minibuf_level++;
+  Fmake_local_variable (Qprint_escape_newlines);
+  print_escape_newlines = 1;
+
+  /* Erase the buffer.  */
+  {
+    int count1 = specpdl_ptr - specpdl;
+    specbind (Qinhibit_read_only, Qt);
+    Ferase_buffer ();
+    unbind_to (count1, Qnil);
+  }
 
+  /* Put in the initial input.  */
   if (!NILP (initial))
     {
       Finsert (1, &initial);
@@ -275,12 +315,11 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
   /* This is in case the minibuffer-setup-hook calls Fsit_for.  */
   previous_echo_glyphs = 0;
 
-  Vhelp_form = Vminibuffer_help_form;
   current_buffer->keymap = map;
 
   /* Run our hook, but not if it is empty.
      (run-hooks would do nothing if it is empty,
-     but it's important to save time here in the usual case.  */
+     but it's important to save time here in the usual case).  */
   if (!NILP (Vminibuffer_setup_hook) && !EQ (Vminibuffer_setup_hook, Qunbound)
       && !NILP (Vrun_hooks))
     call1 (Vrun_hooks, Qminibuffer_setup_hook);
@@ -322,8 +361,27 @@ read_minibuf (map, initial, prompt, backup_n, expflag, histvar, histpos)
       if (NILP (histval)
          || (CONSP (histval)
              && NILP (Fequal (last_minibuf_string, Fcar (histval)))))
-       Fset (Vminibuffer_history_variable,
-             Fcons (last_minibuf_string, histval));
+       {
+         Lisp_Object length;
+
+         histval = Fcons (last_minibuf_string, histval);
+         Fset (Vminibuffer_history_variable, histval);
+
+         /* Truncate if requested.  */
+         length = Fget (Vminibuffer_history_variable, Qhistory_length);
+         if (NILP (length)) length = Vhistory_length;
+         if (INTEGERP (length)) {
+           if (XINT (length) <= 0)
+             Fset (Vminibuffer_history_variable, Qnil);
+           else
+             {
+               Lisp_Object temp;
+
+               temp = Fnthcdr (Fsub1 (length), histval);
+               if (CONSP (temp)) Fsetcdr (temp, Qnil);
+             }
+         }
+       }
     }
 
   /* If Lisp form desired instead of string, parse it. */
@@ -398,6 +456,7 @@ read_minibuf_unwind (data)
      Lisp_Object data;
 {
   Lisp_Object old_deactivate_mark;
+  Lisp_Object window;
 
   /* We are exiting the minibuffer one way or the other,
      so run the hook.  */
@@ -405,24 +464,16 @@ read_minibuf_unwind (data)
       && !NILP (Vrun_hooks))
     safe_run_hooks (Qminibuffer_exit_hook);
 
-  /* Erase the minibuffer we were using at this level.  */
-  Fset_buffer (XWINDOW (minibuf_window)->buffer);
-
-  /* Prevent error in erase-buffer.  */
-  current_buffer->read_only = Qnil;
-
-  old_deactivate_mark = Vdeactivate_mark;
-  Ferase_buffer ();
-  Vdeactivate_mark = old_deactivate_mark;
-
   /* If this was a recursive minibuffer,
-     tie the minibuffer window back to the outer level minibuffer buffer */
+     tie the minibuffer window back to the outer level minibuffer buffer */
   minibuf_level--;
-  /* Make sure minibuffer window is erased, not ignored */
-  windows_or_buffers_changed++;
-  XSETFASTINT (XWINDOW (minibuf_window)->last_modified, 0);
 
-  /* Restore prompt, etc from outer minibuffer */
+  window = minibuf_window;
+  /* To keep things predictable, in case it matters, let's be in the minibuffer
+     when we reset the relevant variables.  */
+  Fset_buffer (XWINDOW (window)->buffer);
+
+  /* Restore prompt, etc, from outer minibuffer level.  */
   minibuf_prompt = Fcar (minibuf_save_list);
   minibuf_save_list = Fcdr (minibuf_save_list);
   minibuf_prompt_width = XFASTINT (Fcar (minibuf_save_list));
@@ -439,6 +490,22 @@ read_minibuf_unwind (data)
   minibuf_save_list = Fcdr (minibuf_save_list);
   minibuf_window = Fcar (minibuf_save_list);
   minibuf_save_list = Fcdr (minibuf_save_list);
+
+  /* Erase the minibuffer we were using at this level.  */
+  {
+    int count = specpdl_ptr - specpdl;
+    /* Prevent error in erase-buffer.  */
+    specbind (Qinhibit_read_only, Qt);
+    old_deactivate_mark = Vdeactivate_mark;
+    Ferase_buffer ();
+    Vdeactivate_mark = old_deactivate_mark;
+    unbind_to (count, Qnil);
+  }
+
+  /* Make sure minibuffer window is erased, not ignored.  */
+  windows_or_buffers_changed++;
+  XSETFASTINT (XWINDOW (window)->last_modified, 0);
+  XSETFASTINT (XWINDOW (window)->last_overlay_modified, 0);
 }
 \f
 
@@ -451,7 +518,7 @@ DEFUN ("read-from-minibuffer", Fread_from_minibuffer, Sread_from_minibuffer, 1,
 If optional second arg INITIAL-CONTENTS is non-nil, it is a string\n\
   to be inserted into the minibuffer before reading input.\n\
   If INITIAL-CONTENTS is (STRING . POSITION), the initial input\n\
-  is STRING, but point is placed POSITION characters into the string.\n\
+  is STRING, but point is placed at position POSITION in the minibuffer.\n\
 Third arg KEYMAP is a keymap to use whilst reading;\n\
   if omitted or nil, the default is `minibuffer-local-map'.\n\
 If fourth arg READ is non-nil, then interpret the result as a lisp object\n\
@@ -489,7 +556,11 @@ DEFUN ("read-from-minibuffer", Fread_from_minibuffer, Sread_from_minibuffer, 1,
        {
          CHECK_NUMBER (position, 0);
          /* Convert to distance from end of input.  */
-         pos = XINT (position) - 1 - XSTRING (initial_contents)->size;
+         if (XINT (position) < 1)
+           /* A number too small means the beginning of the string.  */
+           pos =  - XSTRING (initial_contents)->size;
+         else
+           pos = XINT (position) - 1 - XSTRING (initial_contents)->size;
        }
     }
 
@@ -1407,6 +1478,7 @@ Return nil if there is no valid completion, else t.")
     register unsigned char *buffer_string;
     int buffer_length, completion_length;
 
+    CHECK_STRING (completion, 0);
     tem = Fbuffer_string ();
     GCPRO2 (completion, tem);
     /* If reading a file name,
@@ -1748,6 +1820,9 @@ syms_of_minibuf ()
   Qminibuffer_exit_hook = intern ("minibuffer-exit-hook");
   staticpro (&Qminibuffer_exit_hook);
 
+  Qhistory_length = intern ("history-length");
+  staticpro (&Qhistory_length);
+
   DEFVAR_LISP ("minibuffer-setup-hook", &Vminibuffer_setup_hook, 
     "Normal hook run just after entry to minibuffer.");
   Vminibuffer_setup_hook = Qnil;
@@ -1756,6 +1831,13 @@ syms_of_minibuf ()
     "Normal hook run just after exit from minibuffer.");
   Vminibuffer_exit_hook = Qnil;
 
+  DEFVAR_LISP ("history-length", &Vhistory_length,
+    "*Maximum length for history lists before truncation takes place.\n\
+A number means that length; t means infinite.  Truncation takes place\n\
+just after a new element is inserted.  Setting the history-length\n\
+property of a history variable overrides this default.");
+  XSETFASTINT (Vhistory_length, 30);
+
   DEFVAR_BOOL ("completion-auto-help", &auto_help,
     "*Non-nil means automatically provide help for invalid completion input.");
   auto_help = 1;
@@ -1817,6 +1899,7 @@ is added with\n\
     "List of regexps that should restrict possible completions.");
   Vcompletion_regexp_list = Qnil;
 
+  defsubr (&Sset_minibuffer_window);
   defsubr (&Sread_from_minibuffer);
   defsubr (&Seval_minibuffer);
   defsubr (&Sread_minibuffer);