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