source: trunk/essentials/sys-apps/texinfo/info/echo-area.c

Last change on this file was 2619, checked in by bird, 19 years ago

applied OS/2 patches (manually).

File size: 43.9 KB
Line 
1/* echo-area.c -- how to read a line in the echo area.
2 $Id: echo-area.c,v 1.7 2004/12/14 00:15:36 karl Exp $
3
4 Copyright (C) 1993, 1997, 1998, 1999, 2001, 2004 Free Software
5 Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
21 Written by Brian Fox (bfox@ai.mit.edu). */
22
23#include "info.h"
24
25#if defined (FD_SET)
26# if defined (hpux)
27# define fd_set_cast(x) (int *)(x)
28# else
29# define fd_set_cast(x) (fd_set *)(x)
30# endif /* !hpux */
31#endif /* FD_SET */
32
33/* Non-zero means that C-g was used to quit reading input. */
34int info_aborted_echo_area = 0;
35
36/* Non-zero means that the echo area is being used to read input. */
37int echo_area_is_active = 0;
38
39/* The address of the last command executed in the echo area. */
40VFunction *ea_last_executed_command = (VFunction *)NULL;
41
42/* Non-zero means that the last command executed while reading input
43 killed some text. */
44int echo_area_last_command_was_kill = 0;
45
46/* Variables which hold on to the current state of the input line. */
47static char input_line[1 + EA_MAX_INPUT];
48static char *input_line_prompt;
49static int input_line_point;
50static int input_line_beg;
51static int input_line_end;
52static NODE input_line_node = {
53 (char *)NULL, (char *)NULL, (char *)NULL, input_line,
54 EA_MAX_INPUT, 0, N_IsInternal
55};
56
57static void echo_area_initialize_node (void);
58static void push_echo_area (void), pop_echo_area (void);
59static int echo_area_stack_contains_completions_p (void);
60
61static void ea_kill_text (int from, int to);
62
63/* Non-zero means we force the user to complete. */
64static int echo_area_must_complete_p = 0;
65static int completions_window_p (WINDOW *window);
66
67/* If non-null, this is a window which was specifically created to display
68 possible completions output. We remember it so we can delete it when
69 appropriate. */
70static WINDOW *echo_area_completions_window = (WINDOW *)NULL;
71
72/* Variables which keep track of the window which was active prior to
73 entering the echo area. */
74static WINDOW *calling_window = (WINDOW *)NULL;
75static NODE *calling_window_node = (NODE *)NULL;
76static long calling_window_point = 0;
77static long calling_window_pagetop = 0;
78
79/* Remember the node and pertinent variables of the calling window. */
80static void
81remember_calling_window (WINDOW *window)
82{
83 /* Only do this if the calling window is not the completions window, or,
84 if it is the completions window and there is no other window. */
85 if (!completions_window_p (window) ||
86 ((window == windows) && !(window->next)))
87 {
88 calling_window = window;
89 calling_window_node = window->node;
90 calling_window_point = window->point;
91 calling_window_pagetop = window->pagetop;
92 }
93}
94
95/* Restore the caller's window so that it shows the node that it was showing
96 on entry to info_read_xxx_echo_area (). */
97static void
98restore_calling_window (void)
99{
100 register WINDOW *win, *compwin = (WINDOW *)NULL;
101
102 /* If the calling window is still visible, and it is the window that
103 we used for completions output, then restore the calling window. */
104 for (win = windows; win; win = win->next)
105 {
106 if (completions_window_p (win))
107 compwin = win;
108
109 if (win == calling_window && win == compwin)
110 {
111 window_set_node_of_window (calling_window, calling_window_node);
112 calling_window->point = calling_window_point;
113 calling_window->pagetop = calling_window_pagetop;
114 compwin = (WINDOW *)NULL;
115 break;
116 }
117 }
118
119 /* Delete the completions window if it is still present, it isn't the
120 last window on the screen, and there aren't any prior echo area reads
121 pending which created a completions window. */
122 if (compwin)
123 {
124 if ((compwin != windows || windows->next) &&
125 !echo_area_stack_contains_completions_p ())
126 {
127 WINDOW *next;
128 int pagetop = 0;
129 int start = 0;
130 int end = 0;
131 int amount = 0;
132
133 next = compwin->next;
134 if (next)
135 {
136 start = next->first_row;
137 end = start + next->height;
138 amount = - (compwin->height + 1);
139 pagetop = next->pagetop;
140 }
141
142 info_delete_window_internal (compwin);
143
144 /* This is not necessary because info_delete_window_internal ()
145 calls echo_area_inform_of_deleted_window (), which does the
146 right thing. */
147#if defined (UNNECESSARY)
148 echo_area_completions_window = (WINDOW *)NULL;
149#endif /* UNNECESSARY */
150
151 if (next)
152 {
153 display_scroll_display (start, end, amount);
154 next->pagetop = pagetop;
155 display_update_display (windows);
156 }
157 }
158 }
159}
160
161/* Set up a new input line with PROMPT. */
162static void
163initialize_input_line (char *prompt)
164{
165 input_line_prompt = prompt;
166 if (prompt)
167 strcpy (input_line, prompt);
168 else
169 input_line[0] = '\0';
170
171 input_line_beg = input_line_end = input_line_point = strlen (prompt);
172}
173
174static char *
175echo_area_after_read (void)
176{
177 char *return_value;
178
179 if (info_aborted_echo_area)
180 {
181 info_aborted_echo_area = 0;
182 return_value = (char *)NULL;
183 }
184 else
185 {
186 if (input_line_beg == input_line_end)
187 return_value = xstrdup ("");
188 else
189 {
190 int line_len = input_line_end - input_line_beg;
191 return_value = (char *) xmalloc (1 + line_len);
192 strncpy (return_value, &input_line[input_line_beg], line_len);
193 return_value[line_len] = '\0';
194 }
195 }
196 return (return_value);
197}
198
199/* Read a line of text in the echo area. Return a malloc ()'ed string,
200 or NULL if the user aborted out of this read. WINDOW is the currently
201 active window, so that we can restore it when we need to. PROMPT, if
202 non-null, is a prompt to print before reading the line. */
203char *
204info_read_in_echo_area (WINDOW *window, char *prompt)
205{
206 char *line;
207
208 /* If the echo area is already active, remember the current state. */
209 if (echo_area_is_active)
210 push_echo_area ();
211
212 /* Initialize our local variables. */
213 initialize_input_line (prompt);
214
215 /* Initialize the echo area for the first (but maybe not the last) time. */
216 echo_area_initialize_node ();
217
218 /* Save away the original node of this window, and the window itself,
219 so echo area commands can temporarily use this window. */
220 remember_calling_window (window);
221
222 /* Let the rest of Info know that the echo area is active. */
223 echo_area_is_active++;
224 active_window = the_echo_area;
225
226 /* Read characters in the echo area. */
227 info_read_and_dispatch ();
228
229 echo_area_is_active--;
230
231 /* Restore the original active window and show point in it. */
232 active_window = calling_window;
233 restore_calling_window ();
234 display_cursor_at_point (active_window);
235 fflush (stdout);
236
237 /* Get the value of the line. */
238 line = echo_area_after_read ();
239
240 /* If there is a previous loop waiting for us, restore it now. */
241 if (echo_area_is_active)
242 pop_echo_area ();
243
244 /* Return the results to the caller. */
245 return (line);
246}
247
248/* (re) Initialize the echo area node. */
249static void
250echo_area_initialize_node (void)
251{
252 register int i;
253
254 for (i = input_line_end; (unsigned int) i < sizeof (input_line); i++)
255 input_line[i] = ' ';
256
257 input_line[i - 1] = '\n';
258 window_set_node_of_window (the_echo_area, &input_line_node);
259 input_line[input_line_end] = '\n';
260}
261
262/* Prepare to read characters in the echo area. This can initialize the
263 echo area node, but its primary purpose is to side effect the input
264 line buffer contents. */
265void
266echo_area_prep_read (void)
267{
268 if (the_echo_area->node != &input_line_node)
269 echo_area_initialize_node ();
270
271 the_echo_area->point = input_line_point;
272 input_line[input_line_end] = '\n';
273 display_update_one_window (the_echo_area);
274 display_cursor_at_point (active_window);
275}
276
277
278
279/* **************************************************************** */
280/* */
281/* Echo Area Movement Commands */
282/* */
283/* **************************************************************** */
284
285DECLARE_INFO_COMMAND (ea_forward, _("Move forward a character"))
286{
287 if (count < 0)
288 ea_backward (window, -count, key);
289 else
290 {
291 input_line_point += count;
292 if (input_line_point > input_line_end)
293 input_line_point = input_line_end;
294 }
295}
296
297DECLARE_INFO_COMMAND (ea_backward, _("Move backward a character"))
298{
299 if (count < 0)
300 ea_forward (window, -count, key);
301 else
302 {
303 input_line_point -= count;
304 if (input_line_point < input_line_beg)
305 input_line_point = input_line_beg;
306 }
307}
308
309DECLARE_INFO_COMMAND (ea_beg_of_line, _("Move to the start of this line"))
310{
311 input_line_point = input_line_beg;
312}
313
314DECLARE_INFO_COMMAND (ea_end_of_line, _("Move to the end of this line"))
315{
316 input_line_point = input_line_end;
317}
318
319#define alphabetic(c) (islower (c) || isupper (c) || isdigit (c))
320
321/* Move forward a word in the input line. */
322DECLARE_INFO_COMMAND (ea_forward_word, _("Move forward a word"))
323{
324 int c;
325
326 if (count < 0)
327 ea_backward_word (window, -count, key);
328 else
329 {
330 while (count--)
331 {
332 if (input_line_point == input_line_end)
333 return;
334
335 /* If we are not in a word, move forward until we are in one.
336 Then, move forward until we hit a non-alphabetic character. */
337 c = input_line[input_line_point];
338
339 if (!alphabetic (c))
340 {
341 while (++input_line_point < input_line_end)
342 {
343 c = input_line[input_line_point];
344 if (alphabetic (c))
345 break;
346 }
347 }
348
349 if (input_line_point == input_line_end)
350 return;
351
352 while (++input_line_point < input_line_end)
353 {
354 c = input_line[input_line_point];
355 if (!alphabetic (c))
356 break;
357 }
358 }
359 }
360}
361
362DECLARE_INFO_COMMAND (ea_backward_word, _("Move backward a word"))
363{
364 int c;
365
366 if (count < 0)
367 ea_forward_word (window, -count, key);
368 else
369 {
370 while (count--)
371 {
372 if (input_line_point == input_line_beg)
373 return;
374
375 /* Like ea_forward_word (), except that we look at the
376 characters just before point. */
377
378 c = input_line[input_line_point - 1];
379
380 if (!alphabetic (c))
381 {
382 while ((--input_line_point) != input_line_beg)
383 {
384 c = input_line[input_line_point - 1];
385 if (alphabetic (c))
386 break;
387 }
388 }
389
390 while (input_line_point != input_line_beg)
391 {
392 c = input_line[input_line_point - 1];
393 if (!alphabetic (c))
394 break;
395 else
396 --input_line_point;
397 }
398 }
399 }
400}
401
402DECLARE_INFO_COMMAND (ea_delete, _("Delete the character under the cursor"))
403{
404 register int i;
405
406 if (count < 0)
407 ea_rubout (window, -count, key);
408 else
409 {
410 if (input_line_point == input_line_end)
411 return;
412
413 if (info_explicit_arg || count > 1)
414 {
415 int orig_point;
416
417 orig_point = input_line_point;
418 ea_forward (window, count, key);
419 ea_kill_text (orig_point, input_line_point);
420 input_line_point = orig_point;
421 }
422 else
423 {
424 for (i = input_line_point; i < input_line_end; i++)
425 input_line[i] = input_line[i + 1];
426
427 input_line_end--;
428 }
429 }
430}
431
432DECLARE_INFO_COMMAND (ea_rubout, _("Delete the character behind the cursor"))
433{
434 if (count < 0)
435 ea_delete (window, -count, key);
436 else
437 {
438 int start;
439
440 if (input_line_point == input_line_beg)
441 return;
442
443 start = input_line_point;
444 ea_backward (window, count, key);
445
446 if (info_explicit_arg || count > 1)
447 ea_kill_text (start, input_line_point);
448 else
449 ea_delete (window, count, key);
450 }
451}
452
453DECLARE_INFO_COMMAND (ea_abort, _("Cancel or quit operation"))
454{
455 /* If any text, just discard it, and restore the calling window's node.
456 If no text, quit. */
457 if (input_line_end != input_line_beg)
458 {
459 terminal_ring_bell ();
460 input_line_end = input_line_point = input_line_beg;
461 if (calling_window->node != calling_window_node)
462 restore_calling_window ();
463 }
464 else
465 info_aborted_echo_area = 1;
466}
467
468DECLARE_INFO_COMMAND (ea_newline, _("Accept (or force completion of) this line"))
469{
470 /* Stub does nothing. Simply here to see if it has been executed. */
471}
472
473DECLARE_INFO_COMMAND (ea_quoted_insert, _("Insert next character verbatim"))
474{
475 unsigned char character;
476
477 character = info_get_another_input_char ();
478 ea_insert (window, count, character);
479}
480
481DECLARE_INFO_COMMAND (ea_insert, _("Insert this character"))
482{
483 register int i;
484
485 if ((input_line_end + 1) == EA_MAX_INPUT)
486 {
487 terminal_ring_bell ();
488 return;
489 }
490
491 for (i = input_line_end + 1; i != input_line_point; i--)
492 input_line[i] = input_line[i - 1];
493
494 input_line[input_line_point] = key;
495 input_line_point++;
496 input_line_end++;
497}
498
499DECLARE_INFO_COMMAND (ea_tab_insert, _("Insert a TAB character"))
500{
501 ea_insert (window, count, '\t');
502}
503
504/* Transpose the characters at point. If point is at the end of the line,
505 then transpose the characters before point. */
506DECLARE_INFO_COMMAND (ea_transpose_chars, _("Transpose characters at point"))
507{
508 /* Handle conditions that would make it impossible to transpose
509 characters. */
510 if (!count || !input_line_point || (input_line_end - input_line_beg) < 2)
511 return;
512
513 while (count)
514 {
515 int t;
516 if (input_line_point == input_line_end)
517 {
518 t = input_line[input_line_point - 1];
519
520 input_line[input_line_point - 1] = input_line[input_line_point - 2];
521 input_line[input_line_point - 2] = t;
522 }
523 else
524 {
525 t = input_line[input_line_point];
526
527 input_line[input_line_point] = input_line[input_line_point - 1];
528 input_line[input_line_point - 1] = t;
529
530 if (count < 0 && input_line_point != input_line_beg)
531 input_line_point--;
532 else
533 input_line_point++;
534 }
535
536 if (count < 0)
537 count++;
538 else
539 count--;
540 }
541}
542
543
544/* **************************************************************** */
545/* */
546/* Echo Area Killing and Yanking */
547/* */
548/* **************************************************************** */
549
550static char **kill_ring = (char **)NULL;
551static int kill_ring_index = 0; /* Number of kills appearing in KILL_RING. */
552static int kill_ring_slots = 0; /* Number of slots allocated to KILL_RING. */
553static int kill_ring_loc = 0; /* Location of current yank pointer. */
554
555/* The largest number of kills that we remember at one time. */
556static int max_retained_kills = 15;
557
558DECLARE_INFO_COMMAND (ea_yank, _("Yank back the contents of the last kill"))
559{
560 register int i;
561 register char *text;
562
563 if (!kill_ring_index)
564 {
565 inform_in_echo_area ((char *) _("Kill ring is empty"));
566 return;
567 }
568
569 text = kill_ring[kill_ring_loc];
570
571 for (i = 0; text[i]; i++)
572 ea_insert (window, 1, text[i]);
573}
574
575/* If the last command was yank, or yank_pop, and the text just before
576 point is identical to the current kill item, then delete that text
577 from the line, rotate the index down, and yank back some other text. */
578DECLARE_INFO_COMMAND (ea_yank_pop, _("Yank back a previous kill"))
579{
580 register int len;
581
582 if (((ea_last_executed_command != (VFunction *) ea_yank) &&
583 (ea_last_executed_command != (VFunction *) ea_yank_pop)) ||
584 (kill_ring_index == 0))
585 return;
586
587 len = strlen (kill_ring[kill_ring_loc]);
588
589 /* Delete the last yanked item from the line. */
590 {
591 register int i, counter;
592
593 counter = input_line_end - input_line_point;
594
595 for (i = input_line_point - len; counter; i++, counter--)
596 input_line[i] = input_line[i + len];
597
598 input_line_end -= len;
599 input_line_point -= len;
600 }
601
602 /* Get a previous kill, and yank that. */
603 kill_ring_loc--;
604 if (kill_ring_loc < 0)
605 kill_ring_loc = kill_ring_index - 1;
606
607 ea_yank (window, count, key);
608}
609
610/* Delete the text from point to end of line. */
611DECLARE_INFO_COMMAND (ea_kill_line, _("Kill to the end of the line"))
612{
613 if (count < 0)
614 {
615 ea_kill_text (input_line_point, input_line_beg);
616 input_line_point = input_line_beg;
617 }
618 else
619 ea_kill_text (input_line_point, input_line_end);
620}
621
622/* Delete the text from point to beg of line. */
623DECLARE_INFO_COMMAND (ea_backward_kill_line,
624 _("Kill to the beginning of the line"))
625{
626 if (count < 0)
627 ea_kill_text (input_line_point, input_line_end);
628 else
629 {
630 ea_kill_text (input_line_point, input_line_beg);
631 input_line_point = input_line_beg;
632 }
633}
634
635/* Delete from point to the end of the current word. */
636DECLARE_INFO_COMMAND (ea_kill_word, _("Kill the word following the cursor"))
637{
638 int orig_point = input_line_point;
639
640 if (count < 0)
641 ea_backward_kill_word (window, -count, key);
642 else
643 {
644 ea_forward_word (window, count, key);
645
646 if (input_line_point != orig_point)
647 ea_kill_text (orig_point, input_line_point);
648
649 input_line_point = orig_point;
650 }
651}
652
653/* Delete from point to the start of the current word. */
654DECLARE_INFO_COMMAND (ea_backward_kill_word,
655 _("Kill the word preceding the cursor"))
656{
657 int orig_point = input_line_point;
658
659 if (count < 0)
660 ea_kill_word (window, -count, key);
661 else
662 {
663 ea_backward_word (window, count, key);
664
665 if (input_line_point != orig_point)
666 ea_kill_text (orig_point, input_line_point);
667 }
668}
669
670/* The way to kill something. This appends or prepends to the last
671 kill, if the last command was a kill command. If FROM is less
672 than TO, then the killed text is appended to the most recent kill,
673 otherwise it is prepended. If the last command was not a kill command,
674 then a new slot is made for this kill. */
675static void
676ea_kill_text (int from, int to)
677{
678 register int i, counter, distance;
679 int killing_backwards, slot;
680 char *killed_text;
681
682 killing_backwards = (from > to);
683
684 /* If killing backwards, reverse the values of FROM and TO. */
685 if (killing_backwards)
686 {
687 int temp = from;
688 from = to;
689 to = temp;
690 }
691
692 /* Remember the text that we are about to delete. */
693 distance = to - from;
694 killed_text = (char *)xmalloc (1 + distance);
695 strncpy (killed_text, &input_line[from], distance);
696 killed_text[distance] = '\0';
697
698 /* Actually delete the text from the line. */
699 counter = input_line_end - to;
700
701 for (i = from; counter; i++, counter--)
702 input_line[i] = input_line[i + distance];
703
704 input_line_end -= distance;
705
706 /* If the last command was a kill, append or prepend the killed text to
707 the last command's killed text. */
708 if (echo_area_last_command_was_kill)
709 {
710 char *old, *new;
711
712 slot = kill_ring_loc;
713 old = kill_ring[slot];
714 new = (char *)xmalloc (1 + strlen (old) + strlen (killed_text));
715
716 if (killing_backwards)
717 {
718 /* Prepend TEXT to current kill. */
719 strcpy (new, killed_text);
720 strcat (new, old);
721 }
722 else
723 {
724 /* Append TEXT to current kill. */
725 strcpy (new, old);
726 strcat (new, killed_text);
727 }
728
729 free (old);
730 free (killed_text);
731 kill_ring[slot] = new;
732 }
733 else
734 {
735 /* Try to store the kill in a new slot, unless that would cause there
736 to be too many remembered kills. */
737 slot = kill_ring_index;
738
739 if (slot == max_retained_kills)
740 slot = 0;
741
742 if (slot + 1 > kill_ring_slots)
743 kill_ring = (char **) xrealloc
744 (kill_ring,
745 (kill_ring_slots += max_retained_kills) * sizeof (char *));
746
747 if (slot != kill_ring_index)
748 free (kill_ring[slot]);
749 else
750 kill_ring_index++;
751
752 kill_ring[slot] = killed_text;
753
754 kill_ring_loc = slot;
755 }
756
757 /* Notice that the last command was a kill. */
758 echo_area_last_command_was_kill++;
759}
760
761
762/* **************************************************************** */
763/* */
764/* Echo Area Completion */
765/* */
766/* **************************************************************** */
767
768/* Pointer to an array of REFERENCE to complete over. */
769static REFERENCE **echo_area_completion_items = (REFERENCE **)NULL;
770
771/* Sorted array of REFERENCE * which is the possible completions found in
772 the variable echo_area_completion_items. If there is only one element,
773 it is the only possible completion. */
774static REFERENCE **completions_found = (REFERENCE **)NULL;
775static int completions_found_index = 0;
776static int completions_found_slots = 0;
777
778/* The lowest common denominator found while completing. */
779static REFERENCE *LCD_completion;
780
781/* Internal functions used by the user calls. */
782static void build_completions (void), completions_must_be_rebuilt (void);
783
784/* Variable which holds the output of completions. */
785static NODE *possible_completions_output_node = (NODE *)NULL;
786
787static char *compwin_name = "*Completions*";
788
789/* Return non-zero if WINDOW is a window used for completions output. */
790static int
791completions_window_p (WINDOW *window)
792{
793 int result = 0;
794
795 if (internal_info_node_p (window->node) &&
796 (strcmp (window->node->nodename, compwin_name) == 0))
797 result = 1;
798
799 return (result);
800}
801
802/* Workhorse for completion readers. If FORCE is non-zero, the user cannot
803 exit unless the line read completes, or is empty. */
804char *
805info_read_completing_internal (WINDOW *window, char *prompt,
806 REFERENCE **completions, int force)
807{
808 char *line;
809
810 /* If the echo area is already active, remember the current state. */
811 if (echo_area_is_active)
812 push_echo_area ();
813
814 echo_area_must_complete_p = force;
815
816 /* Initialize our local variables. */
817 initialize_input_line (prompt);
818
819 /* Initialize the echo area for the first (but maybe not the last) time. */
820 echo_area_initialize_node ();
821
822 /* Save away the original node of this window, and the window itself,
823 so echo area commands can temporarily use this window. */
824 remember_calling_window (window);
825
826 /* Save away the list of items to complete over. */
827 echo_area_completion_items = completions;
828 completions_must_be_rebuilt ();
829
830 active_window = the_echo_area;
831 echo_area_is_active++;
832
833 /* Read characters in the echo area. */
834 while (1)
835 {
836 info_read_and_dispatch ();
837
838 line = echo_area_after_read ();
839
840 /* Force the completion to take place if the user hasn't accepted
841 a default or aborted, and if FORCE is active. */
842 if (force && line && *line && completions)
843 {
844 register int i;
845
846 build_completions ();
847
848 /* If there is only one completion, then make the line be that
849 completion. */
850 if (completions_found_index == 1)
851 {
852 free (line);
853 line = xstrdup (completions_found[0]->label);
854 break;
855 }
856
857 /* If one of the completions matches exactly, then that is okay, so
858 return the current line. */
859 for (i = 0; i < completions_found_index; i++)
860 if (strcasecmp (completions_found[i]->label, line) == 0)
861 {
862 free (line);
863 line = xstrdup (completions_found[i]->label);
864 break;
865 }
866
867 /* If no match, go back and try again. */
868 if (i == completions_found_index)
869 {
870 if (!completions_found_index)
871 inform_in_echo_area ((char *) _("No completions"));
872 else
873 inform_in_echo_area ((char *) _("Not complete"));
874 continue;
875 }
876 }
877 break;
878 }
879 echo_area_is_active--;
880
881 /* Restore the original active window and show point in it. */
882 active_window = calling_window;
883 restore_calling_window ();
884 display_cursor_at_point (active_window);
885 fflush (stdout);
886
887 echo_area_completion_items = (REFERENCE **)NULL;
888 completions_must_be_rebuilt ();
889
890 /* If there is a previous loop waiting for us, restore it now. */
891 if (echo_area_is_active)
892 pop_echo_area ();
893
894 return (line);
895}
896
897/* Read a line in the echo area with completion over COMPLETIONS. */
898char *
899info_read_completing_in_echo_area (WINDOW *window,
900 char *prompt, REFERENCE **completions)
901{
902 return (info_read_completing_internal (window, prompt, completions, 1));
903}
904
905/* Read a line in the echo area allowing completion over COMPLETIONS, but
906 not requiring it. */
907char *
908info_read_maybe_completing (WINDOW *window,
909 char *prompt, REFERENCE **completions)
910{
911 return (info_read_completing_internal (window, prompt, completions, 0));
912}
913
914DECLARE_INFO_COMMAND (ea_possible_completions, _("List possible completions"))
915{
916 if (!echo_area_completion_items)
917 {
918 ea_insert (window, count, key);
919 return;
920 }
921
922 build_completions ();
923
924 if (!completions_found_index)
925 {
926 terminal_ring_bell ();
927 inform_in_echo_area ((char *) _("No completions"));
928 }
929 else if ((completions_found_index == 1) && (key != '?'))
930 {
931 inform_in_echo_area ((char *) _("Sole completion"));
932 }
933 else
934 {
935 register int i, l;
936 int limit, iterations, max_label = 0;
937
938 initialize_message_buffer ();
939 printf_to_message_buffer (completions_found_index == 1
940 ? (char *) _("One completion:\n")
941 : (char *) _("%d completions:\n"),
942 (void *) (long) completions_found_index,
943 NULL, NULL);
944
945 /* Find the maximum length of a label. */
946 for (i = 0; i < completions_found_index; i++)
947 {
948 int len = strlen (completions_found[i]->label);
949 if (len > max_label)
950 max_label = len;
951 }
952
953 max_label += 4;
954
955 /* Find out how many columns we should print in. */
956 limit = calling_window->width / max_label;
957 if (limit != 1 && (limit * max_label == calling_window->width))
958 limit--;
959
960 /* Avoid a possible floating exception. If max_label > width then
961 the limit will be 0 and a divide-by-zero fault will result. */
962 if (limit == 0)
963 limit = 1;
964
965 /* How many iterations of the printing loop? */
966 iterations = (completions_found_index + (limit - 1)) / limit;
967
968 /* Watch out for special case. If the number of completions is less
969 than LIMIT, then just do the inner printing loop. */
970 if (completions_found_index < limit)
971 iterations = 1;
972
973 /* Print the sorted items, up-and-down alphabetically. */
974 for (i = 0; i < iterations; i++)
975 {
976 register int j;
977
978 for (j = 0, l = i; j < limit; j++)
979 {
980 if (l >= completions_found_index)
981 break;
982 else
983 {
984 char *label;
985 int printed_length, k;
986
987 label = completions_found[l]->label;
988 printed_length = strlen (label);
989 printf_to_message_buffer ("%s", label, NULL, NULL);
990
991 if (j + 1 < limit)
992 {
993 for (k = 0; k < max_label - printed_length; k++)
994 printf_to_message_buffer (" ", NULL, NULL, NULL);
995 }
996 }
997 l += iterations;
998 }
999 printf_to_message_buffer ("\n", NULL, NULL, NULL);
1000 }
1001
1002 /* Make a new node to hold onto possible completions. Don't destroy
1003 dangling pointers. */
1004 {
1005 NODE *temp;
1006
1007 temp = message_buffer_to_node ();
1008 add_gcable_pointer (temp->contents);
1009 name_internal_node (temp, compwin_name);
1010 possible_completions_output_node = temp;
1011 }
1012
1013 /* Find a suitable window for displaying the completions output.
1014 First choice is an existing window showing completions output.
1015 If there is only one window, and it is large, make another
1016 (smaller) window, and use that one. Otherwise, use the caller's
1017 window. */
1018 {
1019 WINDOW *compwin;
1020
1021 compwin = get_internal_info_window (compwin_name);
1022
1023 if (!compwin)
1024 {
1025 /* If we can split the window to display most of the completion
1026 items, then do so. */
1027 if (calling_window->height > (iterations * 2)
1028 && calling_window->height / 2 >= WINDOW_MIN_SIZE)
1029 {
1030 int start, pagetop;
1031#ifdef SPLIT_BEFORE_ACTIVE
1032 int end;
1033#endif
1034
1035 active_window = calling_window;
1036
1037 /* Perhaps we can scroll this window on redisplay. */
1038 start = calling_window->first_row;
1039 pagetop = calling_window->pagetop;
1040
1041 compwin =
1042 window_make_window (possible_completions_output_node);
1043 active_window = the_echo_area;
1044 window_change_window_height
1045 (compwin, -(compwin->height - (iterations + 2)));
1046
1047 window_adjust_pagetop (calling_window);
1048 remember_calling_window (calling_window);
1049
1050#if defined (SPLIT_BEFORE_ACTIVE)
1051 /* If the pagetop hasn't changed, scrolling the calling
1052 window is a reasonable thing to do. */
1053 if (pagetop == calling_window->pagetop)
1054 {
1055 end = start + calling_window->height;
1056 display_scroll_display
1057 (start, end, calling_window->prev->height + 1);
1058 }
1059#else /* !SPLIT_BEFORE_ACTIVE */
1060 /* If the pagetop has changed, set the new pagetop here. */
1061 if (pagetop != calling_window->pagetop)
1062 {
1063 int newtop = calling_window->pagetop;
1064 calling_window->pagetop = pagetop;
1065 set_window_pagetop (calling_window, newtop);
1066 }
1067#endif /* !SPLIT_BEFORE_ACTIVE */
1068
1069 echo_area_completions_window = compwin;
1070 remember_window_and_node (compwin, compwin->node);
1071 }
1072 else
1073 compwin = calling_window;
1074 }
1075
1076 if (compwin->node != possible_completions_output_node)
1077 {
1078 window_set_node_of_window
1079 (compwin, possible_completions_output_node);
1080 remember_window_and_node (compwin, compwin->node);
1081 }
1082
1083 display_update_display (windows);
1084 }
1085 }
1086}
1087
1088DECLARE_INFO_COMMAND (ea_complete, _("Insert completion"))
1089{
1090 if (!echo_area_completion_items)
1091 {
1092 ea_insert (window, count, key);
1093 return;
1094 }
1095
1096 /* If KEY is SPC, and we are not forcing completion to take place, simply
1097 insert the key. */
1098 if (!echo_area_must_complete_p && key == SPC)
1099 {
1100 ea_insert (window, count, key);
1101 return;
1102 }
1103
1104 if (ea_last_executed_command == (VFunction *) ea_complete)
1105 {
1106 /* If the keypress is a SPC character, and we have already tried
1107 completing once, and there are several completions, then check
1108 the batch of completions to see if any continue with a space.
1109 If there are some, insert the space character and continue. */
1110 if (key == SPC && completions_found_index > 1)
1111 {
1112 register int i, offset;
1113
1114 offset = input_line_end - input_line_beg;
1115
1116 for (i = 0; i < completions_found_index; i++)
1117 if (completions_found[i]->label[offset] == ' ')
1118 break;
1119
1120 if (completions_found[i])
1121 ea_insert (window, 1, ' ');
1122 else
1123 {
1124 ea_possible_completions (window, count, key);
1125 return;
1126 }
1127 }
1128 else
1129 {
1130 ea_possible_completions (window, count, key);
1131 return;
1132 }
1133 }
1134
1135 input_line_point = input_line_end;
1136 build_completions ();
1137
1138 if (!completions_found_index)
1139 terminal_ring_bell ();
1140 else if (LCD_completion->label[0] == '\0')
1141 ea_possible_completions (window, count, key);
1142 else
1143 {
1144 register int i;
1145 input_line_point = input_line_end = input_line_beg;
1146 for (i = 0; LCD_completion->label[i]; i++)
1147 ea_insert (window, 1, LCD_completion->label[i]);
1148 }
1149}
1150
1151/* Utility REFERENCE used to store possible LCD. */
1152static REFERENCE LCD_reference = {
1153 (char *)NULL, (char *)NULL, (char *)NULL, 0, 0, 0
1154};
1155
1156static void remove_completion_duplicates (void);
1157
1158/* Variables which remember the state of the most recent call
1159 to build_completions (). */
1160static char *last_completion_request = (char *)NULL;
1161static REFERENCE **last_completion_items = (REFERENCE **)NULL;
1162
1163/* How to tell the completion builder to reset internal state. */
1164static void
1165completions_must_be_rebuilt (void)
1166{
1167 maybe_free (last_completion_request);
1168 last_completion_request = (char *)NULL;
1169 last_completion_items = (REFERENCE **)NULL;
1170}
1171
1172/* Build a list of possible completions from echo_area_completion_items,
1173 and the contents of input_line. */
1174static void
1175build_completions (void)
1176{
1177 register int i, len;
1178 register REFERENCE *entry;
1179 char *request;
1180 int informed_of_lengthy_job = 0;
1181
1182 /* If there are no items to complete over, exit immediately. */
1183 if (!echo_area_completion_items)
1184 {
1185 completions_found_index = 0;
1186 LCD_completion = (REFERENCE *)NULL;
1187 return;
1188 }
1189
1190 /* Check to see if this call to build completions is the same as the last
1191 call to build completions. */
1192 len = input_line_end - input_line_beg;
1193 request = (char *)xmalloc (1 + len);
1194 strncpy (request, &input_line[input_line_beg], len);
1195 request[len] = '\0';
1196
1197 if (last_completion_request && last_completion_items &&
1198 last_completion_items == echo_area_completion_items &&
1199 (strcmp (last_completion_request, request) == 0))
1200 {
1201 free (request);
1202 return;
1203 }
1204
1205 maybe_free (last_completion_request);
1206 last_completion_request = request;
1207 last_completion_items = echo_area_completion_items;
1208
1209 /* Always start at the beginning of the list. */
1210 completions_found_index = 0;
1211 LCD_completion = (REFERENCE *)NULL;
1212
1213 for (i = 0; (entry = echo_area_completion_items[i]); i++)
1214 {
1215 if (strncasecmp (request, entry->label, len) == 0)
1216 add_pointer_to_array (entry, completions_found_index,
1217 completions_found, completions_found_slots,
1218 20, REFERENCE *);
1219
1220 if (!informed_of_lengthy_job && completions_found_index > 100)
1221 {
1222 informed_of_lengthy_job = 1;
1223 window_message_in_echo_area ((char *) _("Building completions..."),
1224 NULL, NULL);
1225 }
1226 }
1227
1228 if (!completions_found_index)
1229 return;
1230
1231 /* Sort and prune duplicate entries from the completions array. */
1232 remove_completion_duplicates ();
1233
1234 /* If there is only one completion, just return that. */
1235 if (completions_found_index == 1)
1236 {
1237 LCD_completion = completions_found[0];
1238 return;
1239 }
1240
1241 /* Find the least common denominator. */
1242 {
1243 long shortest = 100000;
1244
1245 for (i = 1; i < completions_found_index; i++)
1246 {
1247 register int j;
1248 int c1, c2;
1249
1250 for (j = 0;
1251 (c1 = info_tolower (completions_found[i - 1]->label[j])) &&
1252 (c2 = info_tolower (completions_found[i]->label[j]));
1253 j++)
1254 if (c1 != c2)
1255 break;
1256
1257 if (shortest > j)
1258 shortest = j;
1259 }
1260
1261 maybe_free (LCD_reference.label);
1262 LCD_reference.label = (char *)xmalloc (1 + shortest);
1263 /* Since both the sorting done inside remove_completion_duplicates
1264 and all the comparisons above are case-insensitive, it's
1265 possible that the completion we are going to return is
1266 identical to what the user typed but for the letter-case. This
1267 is confusing, since the user could type FOOBAR<TAB> and get her
1268 string change letter-case for no good reason. So try to find a
1269 possible completion whose letter-case is identical, and if so,
1270 use that. */
1271 if (completions_found_index > 1)
1272 {
1273 int req_len = strlen (request);
1274
1275 for (i = 0; i < completions_found_index; i++)
1276 if (strncmp (request, completions_found[i]->label, req_len) == 0)
1277 break;
1278 /* If none of the candidates match exactly, use the first one. */
1279 if (i >= completions_found_index)
1280 i = 0;
1281 }
1282 strncpy (LCD_reference.label, completions_found[i]->label, shortest);
1283 LCD_reference.label[shortest] = '\0';
1284 LCD_completion = &LCD_reference;
1285 }
1286
1287 if (informed_of_lengthy_job)
1288 echo_area_initialize_node ();
1289}
1290
1291/* Function called by qsort. */
1292static int
1293compare_references (const void *entry1, const void *entry2)
1294{
1295 REFERENCE **e1 = (REFERENCE **) entry1;
1296 REFERENCE **e2 = (REFERENCE **) entry2;
1297
1298 return (strcasecmp ((*e1)->label, (*e2)->label));
1299}
1300
1301/* Prune duplicate entries from COMPLETIONS_FOUND. */
1302static void
1303remove_completion_duplicates (void)
1304{
1305 register int i, j;
1306 REFERENCE **temp;
1307 int newlen;
1308
1309 if (!completions_found_index)
1310 return;
1311
1312 /* Sort the items. */
1313 qsort (completions_found, completions_found_index, sizeof (REFERENCE *),
1314 compare_references);
1315
1316 for (i = 0, newlen = 1; i < completions_found_index - 1; i++)
1317 {
1318 if (strcmp (completions_found[i]->label,
1319 completions_found[i + 1]->label) == 0)
1320 completions_found[i] = (REFERENCE *)NULL;
1321 else
1322 newlen++;
1323 }
1324
1325 /* We have marked all the dead slots. It is faster to copy the live slots
1326 twice than to prune the dead slots one by one. */
1327 temp = (REFERENCE **)xmalloc ((1 + newlen) * sizeof (REFERENCE *));
1328 for (i = 0, j = 0; i < completions_found_index; i++)
1329 if (completions_found[i])
1330 temp[j++] = completions_found[i];
1331
1332 for (i = 0; i < newlen; i++)
1333 completions_found[i] = temp[i];
1334
1335 completions_found[i] = (REFERENCE *)NULL;
1336 completions_found_index = newlen;
1337 free (temp);
1338}
1339
1340/* Scroll the "other" window. If there is a window showing completions, scroll
1341 that one, otherwise scroll the window which was active on entering the read
1342 function. */
1343DECLARE_INFO_COMMAND (ea_scroll_completions_window, _("Scroll the completions window"))
1344{
1345 WINDOW *compwin;
1346 int old_pagetop;
1347
1348 compwin = get_internal_info_window (compwin_name);
1349
1350 if (!compwin)
1351 compwin = calling_window;
1352
1353 old_pagetop = compwin->pagetop;
1354
1355 /* Let info_scroll_forward () do the work, and print any messages that
1356 need to be displayed. */
1357 info_scroll_forward (compwin, count, key);
1358}
1359
1360/* Function which gets called when an Info window is deleted while the
1361 echo area is active. WINDOW is the window which has just been deleted. */
1362void
1363echo_area_inform_of_deleted_window (WINDOW *window)
1364{
1365 /* If this is the calling_window, forget what we remembered about it. */
1366 if (window == calling_window)
1367 {
1368 if (active_window != the_echo_area)
1369 remember_calling_window (active_window);
1370 else
1371 remember_calling_window (windows);
1372 }
1373
1374 /* If this window was the echo_area_completions_window, then notice that
1375 the window has been deleted. */
1376 if (window == echo_area_completions_window)
1377 echo_area_completions_window = (WINDOW *)NULL;
1378}
1379
1380
1381/* **************************************************************** */
1382/* */
1383/* Pushing and Popping the Echo Area */
1384/* */
1385/* **************************************************************** */
1386
1387/* Push and Pop the echo area. */
1388typedef struct {
1389 char *line;
1390 char *prompt;
1391 REFERENCE **comp_items;
1392 int point, beg, end;
1393 int must_complete;
1394 NODE node;
1395 WINDOW *compwin;
1396} PUSHED_EA;
1397
1398static PUSHED_EA **pushed_echo_areas = (PUSHED_EA **)NULL;
1399static int pushed_echo_areas_index = 0;
1400static int pushed_echo_areas_slots = 0;
1401
1402/* Pushing the echo_area has a side effect of zeroing the completion_items. */
1403static void
1404push_echo_area (void)
1405{
1406 PUSHED_EA *pushed;
1407
1408 pushed = (PUSHED_EA *)xmalloc (sizeof (PUSHED_EA));
1409 pushed->line = xstrdup (input_line);
1410 pushed->prompt = input_line_prompt;
1411 pushed->point = input_line_point;
1412 pushed->beg = input_line_beg;
1413 pushed->end = input_line_end;
1414 pushed->node = input_line_node;
1415 pushed->comp_items = echo_area_completion_items;
1416 pushed->must_complete = echo_area_must_complete_p;
1417 pushed->compwin = echo_area_completions_window;
1418
1419 add_pointer_to_array (pushed, pushed_echo_areas_index, pushed_echo_areas,
1420 pushed_echo_areas_slots, 4, PUSHED_EA *);
1421
1422 echo_area_completion_items = (REFERENCE **)NULL;
1423}
1424
1425static void
1426pop_echo_area (void)
1427{
1428 PUSHED_EA *popped;
1429
1430 popped = pushed_echo_areas[--pushed_echo_areas_index];
1431
1432 strcpy (input_line, popped->line);
1433 free (popped->line);
1434 input_line_prompt = popped->prompt;
1435 input_line_point = popped->point;
1436 input_line_beg = popped->beg;
1437 input_line_end = popped->end;
1438 input_line_node = popped->node;
1439 echo_area_completion_items = popped->comp_items;
1440 echo_area_must_complete_p = popped->must_complete;
1441 echo_area_completions_window = popped->compwin;
1442 completions_must_be_rebuilt ();
1443
1444 /* If the completion window no longer exists, forget about it. */
1445 if (echo_area_completions_window)
1446 {
1447 register WINDOW *win;
1448
1449 for (win = windows; win; win = win->next)
1450 if (echo_area_completions_window == win)
1451 break;
1452
1453 /* If the window wasn't found, then it has already been deleted. */
1454 if (!win)
1455 echo_area_completions_window = (WINDOW *)NULL;
1456 }
1457
1458 free (popped);
1459}
1460
1461/* Returns non-zero if any of the prior stacked calls to read in the echo
1462 area produced a completions window. */
1463static int
1464echo_area_stack_contains_completions_p (void)
1465{
1466 register int i;
1467
1468 for (i = 0; i < pushed_echo_areas_index; i++)
1469 if (pushed_echo_areas[i]->compwin)
1470 return (1);
1471
1472 return (0);
1473}
1474
1475
1476/* **************************************************************** */
1477/* */
1478/* Error Messages While Reading in Echo Area */
1479/* */
1480/* **************************************************************** */
1481
1482#if defined (HAVE_SYS_TIME_H)
1483# include <sys/time.h>
1484# define HAVE_STRUCT_TIMEVAL
1485#endif /* HAVE_SYS_TIME_H */
1486
1487static void
1488pause_or_input (void)
1489{
1490#if defined(FD_SET) && !defined(__INNOTEK_LIBC__)
1491 struct timeval timer;
1492 fd_set readfds;
1493 int ready;
1494
1495 FD_ZERO (&readfds);
1496 FD_SET (fileno (stdin), &readfds);
1497 timer.tv_sec = 2;
1498 timer.tv_usec = 0;
1499 ready = select (fileno (stdin) + 1, &readfds, (fd_set *) NULL,
1500 (fd_set *) NULL, &timer);
1501#endif /* FD_SET */
1502}
1503
1504/* Print MESSAGE right after the end of the current line, and wait
1505 for input or a couple of seconds, whichever comes first. Then flush the
1506 informational message that was printed. */
1507void
1508inform_in_echo_area (const char *message)
1509{
1510 int i;
1511 char *text;
1512 int avail = EA_MAX_INPUT + 1 - input_line_end;
1513
1514 text = xstrdup (message);
1515 for (i = 0; text[i] && text[i] != '\n' && i < avail; i++)
1516 ;
1517 text[i] = 0;
1518
1519 echo_area_initialize_node ();
1520 sprintf (&input_line[input_line_end], "%s[%s]\n",
1521 echo_area_is_active ? " ": "", text);
1522 free (text);
1523 the_echo_area->point = input_line_point;
1524 display_update_one_window (the_echo_area);
1525 display_cursor_at_point (active_window);
1526 fflush (stdout);
1527 pause_or_input ();
1528 echo_area_initialize_node ();
1529}
Note: See TracBrowser for help on using the repository browser.