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