156160Sru/* echo-area.c -- how to read a line in the echo area.
2146515Sru   $Id: echo-area.c,v 1.7 2004/12/14 00:15:36 karl Exp $
342660Smarkm
4146515Sru   Copyright (C) 1993, 1997, 1998, 1999, 2001, 2004 Free Software
5146515Sru   Foundation, Inc.
642660Smarkm
742660Smarkm   This program is free software; you can redistribute it and/or modify
842660Smarkm   it under the terms of the GNU General Public License as published by
942660Smarkm   the Free Software Foundation; either version 2, or (at your option)
1042660Smarkm   any later version.
1142660Smarkm
1242660Smarkm   This program is distributed in the hope that it will be useful,
1342660Smarkm   but WITHOUT ANY WARRANTY; without even the implied warranty of
1442660Smarkm   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1542660Smarkm   GNU General Public License for more details.
1642660Smarkm
1742660Smarkm   You should have received a copy of the GNU General Public License
1842660Smarkm   along with this program; if not, write to the Free Software
1942660Smarkm   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2042660Smarkm
2142660Smarkm   Written by Brian Fox (bfox@ai.mit.edu). */
2242660Smarkm
2342660Smarkm#include "info.h"
2442660Smarkm
2542660Smarkm#if defined (FD_SET)
2642660Smarkm#  if defined (hpux)
2742660Smarkm#    define fd_set_cast(x) (int *)(x)
2842660Smarkm#  else
2942660Smarkm#    define fd_set_cast(x) (fd_set *)(x)
3042660Smarkm#  endif /* !hpux */
3142660Smarkm#endif /* FD_SET */
3242660Smarkm
3342660Smarkm/* Non-zero means that C-g was used to quit reading input. */
3442660Smarkmint info_aborted_echo_area = 0;
3542660Smarkm
3642660Smarkm/* Non-zero means that the echo area is being used to read input. */
3742660Smarkmint echo_area_is_active = 0;
3842660Smarkm
3942660Smarkm/* The address of the last command executed in the echo area. */
4042660SmarkmVFunction *ea_last_executed_command = (VFunction *)NULL;
4142660Smarkm
4242660Smarkm/* Non-zero means that the last command executed while reading input
4342660Smarkm   killed some text. */
4442660Smarkmint echo_area_last_command_was_kill = 0;
4542660Smarkm
4642660Smarkm/* Variables which hold on to the current state of the input line. */
4742660Smarkmstatic char input_line[1 + EA_MAX_INPUT];
4842660Smarkmstatic char *input_line_prompt;
4942660Smarkmstatic int input_line_point;
5042660Smarkmstatic int input_line_beg;
5142660Smarkmstatic int input_line_end;
5242660Smarkmstatic NODE input_line_node = {
53146515Sru  (char *)NULL, (char *)NULL, (char *)NULL, input_line,
54146515Sru  EA_MAX_INPUT, 0, N_IsInternal
5542660Smarkm};
5642660Smarkm
57146515Srustatic void echo_area_initialize_node (void);
58146515Srustatic void push_echo_area (void), pop_echo_area (void);
59146515Srustatic int echo_area_stack_contains_completions_p (void);
6042660Smarkm
61146515Srustatic void ea_kill_text (int from, int to);
6242660Smarkm
6342660Smarkm/* Non-zero means we force the user to complete. */
6442660Smarkmstatic int echo_area_must_complete_p = 0;
65146515Srustatic int completions_window_p (WINDOW *window);
6642660Smarkm
6742660Smarkm/* If non-null, this is a window which was specifically created to display
6842660Smarkm   possible completions output.  We remember it so we can delete it when
6942660Smarkm   appropriate. */
7042660Smarkmstatic WINDOW *echo_area_completions_window = (WINDOW *)NULL;
7142660Smarkm
7242660Smarkm/* Variables which keep track of the window which was active prior to
7342660Smarkm   entering the echo area. */
7442660Smarkmstatic WINDOW *calling_window = (WINDOW *)NULL;
7542660Smarkmstatic NODE *calling_window_node = (NODE *)NULL;
7642660Smarkmstatic long calling_window_point = 0;
7742660Smarkmstatic long calling_window_pagetop = 0;
7842660Smarkm
7942660Smarkm/* Remember the node and pertinent variables of the calling window. */
8042660Smarkmstatic void
81146515Sruremember_calling_window (WINDOW *window)
8242660Smarkm{
8342660Smarkm  /* Only do this if the calling window is not the completions window, or,
8442660Smarkm     if it is the completions window and there is no other window. */
8542660Smarkm  if (!completions_window_p (window) ||
8642660Smarkm      ((window == windows) && !(window->next)))
8742660Smarkm    {
8842660Smarkm      calling_window = window;
8942660Smarkm      calling_window_node = window->node;
9042660Smarkm      calling_window_point = window->point;
9142660Smarkm      calling_window_pagetop = window->pagetop;
9242660Smarkm    }
9342660Smarkm}
9442660Smarkm
9542660Smarkm/* Restore the caller's window so that it shows the node that it was showing
9642660Smarkm   on entry to info_read_xxx_echo_area (). */
9742660Smarkmstatic void
98146515Srurestore_calling_window (void)
9942660Smarkm{
10042660Smarkm  register WINDOW *win, *compwin = (WINDOW *)NULL;
10142660Smarkm
10242660Smarkm  /* If the calling window is still visible, and it is the window that
10342660Smarkm     we used for completions output, then restore the calling window. */
10442660Smarkm  for (win = windows; win; win = win->next)
10542660Smarkm    {
10642660Smarkm      if (completions_window_p (win))
10742660Smarkm        compwin = win;
10842660Smarkm
10942660Smarkm      if (win == calling_window && win == compwin)
11042660Smarkm        {
11142660Smarkm          window_set_node_of_window (calling_window, calling_window_node);
11242660Smarkm          calling_window->point = calling_window_point;
11342660Smarkm          calling_window->pagetop = calling_window_pagetop;
11442660Smarkm          compwin = (WINDOW *)NULL;
11542660Smarkm          break;
11642660Smarkm        }
11742660Smarkm    }
11842660Smarkm
11942660Smarkm  /* Delete the completions window if it is still present, it isn't the
12042660Smarkm     last window on the screen, and there aren't any prior echo area reads
12142660Smarkm     pending which created a completions window. */
12242660Smarkm  if (compwin)
12342660Smarkm    {
12442660Smarkm      if ((compwin != windows || windows->next) &&
12542660Smarkm          !echo_area_stack_contains_completions_p ())
12642660Smarkm        {
12742660Smarkm          WINDOW *next;
128146515Sru          int pagetop = 0;
129146515Sru          int start = 0;
130146515Sru          int end = 0;
131146515Sru          int amount = 0;
13242660Smarkm
13342660Smarkm          next = compwin->next;
13442660Smarkm          if (next)
13542660Smarkm            {
13642660Smarkm              start = next->first_row;
13742660Smarkm              end = start + next->height;
13842660Smarkm              amount = - (compwin->height + 1);
13942660Smarkm              pagetop = next->pagetop;
14042660Smarkm            }
14142660Smarkm
14242660Smarkm          info_delete_window_internal (compwin);
14342660Smarkm
14442660Smarkm          /* This is not necessary because info_delete_window_internal ()
14542660Smarkm             calls echo_area_inform_of_deleted_window (), which does the
14642660Smarkm             right thing. */
14742660Smarkm#if defined (UNNECESSARY)
14842660Smarkm          echo_area_completions_window = (WINDOW *)NULL;
14942660Smarkm#endif /* UNNECESSARY */
15042660Smarkm
15142660Smarkm          if (next)
15242660Smarkm            {
15342660Smarkm              display_scroll_display (start, end, amount);
15442660Smarkm              next->pagetop = pagetop;
15542660Smarkm              display_update_display (windows);
15642660Smarkm            }
15742660Smarkm        }
15842660Smarkm    }
15942660Smarkm}
16042660Smarkm
16142660Smarkm/* Set up a new input line with PROMPT. */
16242660Smarkmstatic void
163146515Sruinitialize_input_line (char *prompt)
16442660Smarkm{
16542660Smarkm  input_line_prompt = prompt;
16642660Smarkm  if (prompt)
16742660Smarkm    strcpy (input_line, prompt);
16842660Smarkm  else
16942660Smarkm    input_line[0] = '\0';
17042660Smarkm
17142660Smarkm  input_line_beg = input_line_end = input_line_point = strlen (prompt);
17242660Smarkm}
17342660Smarkm
17442660Smarkmstatic char *
175146515Sruecho_area_after_read (void)
17642660Smarkm{
17742660Smarkm  char *return_value;
17842660Smarkm
17942660Smarkm  if (info_aborted_echo_area)
18042660Smarkm    {
18142660Smarkm      info_aborted_echo_area = 0;
18242660Smarkm      return_value = (char *)NULL;
18342660Smarkm    }
18442660Smarkm  else
18542660Smarkm    {
18642660Smarkm      if (input_line_beg == input_line_end)
18742660Smarkm        return_value = xstrdup ("");
18842660Smarkm      else
18942660Smarkm        {
19042660Smarkm          int line_len = input_line_end - input_line_beg;
19142660Smarkm          return_value = (char *) xmalloc (1 + line_len);
19242660Smarkm          strncpy (return_value, &input_line[input_line_beg], line_len);
19342660Smarkm          return_value[line_len] = '\0';
19442660Smarkm        }
19542660Smarkm    }
19642660Smarkm  return (return_value);
19742660Smarkm}
19842660Smarkm
19942660Smarkm/* Read a line of text in the echo area.  Return a malloc ()'ed string,
20042660Smarkm   or NULL if the user aborted out of this read.  WINDOW is the currently
20142660Smarkm   active window, so that we can restore it when we need to.  PROMPT, if
20242660Smarkm   non-null, is a prompt to print before reading the line. */
20342660Smarkmchar *
204146515Sruinfo_read_in_echo_area (WINDOW *window, char *prompt)
20542660Smarkm{
20642660Smarkm  char *line;
20742660Smarkm
20842660Smarkm  /* If the echo area is already active, remember the current state. */
20942660Smarkm  if (echo_area_is_active)
21042660Smarkm    push_echo_area ();
21142660Smarkm
21242660Smarkm  /* Initialize our local variables. */
21342660Smarkm  initialize_input_line (prompt);
21442660Smarkm
21542660Smarkm  /* Initialize the echo area for the first (but maybe not the last) time. */
21642660Smarkm  echo_area_initialize_node ();
21742660Smarkm
21842660Smarkm  /* Save away the original node of this window, and the window itself,
21942660Smarkm     so echo area commands can temporarily use this window. */
22042660Smarkm  remember_calling_window (window);
22142660Smarkm
22242660Smarkm  /* Let the rest of Info know that the echo area is active. */
22342660Smarkm  echo_area_is_active++;
22442660Smarkm  active_window = the_echo_area;
22542660Smarkm
22642660Smarkm  /* Read characters in the echo area. */
22742660Smarkm  info_read_and_dispatch ();
22842660Smarkm
22942660Smarkm  echo_area_is_active--;
23042660Smarkm
23142660Smarkm  /* Restore the original active window and show point in it. */
23242660Smarkm  active_window = calling_window;
23342660Smarkm  restore_calling_window ();
23442660Smarkm  display_cursor_at_point (active_window);
23542660Smarkm  fflush (stdout);
23642660Smarkm
23742660Smarkm  /* Get the value of the line. */
23842660Smarkm  line = echo_area_after_read ();
23942660Smarkm
24042660Smarkm  /* If there is a previous loop waiting for us, restore it now. */
24142660Smarkm  if (echo_area_is_active)
24242660Smarkm    pop_echo_area ();
24342660Smarkm
24442660Smarkm  /* Return the results to the caller. */
24542660Smarkm  return (line);
24642660Smarkm}
24742660Smarkm
24842660Smarkm/* (re) Initialize the echo area node. */
24942660Smarkmstatic void
250146515Sruecho_area_initialize_node (void)
25142660Smarkm{
25242660Smarkm  register int i;
25342660Smarkm
254146515Sru  for (i = input_line_end; (unsigned int) i < sizeof (input_line); i++)
25542660Smarkm    input_line[i] = ' ';
25642660Smarkm
25742660Smarkm  input_line[i - 1] = '\n';
25842660Smarkm  window_set_node_of_window (the_echo_area, &input_line_node);
25942660Smarkm  input_line[input_line_end] = '\n';
26042660Smarkm}
26142660Smarkm
26242660Smarkm/* Prepare to read characters in the echo area.  This can initialize the
26342660Smarkm   echo area node, but its primary purpose is to side effect the input
26442660Smarkm   line buffer contents. */
26542660Smarkmvoid
266146515Sruecho_area_prep_read (void)
26742660Smarkm{
26842660Smarkm  if (the_echo_area->node != &input_line_node)
26942660Smarkm    echo_area_initialize_node ();
27042660Smarkm
27142660Smarkm  the_echo_area->point = input_line_point;
27242660Smarkm  input_line[input_line_end] = '\n';
27342660Smarkm  display_update_one_window (the_echo_area);
27442660Smarkm  display_cursor_at_point (active_window);
27542660Smarkm}
27642660Smarkm
27742660Smarkm
27842660Smarkm/* **************************************************************** */
27942660Smarkm/*                                                                  */
28042660Smarkm/*                   Echo Area Movement Commands                    */
28142660Smarkm/*                                                                  */
28242660Smarkm/* **************************************************************** */
28342660Smarkm
28442660SmarkmDECLARE_INFO_COMMAND (ea_forward, _("Move forward a character"))
28542660Smarkm{
28642660Smarkm  if (count < 0)
28742660Smarkm    ea_backward (window, -count, key);
28842660Smarkm  else
28942660Smarkm    {
29042660Smarkm      input_line_point += count;
29142660Smarkm      if (input_line_point > input_line_end)
29242660Smarkm        input_line_point = input_line_end;
29342660Smarkm    }
29442660Smarkm}
29542660Smarkm
29642660SmarkmDECLARE_INFO_COMMAND (ea_backward, _("Move backward a character"))
29742660Smarkm{
29842660Smarkm  if (count < 0)
29942660Smarkm    ea_forward (window, -count, key);
30042660Smarkm  else
30142660Smarkm    {
30242660Smarkm      input_line_point -= count;
30342660Smarkm      if (input_line_point < input_line_beg)
30442660Smarkm        input_line_point = input_line_beg;
30542660Smarkm    }
30642660Smarkm}
30742660Smarkm
30842660SmarkmDECLARE_INFO_COMMAND (ea_beg_of_line, _("Move to the start of this line"))
30942660Smarkm{
31042660Smarkm  input_line_point = input_line_beg;
31142660Smarkm}
31242660Smarkm
31342660SmarkmDECLARE_INFO_COMMAND (ea_end_of_line, _("Move to the end of this line"))
31442660Smarkm{
31542660Smarkm  input_line_point = input_line_end;
31642660Smarkm}
31742660Smarkm
31842660Smarkm#define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
31942660Smarkm
32042660Smarkm/* Move forward a word in the input line. */
32142660SmarkmDECLARE_INFO_COMMAND (ea_forward_word, _("Move forward a word"))
32242660Smarkm{
32342660Smarkm  int c;
32442660Smarkm
32542660Smarkm  if (count < 0)
32642660Smarkm    ea_backward_word (window, -count, key);
32742660Smarkm  else
32842660Smarkm    {
32942660Smarkm      while (count--)
33042660Smarkm        {
33142660Smarkm          if (input_line_point == input_line_end)
33242660Smarkm            return;
33342660Smarkm
33442660Smarkm          /* If we are not in a word, move forward until we are in one.
33542660Smarkm             Then, move forward until we hit a non-alphabetic character. */
33642660Smarkm          c = input_line[input_line_point];
33742660Smarkm
33842660Smarkm          if (!alphabetic (c))
33942660Smarkm            {
34042660Smarkm              while (++input_line_point < input_line_end)
34142660Smarkm                {
34242660Smarkm                  c = input_line[input_line_point];
34342660Smarkm                  if (alphabetic (c))
34442660Smarkm                    break;
34542660Smarkm                }
34642660Smarkm            }
34742660Smarkm
34842660Smarkm          if (input_line_point == input_line_end)
34942660Smarkm            return;
35042660Smarkm
35142660Smarkm          while (++input_line_point < input_line_end)
35242660Smarkm            {
35342660Smarkm              c = input_line[input_line_point];
35442660Smarkm              if (!alphabetic (c))
35542660Smarkm                break;
35642660Smarkm            }
35742660Smarkm        }
35842660Smarkm    }
35942660Smarkm}
36042660Smarkm
36142660SmarkmDECLARE_INFO_COMMAND (ea_backward_word, _("Move backward a word"))
36242660Smarkm{
36342660Smarkm  int c;
36442660Smarkm
36542660Smarkm  if (count < 0)
36642660Smarkm    ea_forward_word (window, -count, key);
36742660Smarkm  else
36842660Smarkm    {
36942660Smarkm      while (count--)
37042660Smarkm        {
37142660Smarkm          if (input_line_point == input_line_beg)
37242660Smarkm            return;
37342660Smarkm
37442660Smarkm          /* Like ea_forward_word (), except that we look at the
37542660Smarkm             characters just before point. */
37642660Smarkm
37742660Smarkm          c = input_line[input_line_point - 1];
37842660Smarkm
37942660Smarkm          if (!alphabetic (c))
38042660Smarkm            {
38142660Smarkm              while ((--input_line_point) != input_line_beg)
38242660Smarkm                {
38342660Smarkm                  c = input_line[input_line_point - 1];
38442660Smarkm                  if (alphabetic (c))
38542660Smarkm                    break;
38642660Smarkm                }
38742660Smarkm            }
38842660Smarkm
38942660Smarkm          while (input_line_point != input_line_beg)
39042660Smarkm            {
39142660Smarkm              c = input_line[input_line_point - 1];
39242660Smarkm              if (!alphabetic (c))
39342660Smarkm                break;
39442660Smarkm              else
39542660Smarkm                --input_line_point;
39642660Smarkm            }
39742660Smarkm        }
39842660Smarkm    }
39942660Smarkm}
40042660Smarkm
40142660SmarkmDECLARE_INFO_COMMAND (ea_delete, _("Delete the character under the cursor"))
40242660Smarkm{
40342660Smarkm  register int i;
40442660Smarkm
40542660Smarkm  if (count < 0)
40642660Smarkm    ea_rubout (window, -count, key);
40742660Smarkm  else
40842660Smarkm    {
40942660Smarkm      if (input_line_point == input_line_end)
41042660Smarkm        return;
41142660Smarkm
41242660Smarkm      if (info_explicit_arg || count > 1)
41342660Smarkm        {
41442660Smarkm          int orig_point;
41542660Smarkm
41642660Smarkm          orig_point = input_line_point;
41742660Smarkm          ea_forward (window, count, key);
41842660Smarkm          ea_kill_text (orig_point, input_line_point);
41942660Smarkm          input_line_point = orig_point;
42042660Smarkm        }
42142660Smarkm      else
42242660Smarkm        {
42342660Smarkm          for (i = input_line_point; i < input_line_end; i++)
42442660Smarkm            input_line[i] = input_line[i + 1];
42542660Smarkm
42642660Smarkm          input_line_end--;
42742660Smarkm        }
42842660Smarkm    }
42942660Smarkm}
43042660Smarkm
43142660SmarkmDECLARE_INFO_COMMAND (ea_rubout, _("Delete the character behind the cursor"))
43242660Smarkm{
43342660Smarkm  if (count < 0)
43442660Smarkm    ea_delete (window, -count, key);
43542660Smarkm  else
43642660Smarkm    {
43742660Smarkm      int start;
43842660Smarkm
43942660Smarkm      if (input_line_point == input_line_beg)
44042660Smarkm        return;
44142660Smarkm
44242660Smarkm      start = input_line_point;
44342660Smarkm      ea_backward (window, count, key);
44442660Smarkm
44542660Smarkm      if (info_explicit_arg || count > 1)
44642660Smarkm        ea_kill_text (start, input_line_point);
44742660Smarkm      else
44842660Smarkm        ea_delete (window, count, key);
44942660Smarkm    }
45042660Smarkm}
45142660Smarkm
45242660SmarkmDECLARE_INFO_COMMAND (ea_abort, _("Cancel or quit operation"))
45342660Smarkm{
45442660Smarkm  /* If any text, just discard it, and restore the calling window's node.
45542660Smarkm     If no text, quit. */
45642660Smarkm  if (input_line_end != input_line_beg)
45742660Smarkm    {
45842660Smarkm      terminal_ring_bell ();
45942660Smarkm      input_line_end = input_line_point = input_line_beg;
46042660Smarkm      if (calling_window->node != calling_window_node)
46142660Smarkm        restore_calling_window ();
46242660Smarkm    }
46342660Smarkm  else
46442660Smarkm    info_aborted_echo_area = 1;
46542660Smarkm}
46642660Smarkm
46742660SmarkmDECLARE_INFO_COMMAND (ea_newline, _("Accept (or force completion of) this line"))
46842660Smarkm{
46942660Smarkm  /* Stub does nothing.  Simply here to see if it has been executed. */
47042660Smarkm}
47142660Smarkm
47242660SmarkmDECLARE_INFO_COMMAND (ea_quoted_insert, _("Insert next character verbatim"))
47342660Smarkm{
47442660Smarkm  unsigned char character;
47542660Smarkm
47642660Smarkm  character = info_get_another_input_char ();
47742660Smarkm  ea_insert (window, count, character);
47842660Smarkm}
47942660Smarkm
48042660SmarkmDECLARE_INFO_COMMAND (ea_insert, _("Insert this character"))
48142660Smarkm{
48242660Smarkm  register int i;
48342660Smarkm
48442660Smarkm  if ((input_line_end + 1) == EA_MAX_INPUT)
48542660Smarkm    {
48642660Smarkm      terminal_ring_bell ();
48742660Smarkm      return;
48842660Smarkm    }
48942660Smarkm
49042660Smarkm  for (i = input_line_end + 1; i != input_line_point; i--)
49142660Smarkm    input_line[i] = input_line[i - 1];
49242660Smarkm
49342660Smarkm  input_line[input_line_point] = key;
49442660Smarkm  input_line_point++;
49542660Smarkm  input_line_end++;
49642660Smarkm}
49742660Smarkm
49842660SmarkmDECLARE_INFO_COMMAND (ea_tab_insert, _("Insert a TAB character"))
49942660Smarkm{
50042660Smarkm  ea_insert (window, count, '\t');
50142660Smarkm}
50242660Smarkm
50342660Smarkm/* Transpose the characters at point.  If point is at the end of the line,
50442660Smarkm   then transpose the characters before point. */
50542660SmarkmDECLARE_INFO_COMMAND (ea_transpose_chars, _("Transpose characters at point"))
50642660Smarkm{
50742660Smarkm  /* Handle conditions that would make it impossible to transpose
50842660Smarkm     characters. */
50942660Smarkm  if (!count || !input_line_point || (input_line_end - input_line_beg) < 2)
51042660Smarkm    return;
51142660Smarkm
51242660Smarkm  while (count)
51342660Smarkm    {
51442660Smarkm      int t;
51542660Smarkm      if (input_line_point == input_line_end)
51642660Smarkm        {
51742660Smarkm          t = input_line[input_line_point - 1];
51842660Smarkm
51942660Smarkm          input_line[input_line_point - 1] = input_line[input_line_point - 2];
52042660Smarkm          input_line[input_line_point - 2] = t;
52142660Smarkm        }
52242660Smarkm      else
52342660Smarkm        {
52442660Smarkm          t = input_line[input_line_point];
52542660Smarkm
52642660Smarkm          input_line[input_line_point] = input_line[input_line_point - 1];
52742660Smarkm          input_line[input_line_point - 1] = t;
52842660Smarkm
52942660Smarkm          if (count < 0 && input_line_point != input_line_beg)
53042660Smarkm            input_line_point--;
53142660Smarkm          else
53242660Smarkm            input_line_point++;
53342660Smarkm        }
53442660Smarkm
53542660Smarkm      if (count < 0)
53642660Smarkm        count++;
53742660Smarkm      else
53842660Smarkm        count--;
53942660Smarkm    }
54042660Smarkm}
54142660Smarkm
54242660Smarkm/* **************************************************************** */
54342660Smarkm/*                                                                  */
54442660Smarkm/*                   Echo Area Killing and Yanking                  */
54542660Smarkm/*                                                                  */
54642660Smarkm/* **************************************************************** */
54742660Smarkm
54842660Smarkmstatic char **kill_ring = (char **)NULL;
54942660Smarkmstatic int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
55042660Smarkmstatic int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
55142660Smarkmstatic int kill_ring_loc = 0;   /* Location of current yank pointer. */
55242660Smarkm
55342660Smarkm/* The largest number of kills that we remember at one time. */
55442660Smarkmstatic int max_retained_kills = 15;
55542660Smarkm
55642660SmarkmDECLARE_INFO_COMMAND (ea_yank, _("Yank back the contents of the last kill"))
55742660Smarkm{
55842660Smarkm  register int i;
55942660Smarkm  register char *text;
56042660Smarkm
56142660Smarkm  if (!kill_ring_index)
56242660Smarkm    {
563146515Sru      inform_in_echo_area ((char *) _("Kill ring is empty"));
56442660Smarkm      return;
56542660Smarkm    }
56642660Smarkm
56742660Smarkm  text = kill_ring[kill_ring_loc];
56842660Smarkm
56942660Smarkm  for (i = 0; text[i]; i++)
57042660Smarkm    ea_insert (window, 1, text[i]);
57142660Smarkm}
57242660Smarkm
57342660Smarkm/* If the last command was yank, or yank_pop, and the text just before
57442660Smarkm   point is identical to the current kill item, then delete that text
57542660Smarkm   from the line, rotate the index down, and yank back some other text. */
57642660SmarkmDECLARE_INFO_COMMAND (ea_yank_pop, _("Yank back a previous kill"))
57742660Smarkm{
57842660Smarkm  register int len;
57942660Smarkm
580146515Sru  if (((ea_last_executed_command != (VFunction *) ea_yank) &&
581146515Sru       (ea_last_executed_command != (VFunction *) ea_yank_pop)) ||
58242660Smarkm      (kill_ring_index == 0))
58342660Smarkm    return;
58442660Smarkm
58542660Smarkm  len = strlen (kill_ring[kill_ring_loc]);
58642660Smarkm
58742660Smarkm  /* Delete the last yanked item from the line. */
58842660Smarkm  {
58942660Smarkm    register int i, counter;
59042660Smarkm
59142660Smarkm    counter = input_line_end - input_line_point;
59242660Smarkm
59342660Smarkm    for (i = input_line_point - len; counter; i++, counter--)
59442660Smarkm      input_line[i] = input_line[i + len];
59542660Smarkm
59642660Smarkm    input_line_end -= len;
59742660Smarkm    input_line_point -= len;
59842660Smarkm  }
59942660Smarkm
60042660Smarkm  /* Get a previous kill, and yank that. */
60142660Smarkm  kill_ring_loc--;
60242660Smarkm  if (kill_ring_loc < 0)
60342660Smarkm    kill_ring_loc = kill_ring_index - 1;
60442660Smarkm
60542660Smarkm  ea_yank (window, count, key);
60642660Smarkm}
60742660Smarkm
60842660Smarkm/* Delete the text from point to end of line. */
60942660SmarkmDECLARE_INFO_COMMAND (ea_kill_line, _("Kill to the end of the line"))
61042660Smarkm{
61142660Smarkm  if (count < 0)
61242660Smarkm    {
61342660Smarkm      ea_kill_text (input_line_point, input_line_beg);
61442660Smarkm      input_line_point = input_line_beg;
61542660Smarkm    }
61642660Smarkm  else
61742660Smarkm    ea_kill_text (input_line_point, input_line_end);
61842660Smarkm}
61942660Smarkm
62042660Smarkm/* Delete the text from point to beg of line. */
62142660SmarkmDECLARE_INFO_COMMAND (ea_backward_kill_line,
62242660Smarkm                      _("Kill to the beginning of the line"))
62342660Smarkm{
62442660Smarkm  if (count < 0)
62542660Smarkm    ea_kill_text (input_line_point, input_line_end);
62642660Smarkm  else
62742660Smarkm    {
62842660Smarkm      ea_kill_text (input_line_point, input_line_beg);
62942660Smarkm      input_line_point = input_line_beg;
63042660Smarkm    }
63142660Smarkm}
63242660Smarkm
63342660Smarkm/* Delete from point to the end of the current word. */
63442660SmarkmDECLARE_INFO_COMMAND (ea_kill_word, _("Kill the word following the cursor"))
63542660Smarkm{
63642660Smarkm  int orig_point = input_line_point;
63742660Smarkm
63842660Smarkm  if (count < 0)
63942660Smarkm    ea_backward_kill_word (window, -count, key);
64042660Smarkm  else
64142660Smarkm    {
64242660Smarkm      ea_forward_word (window, count, key);
64342660Smarkm
64442660Smarkm      if (input_line_point != orig_point)
64542660Smarkm        ea_kill_text (orig_point, input_line_point);
64642660Smarkm
64742660Smarkm      input_line_point = orig_point;
64842660Smarkm    }
64942660Smarkm}
65042660Smarkm
65142660Smarkm/* Delete from point to the start of the current word. */
65242660SmarkmDECLARE_INFO_COMMAND (ea_backward_kill_word,
65342660Smarkm                      _("Kill the word preceding the cursor"))
65442660Smarkm{
65542660Smarkm  int orig_point = input_line_point;
65642660Smarkm
65742660Smarkm  if (count < 0)
65842660Smarkm    ea_kill_word (window, -count, key);
65942660Smarkm  else
66042660Smarkm    {
66142660Smarkm      ea_backward_word (window, count, key);
66242660Smarkm
66342660Smarkm      if (input_line_point != orig_point)
66442660Smarkm        ea_kill_text (orig_point, input_line_point);
66542660Smarkm    }
66642660Smarkm}
66742660Smarkm
66842660Smarkm/* The way to kill something.  This appends or prepends to the last
66942660Smarkm   kill, if the last command was a kill command.  If FROM is less
67042660Smarkm   than TO, then the killed text is appended to the most recent kill,
67142660Smarkm   otherwise it is prepended.  If the last command was not a kill command,
67242660Smarkm   then a new slot is made for this kill. */
67342660Smarkmstatic void
674146515Sruea_kill_text (int from, int to)
67542660Smarkm{
67642660Smarkm  register int i, counter, distance;
67742660Smarkm  int killing_backwards, slot;
67842660Smarkm  char *killed_text;
67942660Smarkm
68042660Smarkm  killing_backwards = (from > to);
68142660Smarkm
68242660Smarkm  /* If killing backwards, reverse the values of FROM and TO. */
68342660Smarkm  if (killing_backwards)
68442660Smarkm    {
68542660Smarkm      int temp = from;
68642660Smarkm      from = to;
68742660Smarkm      to = temp;
68842660Smarkm    }
68942660Smarkm
69042660Smarkm  /* Remember the text that we are about to delete. */
69142660Smarkm  distance = to - from;
69242660Smarkm  killed_text = (char *)xmalloc (1 + distance);
69342660Smarkm  strncpy (killed_text, &input_line[from], distance);
69442660Smarkm  killed_text[distance] = '\0';
69542660Smarkm
69642660Smarkm  /* Actually delete the text from the line. */
69742660Smarkm  counter = input_line_end - to;
69842660Smarkm
69942660Smarkm  for (i = from; counter; i++, counter--)
70042660Smarkm    input_line[i] = input_line[i + distance];
70142660Smarkm
70242660Smarkm  input_line_end -= distance;
70342660Smarkm
70442660Smarkm  /* If the last command was a kill, append or prepend the killed text to
70542660Smarkm     the last command's killed text. */
70642660Smarkm  if (echo_area_last_command_was_kill)
70742660Smarkm    {
70842660Smarkm      char *old, *new;
70942660Smarkm
71042660Smarkm      slot = kill_ring_loc;
71142660Smarkm      old = kill_ring[slot];
71242660Smarkm      new = (char *)xmalloc (1 + strlen (old) + strlen (killed_text));
71342660Smarkm
71442660Smarkm      if (killing_backwards)
71542660Smarkm        {
71642660Smarkm          /* Prepend TEXT to current kill. */
71742660Smarkm          strcpy (new, killed_text);
71842660Smarkm          strcat (new, old);
71942660Smarkm        }
72042660Smarkm      else
72142660Smarkm        {
72242660Smarkm          /* Append TEXT to current kill. */
72342660Smarkm          strcpy (new, old);
72442660Smarkm          strcat (new, killed_text);
72542660Smarkm        }
72642660Smarkm
72742660Smarkm      free (old);
72842660Smarkm      free (killed_text);
72942660Smarkm      kill_ring[slot] = new;
73042660Smarkm    }
73142660Smarkm  else
73242660Smarkm    {
73342660Smarkm      /* Try to store the kill in a new slot, unless that would cause there
73442660Smarkm         to be too many remembered kills. */
73542660Smarkm      slot = kill_ring_index;
73642660Smarkm
73742660Smarkm      if (slot == max_retained_kills)
73842660Smarkm        slot = 0;
73942660Smarkm
74042660Smarkm      if (slot + 1 > kill_ring_slots)
74142660Smarkm        kill_ring = (char **) xrealloc
74242660Smarkm          (kill_ring,
74342660Smarkm           (kill_ring_slots += max_retained_kills) * sizeof (char *));
74442660Smarkm
74542660Smarkm      if (slot != kill_ring_index)
74642660Smarkm        free (kill_ring[slot]);
74742660Smarkm      else
74842660Smarkm        kill_ring_index++;
74942660Smarkm
75042660Smarkm      kill_ring[slot] = killed_text;
75142660Smarkm
75242660Smarkm      kill_ring_loc = slot;
75342660Smarkm    }
75442660Smarkm
75542660Smarkm  /* Notice that the last command was a kill. */
75642660Smarkm  echo_area_last_command_was_kill++;
75742660Smarkm}
75842660Smarkm
75942660Smarkm/* **************************************************************** */
76042660Smarkm/*                                                                  */
76142660Smarkm/*                      Echo Area Completion                        */
76242660Smarkm/*                                                                  */
76342660Smarkm/* **************************************************************** */
76442660Smarkm
76542660Smarkm/* Pointer to an array of REFERENCE to complete over. */
76642660Smarkmstatic REFERENCE **echo_area_completion_items = (REFERENCE **)NULL;
76742660Smarkm
76842660Smarkm/* Sorted array of REFERENCE * which is the possible completions found in
76942660Smarkm   the variable echo_area_completion_items.  If there is only one element,
77042660Smarkm   it is the only possible completion. */
77142660Smarkmstatic REFERENCE **completions_found = (REFERENCE **)NULL;
77242660Smarkmstatic int completions_found_index = 0;
77342660Smarkmstatic int completions_found_slots = 0;
77442660Smarkm
77542660Smarkm/* The lowest common denominator found while completing. */
77642660Smarkmstatic REFERENCE *LCD_completion;
77742660Smarkm
77842660Smarkm/* Internal functions used by the user calls. */
779146515Srustatic void build_completions (void), completions_must_be_rebuilt (void);
78042660Smarkm
78142660Smarkm/* Variable which holds the output of completions. */
78242660Smarkmstatic NODE *possible_completions_output_node = (NODE *)NULL;
78342660Smarkm
78442660Smarkmstatic char *compwin_name = "*Completions*";
78542660Smarkm
78642660Smarkm/* Return non-zero if WINDOW is a window used for completions output. */
78742660Smarkmstatic int
788146515Srucompletions_window_p (WINDOW *window)
78942660Smarkm{
79042660Smarkm  int result = 0;
79142660Smarkm
79242660Smarkm  if (internal_info_node_p (window->node) &&
79342660Smarkm      (strcmp (window->node->nodename, compwin_name) == 0))
79442660Smarkm    result = 1;
79542660Smarkm
79642660Smarkm  return (result);
79742660Smarkm}
79842660Smarkm
79942660Smarkm/* Workhorse for completion readers.  If FORCE is non-zero, the user cannot
80042660Smarkm   exit unless the line read completes, or is empty. */
80142660Smarkmchar *
802146515Sruinfo_read_completing_internal (WINDOW *window, char *prompt,
803146515Sru    REFERENCE **completions, int force)
80442660Smarkm{
80542660Smarkm  char *line;
80642660Smarkm
80742660Smarkm  /* If the echo area is already active, remember the current state. */
80842660Smarkm  if (echo_area_is_active)
80942660Smarkm    push_echo_area ();
81042660Smarkm
81142660Smarkm  echo_area_must_complete_p = force;
81242660Smarkm
81342660Smarkm  /* Initialize our local variables. */
81442660Smarkm  initialize_input_line (prompt);
81542660Smarkm
81642660Smarkm  /* Initialize the echo area for the first (but maybe not the last) time. */
81742660Smarkm  echo_area_initialize_node ();
81842660Smarkm
81942660Smarkm  /* Save away the original node of this window, and the window itself,
82042660Smarkm     so echo area commands can temporarily use this window. */
82142660Smarkm  remember_calling_window (window);
82242660Smarkm
82342660Smarkm  /* Save away the list of items to complete over. */
82442660Smarkm  echo_area_completion_items = completions;
82542660Smarkm  completions_must_be_rebuilt ();
82642660Smarkm
82742660Smarkm  active_window = the_echo_area;
82842660Smarkm  echo_area_is_active++;
82942660Smarkm
83042660Smarkm  /* Read characters in the echo area. */
83142660Smarkm  while (1)
83242660Smarkm    {
83342660Smarkm      info_read_and_dispatch ();
83442660Smarkm
83542660Smarkm      line = echo_area_after_read ();
83642660Smarkm
83742660Smarkm      /* Force the completion to take place if the user hasn't accepted
83842660Smarkm         a default or aborted, and if FORCE is active. */
83942660Smarkm      if (force && line && *line && completions)
84042660Smarkm        {
84142660Smarkm          register int i;
84242660Smarkm
84342660Smarkm          build_completions ();
84442660Smarkm
84542660Smarkm          /* If there is only one completion, then make the line be that
84642660Smarkm             completion. */
84742660Smarkm          if (completions_found_index == 1)
84842660Smarkm            {
84942660Smarkm              free (line);
85042660Smarkm              line = xstrdup (completions_found[0]->label);
85142660Smarkm              break;
85242660Smarkm            }
85342660Smarkm
85442660Smarkm          /* If one of the completions matches exactly, then that is okay, so
85542660Smarkm             return the current line. */
85642660Smarkm          for (i = 0; i < completions_found_index; i++)
85742660Smarkm            if (strcasecmp (completions_found[i]->label, line) == 0)
85842660Smarkm              {
85942660Smarkm                free (line);
86042660Smarkm                line = xstrdup (completions_found[i]->label);
86142660Smarkm                break;
86242660Smarkm              }
86342660Smarkm
86442660Smarkm          /* If no match, go back and try again. */
86542660Smarkm          if (i == completions_found_index)
86642660Smarkm            {
86793139Sru              if (!completions_found_index)
868146515Sru                inform_in_echo_area ((char *) _("No completions"));
86993139Sru              else
870146515Sru                inform_in_echo_area ((char *) _("Not complete"));
87142660Smarkm              continue;
87242660Smarkm            }
87342660Smarkm        }
87442660Smarkm      break;
87542660Smarkm    }
87642660Smarkm  echo_area_is_active--;
87742660Smarkm
87842660Smarkm  /* Restore the original active window and show point in it. */
87942660Smarkm  active_window = calling_window;
88042660Smarkm  restore_calling_window ();
88142660Smarkm  display_cursor_at_point (active_window);
88242660Smarkm  fflush (stdout);
88342660Smarkm
88442660Smarkm  echo_area_completion_items = (REFERENCE **)NULL;
88542660Smarkm  completions_must_be_rebuilt ();
88642660Smarkm
88742660Smarkm  /* If there is a previous loop waiting for us, restore it now. */
88842660Smarkm  if (echo_area_is_active)
88942660Smarkm    pop_echo_area ();
89042660Smarkm
89142660Smarkm  return (line);
89242660Smarkm}
89342660Smarkm
89442660Smarkm/* Read a line in the echo area with completion over COMPLETIONS. */
89542660Smarkmchar *
896146515Sruinfo_read_completing_in_echo_area (WINDOW *window,
897146515Sru    char *prompt, REFERENCE **completions)
89842660Smarkm{
89942660Smarkm  return (info_read_completing_internal (window, prompt, completions, 1));
90042660Smarkm}
90142660Smarkm
90242660Smarkm/* Read a line in the echo area allowing completion over COMPLETIONS, but
90342660Smarkm   not requiring it. */
90442660Smarkmchar *
905146515Sruinfo_read_maybe_completing (WINDOW *window,
906146515Sru    char *prompt, REFERENCE **completions)
90742660Smarkm{
90842660Smarkm  return (info_read_completing_internal (window, prompt, completions, 0));
90942660Smarkm}
91042660Smarkm
91142660SmarkmDECLARE_INFO_COMMAND (ea_possible_completions, _("List possible completions"))
91242660Smarkm{
91342660Smarkm  if (!echo_area_completion_items)
91442660Smarkm    {
91542660Smarkm      ea_insert (window, count, key);
91642660Smarkm      return;
91742660Smarkm    }
91842660Smarkm
91942660Smarkm  build_completions ();
92042660Smarkm
92142660Smarkm  if (!completions_found_index)
92242660Smarkm    {
92342660Smarkm      terminal_ring_bell ();
924146515Sru      inform_in_echo_area ((char *) _("No completions"));
92542660Smarkm    }
92642660Smarkm  else if ((completions_found_index == 1) && (key != '?'))
92742660Smarkm    {
928146515Sru      inform_in_echo_area ((char *) _("Sole completion"));
92942660Smarkm    }
93042660Smarkm  else
93142660Smarkm    {
93242660Smarkm      register int i, l;
933146515Sru      int limit, iterations, max_label = 0;
93442660Smarkm
93542660Smarkm      initialize_message_buffer ();
93642660Smarkm      printf_to_message_buffer (completions_found_index == 1
937146515Sru                                ? (char *) _("One completion:\n")
938146515Sru                                : (char *) _("%d completions:\n"),
939146515Sru				(void *) (long) completions_found_index,
940146515Sru				NULL, NULL);
94142660Smarkm
94242660Smarkm      /* Find the maximum length of a label. */
94342660Smarkm      for (i = 0; i < completions_found_index; i++)
94442660Smarkm        {
94542660Smarkm          int len = strlen (completions_found[i]->label);
94642660Smarkm          if (len > max_label)
94742660Smarkm            max_label = len;
94842660Smarkm        }
94942660Smarkm
95042660Smarkm      max_label += 4;
95142660Smarkm
95242660Smarkm      /* Find out how many columns we should print in. */
95342660Smarkm      limit = calling_window->width / max_label;
95442660Smarkm      if (limit != 1 && (limit * max_label == calling_window->width))
95542660Smarkm        limit--;
95642660Smarkm
95742660Smarkm      /* Avoid a possible floating exception.  If max_label > width then
95842660Smarkm         the limit will be 0 and a divide-by-zero fault will result. */
95942660Smarkm      if (limit == 0)
96042660Smarkm        limit = 1;
96142660Smarkm
96242660Smarkm      /* How many iterations of the printing loop? */
963146515Sru      iterations = (completions_found_index + (limit - 1)) / limit;
96442660Smarkm
96542660Smarkm      /* Watch out for special case.  If the number of completions is less
96642660Smarkm         than LIMIT, then just do the inner printing loop. */
96742660Smarkm      if (completions_found_index < limit)
968146515Sru        iterations = 1;
96942660Smarkm
97042660Smarkm      /* Print the sorted items, up-and-down alphabetically. */
971146515Sru      for (i = 0; i < iterations; i++)
97242660Smarkm        {
97342660Smarkm          register int j;
97442660Smarkm
97542660Smarkm          for (j = 0, l = i; j < limit; j++)
97642660Smarkm            {
97742660Smarkm              if (l >= completions_found_index)
97842660Smarkm                break;
97942660Smarkm              else
98042660Smarkm                {
98142660Smarkm                  char *label;
98242660Smarkm                  int printed_length, k;
98342660Smarkm
98442660Smarkm                  label = completions_found[l]->label;
98542660Smarkm                  printed_length = strlen (label);
986146515Sru                  printf_to_message_buffer ("%s", label, NULL, NULL);
98742660Smarkm
98842660Smarkm                  if (j + 1 < limit)
98942660Smarkm                    {
99042660Smarkm                      for (k = 0; k < max_label - printed_length; k++)
991146515Sru                        printf_to_message_buffer (" ", NULL, NULL, NULL);
99242660Smarkm                    }
99342660Smarkm                }
994146515Sru              l += iterations;
99542660Smarkm            }
996146515Sru          printf_to_message_buffer ("\n", NULL, NULL, NULL);
99742660Smarkm        }
99842660Smarkm
99942660Smarkm      /* Make a new node to hold onto possible completions.  Don't destroy
100042660Smarkm         dangling pointers. */
100142660Smarkm      {
100242660Smarkm        NODE *temp;
100342660Smarkm
100442660Smarkm        temp = message_buffer_to_node ();
100542660Smarkm        add_gcable_pointer (temp->contents);
100642660Smarkm        name_internal_node (temp, compwin_name);
100742660Smarkm        possible_completions_output_node = temp;
100842660Smarkm      }
100942660Smarkm
101042660Smarkm      /* Find a suitable window for displaying the completions output.
101142660Smarkm         First choice is an existing window showing completions output.
101242660Smarkm         If there is only one window, and it is large, make another
101342660Smarkm         (smaller) window, and use that one.  Otherwise, use the caller's
101442660Smarkm         window. */
101542660Smarkm      {
101642660Smarkm        WINDOW *compwin;
101742660Smarkm
101842660Smarkm        compwin = get_internal_info_window (compwin_name);
101942660Smarkm
102042660Smarkm        if (!compwin)
102142660Smarkm          {
102242660Smarkm            /* If we can split the window to display most of the completion
102342660Smarkm               items, then do so. */
1024146515Sru            if (calling_window->height > (iterations * 2)
102542660Smarkm		&& calling_window->height / 2 >= WINDOW_MIN_SIZE)
102642660Smarkm              {
102742660Smarkm                int start, pagetop;
102842660Smarkm#ifdef SPLIT_BEFORE_ACTIVE
102942660Smarkm                int end;
103042660Smarkm#endif
103142660Smarkm
103242660Smarkm                active_window = calling_window;
103342660Smarkm
103442660Smarkm                /* Perhaps we can scroll this window on redisplay. */
103542660Smarkm                start = calling_window->first_row;
103642660Smarkm                pagetop = calling_window->pagetop;
103742660Smarkm
103842660Smarkm                compwin =
103942660Smarkm                  window_make_window (possible_completions_output_node);
104042660Smarkm                active_window = the_echo_area;
104142660Smarkm                window_change_window_height
1042146515Sru                  (compwin, -(compwin->height - (iterations + 2)));
104342660Smarkm
104442660Smarkm                window_adjust_pagetop (calling_window);
104542660Smarkm                remember_calling_window (calling_window);
104642660Smarkm
104742660Smarkm#if defined (SPLIT_BEFORE_ACTIVE)
104842660Smarkm                /* If the pagetop hasn't changed, scrolling the calling
104942660Smarkm                   window is a reasonable thing to do. */
105042660Smarkm                if (pagetop == calling_window->pagetop)
105142660Smarkm                  {
105242660Smarkm                    end = start + calling_window->height;
105342660Smarkm                    display_scroll_display
105442660Smarkm                      (start, end, calling_window->prev->height + 1);
105542660Smarkm                  }
105642660Smarkm#else /* !SPLIT_BEFORE_ACTIVE */
105742660Smarkm                /* If the pagetop has changed, set the new pagetop here. */
105842660Smarkm                if (pagetop != calling_window->pagetop)
105942660Smarkm                  {
106042660Smarkm                    int newtop = calling_window->pagetop;
106142660Smarkm                    calling_window->pagetop = pagetop;
106242660Smarkm                    set_window_pagetop (calling_window, newtop);
106342660Smarkm                  }
106442660Smarkm#endif /* !SPLIT_BEFORE_ACTIVE */
106542660Smarkm
106642660Smarkm                echo_area_completions_window = compwin;
106742660Smarkm                remember_window_and_node (compwin, compwin->node);
106842660Smarkm              }
106942660Smarkm            else
107042660Smarkm              compwin = calling_window;
107142660Smarkm          }
107242660Smarkm
107342660Smarkm        if (compwin->node != possible_completions_output_node)
107442660Smarkm          {
107542660Smarkm            window_set_node_of_window
107642660Smarkm              (compwin, possible_completions_output_node);
107742660Smarkm            remember_window_and_node (compwin, compwin->node);
107842660Smarkm          }
107942660Smarkm
108042660Smarkm        display_update_display (windows);
108142660Smarkm      }
108242660Smarkm    }
108342660Smarkm}
108442660Smarkm
108542660SmarkmDECLARE_INFO_COMMAND (ea_complete, _("Insert completion"))
108642660Smarkm{
108742660Smarkm  if (!echo_area_completion_items)
108842660Smarkm    {
108942660Smarkm      ea_insert (window, count, key);
109042660Smarkm      return;
109142660Smarkm    }
109242660Smarkm
109342660Smarkm  /* If KEY is SPC, and we are not forcing completion to take place, simply
109442660Smarkm     insert the key. */
109542660Smarkm  if (!echo_area_must_complete_p && key == SPC)
109642660Smarkm    {
109742660Smarkm      ea_insert (window, count, key);
109842660Smarkm      return;
109942660Smarkm    }
110042660Smarkm
1101146515Sru  if (ea_last_executed_command == (VFunction *) ea_complete)
110242660Smarkm    {
110342660Smarkm      /* If the keypress is a SPC character, and we have already tried
110442660Smarkm         completing once, and there are several completions, then check
110542660Smarkm         the batch of completions to see if any continue with a space.
110642660Smarkm         If there are some, insert the space character and continue. */
110742660Smarkm      if (key == SPC && completions_found_index > 1)
110842660Smarkm        {
110942660Smarkm          register int i, offset;
111042660Smarkm
111142660Smarkm          offset = input_line_end - input_line_beg;
111242660Smarkm
111342660Smarkm          for (i = 0; i < completions_found_index; i++)
111442660Smarkm            if (completions_found[i]->label[offset] == ' ')
111542660Smarkm              break;
111642660Smarkm
111742660Smarkm          if (completions_found[i])
111842660Smarkm            ea_insert (window, 1, ' ');
111942660Smarkm          else
112042660Smarkm            {
112142660Smarkm              ea_possible_completions (window, count, key);
112242660Smarkm              return;
112342660Smarkm            }
112442660Smarkm        }
112542660Smarkm      else
112642660Smarkm        {
112742660Smarkm          ea_possible_completions (window, count, key);
112842660Smarkm          return;
112942660Smarkm        }
113042660Smarkm    }
113142660Smarkm
113242660Smarkm  input_line_point = input_line_end;
113342660Smarkm  build_completions ();
113442660Smarkm
113542660Smarkm  if (!completions_found_index)
113642660Smarkm    terminal_ring_bell ();
113742660Smarkm  else if (LCD_completion->label[0] == '\0')
113842660Smarkm    ea_possible_completions (window, count, key);
113942660Smarkm  else
114042660Smarkm    {
114142660Smarkm      register int i;
114242660Smarkm      input_line_point = input_line_end = input_line_beg;
114342660Smarkm      for (i = 0; LCD_completion->label[i]; i++)
114442660Smarkm        ea_insert (window, 1, LCD_completion->label[i]);
114542660Smarkm    }
114642660Smarkm}
114742660Smarkm
114842660Smarkm/* Utility REFERENCE used to store possible LCD. */
1149146515Srustatic REFERENCE LCD_reference = {
1150146515Sru    (char *)NULL, (char *)NULL, (char *)NULL, 0, 0, 0
1151146515Sru};
115242660Smarkm
1153146515Srustatic void remove_completion_duplicates (void);
115442660Smarkm
115542660Smarkm/* Variables which remember the state of the most recent call
115642660Smarkm   to build_completions (). */
115742660Smarkmstatic char *last_completion_request = (char *)NULL;
115842660Smarkmstatic REFERENCE **last_completion_items = (REFERENCE **)NULL;
115942660Smarkm
116042660Smarkm/* How to tell the completion builder to reset internal state. */
116142660Smarkmstatic void
1162146515Srucompletions_must_be_rebuilt (void)
116342660Smarkm{
116442660Smarkm  maybe_free (last_completion_request);
116542660Smarkm  last_completion_request = (char *)NULL;
116642660Smarkm  last_completion_items = (REFERENCE **)NULL;
116742660Smarkm}
116842660Smarkm
116942660Smarkm/* Build a list of possible completions from echo_area_completion_items,
117042660Smarkm   and the contents of input_line. */
117142660Smarkmstatic void
1172146515Srubuild_completions (void)
117342660Smarkm{
117442660Smarkm  register int i, len;
117542660Smarkm  register REFERENCE *entry;
117642660Smarkm  char *request;
117742660Smarkm  int informed_of_lengthy_job = 0;
117842660Smarkm
117942660Smarkm  /* If there are no items to complete over, exit immediately. */
118042660Smarkm  if (!echo_area_completion_items)
118142660Smarkm    {
118242660Smarkm      completions_found_index = 0;
118342660Smarkm      LCD_completion = (REFERENCE *)NULL;
118442660Smarkm      return;
118542660Smarkm    }
118642660Smarkm
118742660Smarkm  /* Check to see if this call to build completions is the same as the last
118842660Smarkm     call to build completions. */
118942660Smarkm  len = input_line_end - input_line_beg;
119042660Smarkm  request = (char *)xmalloc (1 + len);
119142660Smarkm  strncpy (request, &input_line[input_line_beg], len);
119242660Smarkm  request[len] = '\0';
119342660Smarkm
119442660Smarkm  if (last_completion_request && last_completion_items &&
119542660Smarkm      last_completion_items == echo_area_completion_items &&
119642660Smarkm      (strcmp (last_completion_request, request) == 0))
119742660Smarkm    {
119842660Smarkm      free (request);
119942660Smarkm      return;
120042660Smarkm    }
120142660Smarkm
120242660Smarkm  maybe_free (last_completion_request);
120342660Smarkm  last_completion_request = request;
120442660Smarkm  last_completion_items = echo_area_completion_items;
120542660Smarkm
120642660Smarkm  /* Always start at the beginning of the list. */
120742660Smarkm  completions_found_index = 0;
120842660Smarkm  LCD_completion = (REFERENCE *)NULL;
120942660Smarkm
121042660Smarkm  for (i = 0; (entry = echo_area_completion_items[i]); i++)
121142660Smarkm    {
121242660Smarkm      if (strncasecmp (request, entry->label, len) == 0)
121342660Smarkm        add_pointer_to_array (entry, completions_found_index,
121442660Smarkm                              completions_found, completions_found_slots,
121542660Smarkm                              20, REFERENCE *);
121642660Smarkm
121742660Smarkm      if (!informed_of_lengthy_job && completions_found_index > 100)
121842660Smarkm        {
121942660Smarkm          informed_of_lengthy_job = 1;
1220146515Sru          window_message_in_echo_area ((char *) _("Building completions..."),
1221146515Sru              NULL, NULL);
122242660Smarkm        }
122342660Smarkm    }
122442660Smarkm
122542660Smarkm  if (!completions_found_index)
122642660Smarkm    return;
122742660Smarkm
122842660Smarkm  /* Sort and prune duplicate entries from the completions array. */
122942660Smarkm  remove_completion_duplicates ();
123042660Smarkm
123142660Smarkm  /* If there is only one completion, just return that. */
123242660Smarkm  if (completions_found_index == 1)
123342660Smarkm    {
123442660Smarkm      LCD_completion = completions_found[0];
123542660Smarkm      return;
123642660Smarkm    }
123742660Smarkm
123842660Smarkm  /* Find the least common denominator. */
123942660Smarkm  {
124042660Smarkm    long shortest = 100000;
124142660Smarkm
124242660Smarkm    for (i = 1; i < completions_found_index; i++)
124342660Smarkm      {
124442660Smarkm        register int j;
124542660Smarkm        int c1, c2;
124642660Smarkm
124742660Smarkm        for (j = 0;
124842660Smarkm             (c1 = info_tolower (completions_found[i - 1]->label[j])) &&
124942660Smarkm             (c2 = info_tolower (completions_found[i]->label[j]));
125042660Smarkm             j++)
125142660Smarkm          if (c1 != c2)
125242660Smarkm            break;
125342660Smarkm
125442660Smarkm        if (shortest > j)
125542660Smarkm          shortest = j;
125642660Smarkm      }
125742660Smarkm
125842660Smarkm    maybe_free (LCD_reference.label);
125942660Smarkm    LCD_reference.label = (char *)xmalloc (1 + shortest);
126093139Sru    /* Since both the sorting done inside remove_completion_duplicates
126193139Sru       and all the comparisons above are case-insensitive, it's
126293139Sru       possible that the completion we are going to return is
126393139Sru       identical to what the user typed but for the letter-case.  This
126493139Sru       is confusing, since the user could type FOOBAR<TAB> and get her
126593139Sru       string change letter-case for no good reason.  So try to find a
126693139Sru       possible completion whose letter-case is identical, and if so,
126793139Sru       use that.  */
126893139Sru    if (completions_found_index > 1)
126993139Sru      {
127093139Sru	int req_len = strlen (request);
127193139Sru
127293139Sru        for (i = 0; i < completions_found_index; i++)
127393139Sru          if (strncmp (request, completions_found[i]->label, req_len) == 0)
127493139Sru            break;
127593139Sru        /* If none of the candidates match exactly, use the first one.  */
127693139Sru        if (i >= completions_found_index)
127793139Sru          i = 0;
127893139Sru      }
127993139Sru    strncpy (LCD_reference.label, completions_found[i]->label, shortest);
128042660Smarkm    LCD_reference.label[shortest] = '\0';
128142660Smarkm    LCD_completion = &LCD_reference;
128242660Smarkm  }
128342660Smarkm
128442660Smarkm  if (informed_of_lengthy_job)
128542660Smarkm    echo_area_initialize_node ();
128642660Smarkm}
128742660Smarkm
128842660Smarkm/* Function called by qsort. */
128942660Smarkmstatic int
1290146515Srucompare_references (const void *entry1, const void *entry2)
129142660Smarkm{
1292146515Sru  REFERENCE **e1 = (REFERENCE **) entry1;
1293146515Sru  REFERENCE **e2 = (REFERENCE **) entry2;
1294146515Sru
1295146515Sru  return (strcasecmp ((*e1)->label, (*e2)->label));
129642660Smarkm}
129742660Smarkm
129842660Smarkm/* Prune duplicate entries from COMPLETIONS_FOUND. */
129942660Smarkmstatic void
1300146515Sruremove_completion_duplicates (void)
130142660Smarkm{
130242660Smarkm  register int i, j;
130342660Smarkm  REFERENCE **temp;
130442660Smarkm  int newlen;
130542660Smarkm
130642660Smarkm  if (!completions_found_index)
130742660Smarkm    return;
130842660Smarkm
130942660Smarkm  /* Sort the items. */
131042660Smarkm  qsort (completions_found, completions_found_index, sizeof (REFERENCE *),
131142660Smarkm         compare_references);
131242660Smarkm
131342660Smarkm  for (i = 0, newlen = 1; i < completions_found_index - 1; i++)
131442660Smarkm    {
131542660Smarkm      if (strcmp (completions_found[i]->label,
131642660Smarkm                  completions_found[i + 1]->label) == 0)
131742660Smarkm        completions_found[i] = (REFERENCE *)NULL;
131842660Smarkm      else
131942660Smarkm        newlen++;
132042660Smarkm    }
132142660Smarkm
132242660Smarkm  /* We have marked all the dead slots.  It is faster to copy the live slots
132342660Smarkm     twice than to prune the dead slots one by one. */
132442660Smarkm  temp = (REFERENCE **)xmalloc ((1 + newlen) * sizeof (REFERENCE *));
132542660Smarkm  for (i = 0, j = 0; i < completions_found_index; i++)
132642660Smarkm    if (completions_found[i])
132742660Smarkm      temp[j++] = completions_found[i];
132842660Smarkm
132942660Smarkm  for (i = 0; i < newlen; i++)
133042660Smarkm    completions_found[i] = temp[i];
133142660Smarkm
133242660Smarkm  completions_found[i] = (REFERENCE *)NULL;
133342660Smarkm  completions_found_index = newlen;
133442660Smarkm  free (temp);
133542660Smarkm}
133642660Smarkm
133742660Smarkm/* Scroll the "other" window.  If there is a window showing completions, scroll
133842660Smarkm   that one, otherwise scroll the window which was active on entering the read
133942660Smarkm   function. */
134042660SmarkmDECLARE_INFO_COMMAND (ea_scroll_completions_window, _("Scroll the completions window"))
134142660Smarkm{
134242660Smarkm  WINDOW *compwin;
134342660Smarkm  int old_pagetop;
134442660Smarkm
134542660Smarkm  compwin = get_internal_info_window (compwin_name);
134642660Smarkm
134742660Smarkm  if (!compwin)
134842660Smarkm    compwin = calling_window;
134942660Smarkm
135042660Smarkm  old_pagetop = compwin->pagetop;
135142660Smarkm
135242660Smarkm  /* Let info_scroll_forward () do the work, and print any messages that
135342660Smarkm     need to be displayed. */
135442660Smarkm  info_scroll_forward (compwin, count, key);
135542660Smarkm}
135642660Smarkm
135742660Smarkm/* Function which gets called when an Info window is deleted while the
135842660Smarkm   echo area is active.  WINDOW is the window which has just been deleted. */
135942660Smarkmvoid
1360146515Sruecho_area_inform_of_deleted_window (WINDOW *window)
136142660Smarkm{
136242660Smarkm  /* If this is the calling_window, forget what we remembered about it. */
136342660Smarkm  if (window == calling_window)
136442660Smarkm    {
136542660Smarkm      if (active_window != the_echo_area)
136642660Smarkm        remember_calling_window (active_window);
136742660Smarkm      else
136842660Smarkm        remember_calling_window (windows);
136942660Smarkm    }
137042660Smarkm
137142660Smarkm  /* If this window was the echo_area_completions_window, then notice that
137242660Smarkm     the window has been deleted. */
137342660Smarkm  if (window == echo_area_completions_window)
137442660Smarkm    echo_area_completions_window = (WINDOW *)NULL;
137542660Smarkm}
137642660Smarkm
137742660Smarkm/* **************************************************************** */
137842660Smarkm/*                                                                  */
137942660Smarkm/*                 Pushing and Popping the Echo Area                */
138042660Smarkm/*                                                                  */
138142660Smarkm/* **************************************************************** */
138242660Smarkm
138342660Smarkm/* Push and Pop the echo area. */
138442660Smarkmtypedef struct {
138542660Smarkm  char *line;
138642660Smarkm  char *prompt;
138742660Smarkm  REFERENCE **comp_items;
138842660Smarkm  int point, beg, end;
138942660Smarkm  int must_complete;
139042660Smarkm  NODE node;
139142660Smarkm  WINDOW *compwin;
139242660Smarkm} PUSHED_EA;
139342660Smarkm
139442660Smarkmstatic PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL;
139542660Smarkmstatic int pushed_echo_areas_index = 0;
139642660Smarkmstatic int pushed_echo_areas_slots = 0;
139742660Smarkm
139842660Smarkm/* Pushing the echo_area has a side effect of zeroing the completion_items. */
139942660Smarkmstatic void
1400146515Srupush_echo_area (void)
140142660Smarkm{
140242660Smarkm  PUSHED_EA *pushed;
140342660Smarkm
140442660Smarkm  pushed = (PUSHED_EA *)xmalloc (sizeof (PUSHED_EA));
140542660Smarkm  pushed->line = xstrdup (input_line);
140642660Smarkm  pushed->prompt = input_line_prompt;
140742660Smarkm  pushed->point = input_line_point;
140842660Smarkm  pushed->beg = input_line_beg;
140942660Smarkm  pushed->end = input_line_end;
141042660Smarkm  pushed->node = input_line_node;
141142660Smarkm  pushed->comp_items = echo_area_completion_items;
141242660Smarkm  pushed->must_complete = echo_area_must_complete_p;
141342660Smarkm  pushed->compwin = echo_area_completions_window;
141442660Smarkm
141542660Smarkm  add_pointer_to_array (pushed, pushed_echo_areas_index, pushed_echo_areas,
141642660Smarkm                        pushed_echo_areas_slots, 4, PUSHED_EA *);
141742660Smarkm
141842660Smarkm  echo_area_completion_items = (REFERENCE **)NULL;
141942660Smarkm}
142042660Smarkm
142142660Smarkmstatic void
1422146515Srupop_echo_area (void)
142342660Smarkm{
142442660Smarkm  PUSHED_EA *popped;
142542660Smarkm
142642660Smarkm  popped = pushed_echo_areas[--pushed_echo_areas_index];
142742660Smarkm
142842660Smarkm  strcpy (input_line, popped->line);
142942660Smarkm  free (popped->line);
143042660Smarkm  input_line_prompt = popped->prompt;
143142660Smarkm  input_line_point = popped->point;
143242660Smarkm  input_line_beg = popped->beg;
143342660Smarkm  input_line_end = popped->end;
143442660Smarkm  input_line_node = popped->node;
143542660Smarkm  echo_area_completion_items = popped->comp_items;
143642660Smarkm  echo_area_must_complete_p = popped->must_complete;
143742660Smarkm  echo_area_completions_window = popped->compwin;
143842660Smarkm  completions_must_be_rebuilt ();
143942660Smarkm
144042660Smarkm  /* If the completion window no longer exists, forget about it. */
144142660Smarkm  if (echo_area_completions_window)
144242660Smarkm    {
144342660Smarkm      register WINDOW *win;
144442660Smarkm
144542660Smarkm      for (win = windows; win; win = win->next)
144642660Smarkm        if (echo_area_completions_window == win)
144742660Smarkm          break;
144842660Smarkm
144942660Smarkm      /* If the window wasn't found, then it has already been deleted. */
145042660Smarkm      if (!win)
145142660Smarkm        echo_area_completions_window = (WINDOW *)NULL;
145242660Smarkm    }
145342660Smarkm
145442660Smarkm  free (popped);
145542660Smarkm}
145642660Smarkm
145742660Smarkm/* Returns non-zero if any of the prior stacked calls to read in the echo
145842660Smarkm   area produced a completions window. */
145942660Smarkmstatic int
1460146515Sruecho_area_stack_contains_completions_p (void)
146142660Smarkm{
146242660Smarkm  register int i;
146342660Smarkm
146442660Smarkm  for (i = 0; i < pushed_echo_areas_index; i++)
146542660Smarkm    if (pushed_echo_areas[i]->compwin)
146642660Smarkm      return (1);
146742660Smarkm
146842660Smarkm  return (0);
146942660Smarkm}
147042660Smarkm
147142660Smarkm/* **************************************************************** */
147242660Smarkm/*                                                                  */
147342660Smarkm/*             Error Messages While Reading in Echo Area            */
147442660Smarkm/*                                                                  */
147542660Smarkm/* **************************************************************** */
147642660Smarkm
147742660Smarkm#if defined (HAVE_SYS_TIME_H)
147842660Smarkm#  include <sys/time.h>
147942660Smarkm#  define HAVE_STRUCT_TIMEVAL
148042660Smarkm#endif /* HAVE_SYS_TIME_H */
148142660Smarkm
148242660Smarkmstatic void
1483146515Srupause_or_input (void)
148442660Smarkm{
148556160Sru#ifdef FD_SET
148642660Smarkm  struct timeval timer;
148742660Smarkm  fd_set readfds;
148842660Smarkm  int ready;
148942660Smarkm
149042660Smarkm  FD_ZERO (&readfds);
149142660Smarkm  FD_SET (fileno (stdin), &readfds);
149242660Smarkm  timer.tv_sec = 2;
149356160Sru  timer.tv_usec = 0;
149442660Smarkm  ready = select (fileno (stdin) + 1, &readfds, (fd_set *) NULL,
149542660Smarkm                  (fd_set *) NULL, &timer);
149642660Smarkm#endif /* FD_SET */
149742660Smarkm}
149842660Smarkm
149942660Smarkm/* Print MESSAGE right after the end of the current line, and wait
150056160Sru   for input or a couple of seconds, whichever comes first.  Then flush the
150142660Smarkm   informational message that was printed. */
150242660Smarkmvoid
1503146515Sruinform_in_echo_area (const char *message)
150442660Smarkm{
1505146515Sru  int i;
150642660Smarkm  char *text;
1507146515Sru  int avail = EA_MAX_INPUT + 1 - input_line_end;
150842660Smarkm
150942660Smarkm  text = xstrdup (message);
1510146515Sru  for (i = 0; text[i] && text[i] != '\n' && i < avail; i++)
151156160Sru    ;
151256160Sru  text[i] = 0;
151342660Smarkm
151442660Smarkm  echo_area_initialize_node ();
151542660Smarkm  sprintf (&input_line[input_line_end], "%s[%s]\n",
151642660Smarkm           echo_area_is_active ? " ": "", text);
151742660Smarkm  free (text);
151842660Smarkm  the_echo_area->point = input_line_point;
151942660Smarkm  display_update_one_window (the_echo_area);
152042660Smarkm  display_cursor_at_point (active_window);
152142660Smarkm  fflush (stdout);
152242660Smarkm  pause_or_input ();
152342660Smarkm  echo_area_initialize_node ();
152442660Smarkm}
1525