1 /* infodoc.c -- Functions which build documentation nodes.
2 $Id: infodoc.c,v 1.23 1999/09/25 16:10:04 karl Exp $
4 Copyright (C) 1993, 97, 98, 99 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Written by Brian Fox (bfox@ai.mit.edu). */
24 /* HELP_NODE_GETS_REGENERATED is always defined now that keys may get
25 rebound, or other changes in the help text may occur. */
26 #define HELP_NODE_GETS_REGENERATED 1
28 /* **************************************************************** */
30 /* Info Help Windows */
32 /* **************************************************************** */
34 /* The name of the node used in the help window. */
35 static char *info_help_nodename = "*Info Help*";
37 /* A node containing printed key bindings and their documentation. */
38 static NODE *internal_info_help_node = (NODE *)NULL;
40 /* A pointer to the contents of the help node. */
41 static char *internal_info_help_node_contents = (char *)NULL;
43 /* The static text which appears in the internal info help node. */
44 static char *info_internal_help_text[] = {
45 N_("Basic Commands in Info Windows\n"),
46 N_("******************************\n"),
48 N_(" %-10s Quit this help.\n"),
49 N_(" %-10s Quit Info altogether.\n"),
50 N_(" %-10s Invoke the Info tutorial.\n"),
52 N_("Moving within a node:\n"),
53 N_("---------------------\n"),
54 N_(" %-10s Scroll forward a page.\n"),
55 N_(" %-10s Scroll backward a page.\n"),
56 N_(" %-10s Go to the beginning of this node.\n"),
57 N_(" %-10s Go to the end of this node.\n"),
58 N_(" %-10s Scroll forward 1 line.\n"),
59 N_(" %-10s Scroll backward 1 line.\n"),
61 N_("Selecting other nodes:\n"),
62 N_("----------------------\n"),
63 N_(" %-10s Move to the `next' node of this node.\n"),
64 N_(" %-10s Move to the `previous' node of this node.\n"),
65 N_(" %-10s Move `up' from this node.\n"),
66 N_(" %-10s Pick menu item specified by name.\n"),
67 N_(" Picking a menu item causes another node to be selected.\n"),
68 N_(" %-10s Follow a cross reference. Reads name of reference.\n"),
69 N_(" %-10s Move to the last node seen in this window.\n"),
70 N_(" %-10s Skip to next hypertext link within this node.\n"),
71 N_(" %-10s Follow the hypertext link under cursor.\n"),
72 N_(" %-10s Move to the `directory' node. Equivalent to `g (DIR)'.\n"),
73 N_(" %-10s Move to the Top node. Equivalent to `g Top'.\n"),
75 N_("Other commands:\n"),
76 N_("---------------\n"),
77 N_(" %-10s Pick first ... ninth item in node's menu.\n"),
78 N_(" %-10s Pick last item in node's menu.\n"),
79 N_(" %-10s Search for a specified string in the index entries of this Info\n"),
80 N_(" file, and select the node referenced by the first entry found.\n"),
81 N_(" %-10s Move to node specified by name.\n"),
82 N_(" You may include a filename as well, as in (FILENAME)NODENAME.\n"),
83 N_(" %-10s Search forward through this Info file for a specified string,\n"),
84 N_(" and select the node in which the next occurrence is found.\n"),
85 N_(" %-10s Search backward in this Info file for a specified string,\n"),
86 N_(" and select the node in which the next occurrence is found.\n"),
90 static char *info_help_keys_text[][2] = {
94 { "CTRL-x 0", "CTRL-x 0" },
104 { "ESC 1 SPC", "RET" },
105 { "ESC 1 DEL", "y" },
117 { "RET", "CTRL-x RET" },
123 { "1-9", "ESC 1-9" },
136 static char *where_is (), *where_is_internal ();
139 dump_map_to_message_buffer (prefix, map)
145 for (i = 0; i < 256; i++)
147 if (map[i].type == ISKMAP)
149 char *new_prefix, *keyname;
151 keyname = pretty_keyname (i);
152 new_prefix = (char *)
153 xmalloc (3 + strlen (prefix) + strlen (keyname));
154 sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
156 dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
159 else if (map[i].function)
164 doc = function_documentation (map[i].function);
165 name = function_name (map[i].function);
170 /* Find out if there is a series of identical functions, as in
172 for (last = i + 1; last < 256; last++)
173 if ((map[last].type != ISFUNC) ||
174 (map[last].function != map[i].function))
179 printf_to_message_buffer
180 ("%s%s .. ", prefix, pretty_keyname (i));
181 printf_to_message_buffer
182 ("%s%s\t", prefix, pretty_keyname (last - 1));
186 printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
188 #if defined (NAMED_FUNCTIONS)
189 /* Print the name of the function, and some padding before the
190 documentation string is printed. */
193 int desired_doc_start = 40; /* Must be multiple of 8. */
195 printf_to_message_buffer ("(%s)", name);
196 length_so_far = message_buffer_length_this_line ();
198 if ((desired_doc_start + strlen (doc)) >= the_screen->width)
199 printf_to_message_buffer ("\n ");
202 while (length_so_far < desired_doc_start)
204 printf_to_message_buffer ("\t");
205 length_so_far += character_width ('\t', length_so_far);
209 #endif /* NAMED_FUNCTIONS */
210 printf_to_message_buffer ("%s\n", doc);
215 /* How to create internal_info_help_node. HELP_IS_ONLY_WINDOW_P says
216 whether we're going to end up in a second (or more) window of our
217 own, or whether there's only one window and we're going to usurp it.
218 This determines how to quit the help window. Maybe we should just
219 make q do the right thing in both cases. */
222 create_internal_info_help_node (help_is_only_window_p)
223 int help_is_only_window_p;
227 char *contents = NULL;
229 #ifndef HELP_NODE_GETS_REGENERATED
230 if (internal_info_help_node_contents)
231 contents = internal_info_help_node_contents;
232 #endif /* !HELP_NODE_GETS_REGENERATED */
236 int printed_one_mx = 0;
238 initialize_message_buffer ();
240 for (i = 0; info_internal_help_text[i]; i++)
242 /* Don't translate blank lines, gettext outputs the po file
243 header in that case. We want a blank line. */
244 char *msg = *(info_internal_help_text[i])
245 ? _(info_internal_help_text[i])
246 : info_internal_help_text[i];
247 char *key = info_help_keys_text[i][vi_keys_p];
249 /* If we have only one window (because the window size was too
250 small to split it), CTRL-x 0 doesn't work to `quit' help. */
251 if (STREQ (key, "CTRL-x 0") && help_is_only_window_p)
254 printf_to_message_buffer (msg, key);
257 printf_to_message_buffer ("---------------------\n\n");
258 printf_to_message_buffer (_("The current search path is:\n"));
259 printf_to_message_buffer (" %s\n", infopath);
260 printf_to_message_buffer ("---------------------\n\n");
261 printf_to_message_buffer (_("Commands available in Info windows:\n\n"));
262 dump_map_to_message_buffer ("", info_keymap);
263 printf_to_message_buffer ("---------------------\n\n");
264 printf_to_message_buffer (_("Commands available in the echo area:\n\n"));
265 dump_map_to_message_buffer ("", echo_area_keymap);
267 #if defined (NAMED_FUNCTIONS)
268 /* Get a list of the M-x commands which have no keystroke equivs. */
269 for (i = 0; function_doc_array[i].func; i++)
271 VFunction *func = function_doc_array[i].func;
273 if ((!where_is_internal (info_keymap, func)) &&
274 (!where_is_internal (echo_area_keymap, func)))
278 printf_to_message_buffer ("---------------------\n\n");
279 printf_to_message_buffer
280 (_("The following commands can only be invoked via M-x:\n\n"));
284 printf_to_message_buffer
286 function_doc_array[i].func_name,
287 replace_in_documentation (strlen (function_doc_array[i].doc)
289 ? function_doc_array[i].doc
290 : _(function_doc_array[i].doc)));
296 printf_to_message_buffer ("\n");
297 #endif /* NAMED_FUNCTIONS */
299 printf_to_message_buffer
300 ("%s", replace_in_documentation
301 (_("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n")));
302 node = message_buffer_to_node ();
303 internal_info_help_node_contents = node->contents;
307 /* We already had the right contents, so simply use them. */
308 node = build_message_node ("", 0, 0);
309 free (node->contents);
310 node->contents = contents;
311 node->nodelen = 1 + strlen (contents);
314 internal_info_help_node = node;
316 /* Do not GC this node's contents. It never changes, and we never need
317 to delete it once it is made. If you change some things (such as
318 placing information about dynamic variables in the help text) then
319 you will need to allow the contents to be gc'd, and you will have to
320 arrange to always regenerate the help node. */
321 #if defined (HELP_NODE_GETS_REGENERATED)
322 add_gcable_pointer (internal_info_help_node->contents);
325 name_internal_node (internal_info_help_node, info_help_nodename);
327 /* Even though this is an internal node, we don't want the window
328 system to treat it specially. So we turn off the internalness
330 internal_info_help_node->flags &= ~N_IsInternal;
333 /* Return a window which is the window showing help in this Info. */
335 /* If the eligible window's height is >= this, split it to make the help
336 window. Otherwise display the help window in the current window. */
337 #define HELP_SPLIT_SIZE 24
340 info_find_or_create_help_window ()
342 int help_is_only_window_p;
343 WINDOW *eligible = NULL;
344 WINDOW *help_window = get_window_of_node (internal_info_help_node);
346 /* If we couldn't find the help window, then make it. */
352 for (window = windows; window; window = window->next)
354 if (window->height > max)
356 max = window->height;
364 #ifndef HELP_NODE_GETS_REGENERATED
366 /* help window is static, just return it. */
368 #endif /* not HELP_NODE_GETS_REGENERATED */
370 /* Make sure that we have a node containing the help text. The
371 argument is false if help will be the only window (so l must be used
372 to quit help), true if help will be one of several visible windows
373 (so CTRL-x 0 must be used to quit help). */
374 help_is_only_window_p
375 = (help_window && !windows->next
376 || !help_window && eligible->height < HELP_SPLIT_SIZE);
377 create_internal_info_help_node (help_is_only_window_p);
379 /* Either use the existing window to display the help node, or create
380 a new window if there was no existing help window. */
382 { /* Split the largest window into 2 windows, and show the help text
384 if (eligible->height >= HELP_SPLIT_SIZE)
386 active_window = eligible;
387 help_window = window_make_window (internal_info_help_node);
391 set_remembered_pagetop_and_point (active_window);
392 window_set_node_of_window (active_window, internal_info_help_node);
393 help_window = active_window;
397 { /* Case where help node always gets regenerated, and we have an
398 existing window in which to place the node. */
399 if (active_window != help_window)
401 set_remembered_pagetop_and_point (active_window);
402 active_window = help_window;
404 window_set_node_of_window (active_window, internal_info_help_node);
406 remember_window_and_node (help_window, help_window->node);
410 /* Create or move to the help window. */
411 DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message"))
415 help_window = info_find_or_create_help_window ();
418 active_window = help_window;
419 active_window->flags |= W_UpdateWindow;
423 info_error (msg_cant_make_help);
427 /* Show the Info help node. This means that the "info" file is installed
428 where it can easily be found on your system. */
429 DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'"))
434 /* If there is a window on the screen showing the node "(info)Help" or
435 the node "(info)Help-Small-Screen", simply select that window. */
439 for (win = windows; win; win = win->next)
441 if (win->node && win->node->filename &&
443 (filename_non_directory (win->node->filename), "info") == 0) &&
444 ((strcmp (win->node->nodename, "Help") == 0) ||
445 (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
453 /* If the current window is small, show the small screen help. */
454 if (active_window->height < 24)
455 nodename = "Help-Small-Screen";
459 /* Try to get the info file for Info. */
460 node = info_get_node ("Info", nodename);
464 if (info_recent_file_error)
465 info_error (info_recent_file_error);
467 info_error (msg_cant_file_node, "Info", nodename);
471 /* If the current window is very large (greater than 45 lines),
472 then split it and show the help node in another window.
473 Otherwise, use the current window. */
475 if (active_window->height > 45)
476 active_window = window_make_window (node);
479 set_remembered_pagetop_and_point (active_window);
480 window_set_node_of_window (active_window, node);
483 remember_window_and_node (active_window, node);
487 /* **************************************************************** */
489 /* Groveling Info Keymaps and Docs */
491 /* **************************************************************** */
493 /* Return the documentation associated with the Info command FUNCTION. */
495 function_documentation (function)
500 for (i = 0; function_doc_array[i].func; i++)
501 if (function == function_doc_array[i].func)
504 return replace_in_documentation ((strlen (function_doc_array[i].doc) == 0)
505 ? function_doc_array[i].doc
506 : _(function_doc_array[i].doc));
509 #if defined (NAMED_FUNCTIONS)
510 /* Return the user-visible name of the function associated with the
511 Info command FUNCTION. */
513 function_name (function)
519 for (i = 0; function_doc_array[i].func; i++)
520 if (function == function_doc_array[i].func)
523 return (function_doc_array[i].func_name);
526 /* Return a pointer to the function named NAME. */
528 named_function (name)
533 for (i = 0; function_doc_array[i].func; i++)
534 if (strcmp (function_doc_array[i].func_name, name) == 0)
537 return (function_doc_array[i].func);
539 #endif /* NAMED_FUNCTIONS */
541 /* Return the documentation associated with KEY in MAP. */
543 key_documentation (key, map)
547 VFunction *function = map[key].function;
550 return (function_documentation (function));
552 return ((char *)NULL);
555 DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY"))
558 int keyname_index = 0;
559 unsigned char keystroke;
564 map = window->keymap;
568 message_in_echo_area (_("Describe key: %s"), keyname);
569 keystroke = info_get_input_char ();
570 unmessage_in_echo_area ();
572 if (Meta_p (keystroke))
574 if (map[ESC].type != ISKMAP)
576 window_message_in_echo_area
577 (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke)));
581 strcpy (keyname + keyname_index, "ESC ");
582 keyname_index = strlen (keyname);
583 keystroke = UnMeta (keystroke);
584 map = (Keymap)map[ESC].function;
587 /* Add the printed representation of KEYSTROKE to our keyname. */
588 rep = pretty_keyname (keystroke);
589 strcpy (keyname + keyname_index, rep);
590 keyname_index = strlen (keyname);
592 if (map[keystroke].function == (VFunction *)NULL)
594 message_in_echo_area (_("%s is undefined."), keyname);
597 else if (map[keystroke].type == ISKMAP)
599 map = (Keymap)map[keystroke].function;
600 strcat (keyname, " ");
601 keyname_index = strlen (keyname);
606 char *message, *fundoc, *funname = "";
608 #if defined (NAMED_FUNCTIONS)
609 funname = function_name (map[keystroke].function);
610 #endif /* NAMED_FUNCTIONS */
612 fundoc = function_documentation (map[keystroke].function);
614 message = (char *)xmalloc
615 (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
617 #if defined (NAMED_FUNCTIONS)
618 sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
620 sprintf (message, _("%s is defined to %s."), keyname, fundoc);
621 #endif /* !NAMED_FUNCTIONS */
623 window_message_in_echo_area ("%s", message);
630 /* How to get the pretty printable name of a character. */
631 static char rep_buffer[30];
643 rep = pretty_keyname (UnMeta (key));
645 sprintf (temp, "ESC %s", rep);
646 strcpy (rep_buffer, temp);
649 else if (Control_p (key))
653 case '\n': rep = "LFD"; break;
654 case '\t': rep = "TAB"; break;
655 case '\r': rep = "RET"; break;
656 case ESC: rep = "ESC"; break;
659 sprintf (rep_buffer, "C-%c", UnControl (key));
667 case ' ': rep = "SPC"; break;
668 case DEL: rep = "DEL"; break;
671 rep_buffer[1] = '\0';
678 /* Replace the names of functions with the key that invokes them. */
680 replace_in_documentation (string)
683 register int i, start, next;
684 static char *result = (char *)NULL;
687 result = (char *)xmalloc (1 + strlen (string));
689 i = next = start = 0;
691 /* Skip to the beginning of a replaceable function. */
692 for (i = start; string[i]; i++)
694 /* Is this the start of a replaceable function name? */
695 if (string[i] == '\\' && string[i + 1] == '[')
697 char *fun_name, *rep;
700 /* Copy in the old text. */
701 strncpy (result + next, string + start, i - start);
705 /* Move to the end of the function name. */
706 for (i = start; string[i] && (string[i] != ']'); i++);
708 fun_name = (char *)xmalloc (1 + i - start);
709 strncpy (fun_name, string + start, i - start);
710 fun_name[i - start] = '\0';
712 /* Find a key which invokes this function in the info_keymap. */
713 function = named_function (fun_name);
715 /* If the internal documentation string fails, there is a
716 serious problem with the associated command's documentation.
717 We croak so that it can be fixed immediately. */
721 rep = where_is (info_keymap, function);
722 strcpy (result + next, rep);
723 next = strlen (result);
730 strcpy (result + next, string + start);
734 /* Return a string of characters which could be typed from the keymap
735 MAP to invoke FUNCTION. */
736 static char *where_is_rep = (char *)NULL;
737 static int where_is_rep_index = 0;
738 static int where_is_rep_size = 0;
741 where_is (map, function)
747 if (!where_is_rep_size)
748 where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
749 where_is_rep_index = 0;
751 rep = where_is_internal (map, function);
753 /* If it couldn't be found, return "M-x Foo". */
758 name = function_name (function);
761 sprintf (where_is_rep, "M-x %s", name);
768 /* Return the printed rep of FUNCTION as found in MAP, or NULL. */
770 where_is_internal (map, function)
776 /* If the function is directly invokable in MAP, return the representation
777 of that keystroke. */
778 for (i = 0; i < 256; i++)
779 if ((map[i].type == ISFUNC) && map[i].function == function)
781 sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
782 return (where_is_rep);
785 /* Okay, search subsequent maps for this function. */
786 for (i = 0; i < 256; i++)
788 if (map[i].type == ISKMAP)
790 int saved_index = where_is_rep_index;
793 sprintf (where_is_rep + where_is_rep_index, "%s ",
796 where_is_rep_index = strlen (where_is_rep);
797 rep = where_is_internal ((Keymap)map[i].function, function);
800 return (where_is_rep);
802 where_is_rep_index = saved_index;
809 extern char *read_function_name ();
811 DECLARE_INFO_COMMAND (info_where_is,
812 _("Show what to type to execute a given command"))
816 command_name = read_function_name (_("Where is command: "), window);
820 info_abort_key (active_window, count, key);
828 function = named_function (command_name);
834 location = where_is (active_window->keymap, function);
838 info_error (_("`%s' is not on any keys"), command_name);
842 if (strncmp (location, "M-x ", 4) == 0)
843 window_message_in_echo_area
844 (_("%s can only be invoked via %s."), command_name, location);
846 window_message_in_echo_area
847 (_("%s can be invoked via %s."), command_name, location);
851 info_error (_("There is no function named `%s'"), command_name);