1 /* infodoc.c -- Functions which build documentation nodes.
2 $Id: infodoc.c,v 1.4 1997/07/25 21:08:40 karl Exp $
4 Copyright (C) 1993, 97 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 /* Normally we do not define HELP_NODE_GETS_REGENERATED because the
25 contents of the help node currently can never change once an info
26 session has been started. You should consider defining this in
27 the case that you place information about dynamic variables in the
28 help text. When that happens, the contents of the help node will
29 change dependent on the value of those variables, and the user will
30 expect to see those changes. */
31 /* #define HELP_NODE_GETS_REGENERATED 1 */
33 /* **************************************************************** */
35 /* Info Help Windows */
37 /* **************************************************************** */
39 /* The name of the node used in the help window. */
40 static char *info_help_nodename = "*Info Help*";
42 /* A node containing printed key bindings and their documentation. */
43 static NODE *internal_info_help_node = (NODE *)NULL;
45 /* A pointer to the contents of the help node. */
46 static char *internal_info_help_node_contents = (char *)NULL;
48 /* The static text which appears in the internal info help node. */
49 static char *info_internal_help_text[] = {
50 N_ ("Basic Commands in Info Windows"),
51 "******************************",
53 " h Invoke the Info tutorial.",
54 " CTRL-x 0 Quit this help.",
55 " q Quit Info altogether.",
57 "Selecting other nodes:",
58 "----------------------",
59 " n Move to the \"next\" node of this node.",
60 " p Move to the \"previous\" node of this node.",
61 " u Move \"up\" from this node.",
62 " m Pick menu item specified by name.",
63 " Picking a menu item causes another node to be selected.",
64 " f Follow a cross reference. Reads name of reference.",
65 " l Move to the last node seen in this window.",
66 " d Move to the `directory' node. Equivalent to `g(DIR)'.",
68 "Moving within a node:",
69 "---------------------",
70 " SPC Scroll forward a page.",
71 " DEL Scroll backward a page.",
72 " b Go to the beginning of this node.",
73 " e Go to the end of this node.",
76 "--------------------",
77 " 1 Pick first item in node's menu.",
78 " 2-9 Pick second ... ninth item in node's menu.",
79 " 0 Pick last item in node's menu.",
80 " g Move to node specified by name.",
81 " You may include a filename as well, as in (FILENAME)NODENAME.",
82 " s Search through this Info file for a specified string,",
83 " and select the node in which the next occurrence is found.",
87 static char *where_is (), *where_is_internal ();
90 dump_map_to_message_buffer (prefix, map)
96 for (i = 0; i < 256; i++)
98 if (map[i].type == ISKMAP)
100 char *new_prefix, *keyname;
102 keyname = pretty_keyname (i);
103 new_prefix = (char *)
104 xmalloc (3 + strlen (prefix) + strlen (keyname));
105 sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
107 dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
110 else if (map[i].function)
115 doc = function_documentation (map[i].function);
116 name = function_name (map[i].function);
121 /* Find out if there is a series of identical functions, as in
123 for (last = i + 1; last < 256; last++)
124 if ((map[last].type != ISFUNC) ||
125 (map[last].function != map[i].function))
130 printf_to_message_buffer
131 ("%s%s .. ", prefix, pretty_keyname (i));
132 printf_to_message_buffer
133 ("%s%s\t", prefix, pretty_keyname (last - 1));
137 printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
139 #if defined (NAMED_FUNCTIONS)
140 /* Print the name of the function, and some padding before the
141 documentation string is printed. */
144 int desired_doc_start = 40; /* Must be multiple of 8. */
146 printf_to_message_buffer ("(%s)", name);
147 length_so_far = message_buffer_length_this_line ();
149 if ((desired_doc_start + strlen (doc)) >= the_screen->width)
150 printf_to_message_buffer ("\n ");
153 while (length_so_far < desired_doc_start)
155 printf_to_message_buffer ("\t");
156 length_so_far += character_width ('\t', length_so_far);
160 #endif /* NAMED_FUNCTIONS */
161 printf_to_message_buffer ("%s\n", doc);
166 /* How to create internal_info_help_node. */
168 create_internal_info_help_node ()
171 char *contents = (char *)NULL;
174 #if !defined (HELP_NODE_GETS_REGENERATED)
175 if (internal_info_help_node_contents)
176 contents = internal_info_help_node_contents;
177 #endif /* !HELP_NODE_GETS_REGENERATED */
181 int printed_one_mx = 0;
183 initialize_message_buffer ();
185 for (i = 0; info_internal_help_text[i]; i++)
186 printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
188 printf_to_message_buffer ("---------------------\n\n");
189 printf_to_message_buffer ("The current search path is:\n");
190 printf_to_message_buffer (" \"%s\"\n", infopath);
191 printf_to_message_buffer ("---------------------\n\n");
192 printf_to_message_buffer ("Commands available in Info windows:\n\n");
193 dump_map_to_message_buffer ("", info_keymap);
194 printf_to_message_buffer ("---------------------\n\n");
195 printf_to_message_buffer ("Commands available in the echo area:\n\n");
196 dump_map_to_message_buffer ("", echo_area_keymap);
198 #if defined (NAMED_FUNCTIONS)
199 /* Get a list of the M-x commands which have no keystroke equivs. */
200 for (i = 0; function_doc_array[i].func; i++)
202 VFunction *func = function_doc_array[i].func;
204 if ((!where_is_internal (info_keymap, func)) &&
205 (!where_is_internal (echo_area_keymap, func)))
209 printf_to_message_buffer ("---------------------\n\n");
210 printf_to_message_buffer
211 (_("The following commands can only be invoked via M-x:\n\n"));
215 printf_to_message_buffer
217 function_doc_array[i].func_name,
218 replace_in_documentation (function_doc_array[i].doc));
223 printf_to_message_buffer ("\n");
224 #endif /* NAMED_FUNCTIONS */
226 printf_to_message_buffer
227 ("%s", replace_in_documentation
228 (_("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n")));
229 node = message_buffer_to_node ();
230 internal_info_help_node_contents = node->contents;
234 /* We already had the right contents, so simply use them. */
235 node = build_message_node ("", 0, 0);
236 free (node->contents);
237 node->contents = contents;
238 node->nodelen = 1 + strlen (contents);
241 internal_info_help_node = node;
243 /* Do not GC this node's contents. It never changes, and we never need
244 to delete it once it is made. If you change some things (such as
245 placing information about dynamic variables in the help text) then
246 you will need to allow the contents to be gc'd, and you will have to
247 arrange to always regenerate the help node. */
248 #if defined (HELP_NODE_GETS_REGENERATED)
249 add_gcable_pointer (internal_info_help_node->contents);
252 name_internal_node (internal_info_help_node, info_help_nodename);
254 /* Even though this is an internal node, we don't want the window
255 system to treat it specially. So we turn off the internalness
257 internal_info_help_node->flags &= ~N_IsInternal;
260 /* Return a window which is the window showing help in this Info. */
262 info_find_or_create_help_window ()
264 WINDOW *help_window, *eligible, *window;
266 eligible = (WINDOW *)NULL;
267 help_window = get_internal_info_window (info_help_nodename);
269 /* If we couldn't find the help window, then make it. */
274 for (window = windows; window; window = window->next)
276 if (window->height > max)
278 max = window->height;
284 return ((WINDOW *)NULL);
286 #if !defined (HELP_NODE_GETS_REGENERATED)
288 return (help_window);
289 #endif /* !HELP_NODE_GETS_REGENERATED */
291 /* Make sure that we have a node containing the help text. */
292 create_internal_info_help_node ();
294 /* Either use the existing window to display the help node, or create
295 a new window if there was no existing help window. */
298 /* Split the largest window into 2 windows, and show the help text
300 if (eligible->height > 30)
302 active_window = eligible;
303 help_window = window_make_window (internal_info_help_node);
307 set_remembered_pagetop_and_point (active_window);
308 window_set_node_of_window (active_window, internal_info_help_node);
309 help_window = active_window;
314 /* Case where help node always gets regenerated, and we have an
315 existing window in which to place the node. */
316 if (active_window != help_window)
318 set_remembered_pagetop_and_point (active_window);
319 active_window = help_window;
321 window_set_node_of_window (active_window, internal_info_help_node);
323 remember_window_and_node (help_window, help_window->node);
324 return (help_window);
327 /* Create or move to the help window. */
328 DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message"))
332 help_window = info_find_or_create_help_window ();
335 active_window = help_window;
336 active_window->flags |= W_UpdateWindow;
340 info_error (CANT_MAKE_HELP);
344 /* Show the Info help node. This means that the "info" file is installed
345 where it can easily be found on your system. */
346 DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'"))
351 /* If there is a window on the screen showing the node "(info)Help" or
352 the node "(info)Help-Small-Screen", simply select that window. */
356 for (win = windows; win; win = win->next)
358 if (win->node && win->node->filename &&
360 (filename_non_directory (win->node->filename), "info") == 0) &&
361 ((strcmp (win->node->nodename, "Help") == 0) ||
362 (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
370 /* If the current window is small, show the small screen help. */
371 if (active_window->height < 24)
372 nodename = "Help-Small-Screen";
376 /* Try to get the info file for Info. */
377 node = info_get_node ("Info", nodename);
381 if (info_recent_file_error)
382 info_error (info_recent_file_error);
384 info_error (CANT_FILE_NODE, "Info", nodename);
388 /* If the current window is very large (greater than 45 lines),
389 then split it and show the help node in another window.
390 Otherwise, use the current window. */
392 if (active_window->height > 45)
393 active_window = window_make_window (node);
396 set_remembered_pagetop_and_point (active_window);
397 window_set_node_of_window (active_window, node);
400 remember_window_and_node (active_window, node);
404 /* **************************************************************** */
406 /* Groveling Info Keymaps and Docs */
408 /* **************************************************************** */
410 /* Return the documentation associated with the Info command FUNCTION. */
412 function_documentation (function)
417 for (i = 0; function_doc_array[i].func; i++)
418 if (function == function_doc_array[i].func)
421 return (replace_in_documentation (function_doc_array[i].doc));
424 #if defined (NAMED_FUNCTIONS)
425 /* Return the user-visible name of the function associated with the
426 Info command FUNCTION. */
428 function_name (function)
434 for (i = 0; function_doc_array[i].func; i++)
435 if (function == function_doc_array[i].func)
438 return (function_doc_array[i].func_name);
441 /* Return a pointer to the function named NAME. */
443 named_function (name)
448 for (i = 0; function_doc_array[i].func; i++)
449 if (strcmp (function_doc_array[i].func_name, name) == 0)
452 return (function_doc_array[i].func);
454 #endif /* NAMED_FUNCTIONS */
456 /* Return the documentation associated with KEY in MAP. */
458 key_documentation (key, map)
462 VFunction *function = map[key].function;
465 return (function_documentation (function));
467 return ((char *)NULL);
470 DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY"))
473 int keyname_index = 0;
474 unsigned char keystroke;
479 map = window->keymap;
483 message_in_echo_area (_("Describe key: %s"), keyname);
484 keystroke = info_get_input_char ();
485 unmessage_in_echo_area ();
487 if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
489 if (map[ESC].type != ISKMAP)
491 window_message_in_echo_area
492 (_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke)));
496 strcpy (keyname + keyname_index, "ESC ");
497 keyname_index = strlen (keyname);
498 keystroke = UnMeta (keystroke);
499 map = (Keymap)map[ESC].function;
502 /* Add the printed representation of KEYSTROKE to our keyname. */
503 rep = pretty_keyname (keystroke);
504 strcpy (keyname + keyname_index, rep);
505 keyname_index = strlen (keyname);
507 if (map[keystroke].function == (VFunction *)NULL)
509 message_in_echo_area (_("%s is undefined."), keyname);
512 else if (map[keystroke].type == ISKMAP)
514 map = (Keymap)map[keystroke].function;
515 strcat (keyname, " ");
516 keyname_index = strlen (keyname);
521 char *message, *fundoc, *funname = "";
523 #if defined (NAMED_FUNCTIONS)
524 funname = function_name (map[keystroke].function);
525 #endif /* NAMED_FUNCTIONS */
527 fundoc = function_documentation (map[keystroke].function);
529 message = (char *)xmalloc
530 (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
532 #if defined (NAMED_FUNCTIONS)
533 sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
535 sprintf (message, _("%s is defined to %s."), keyname, fundoc);
536 #endif /* !NAMED_FUNCTIONS */
538 window_message_in_echo_area ("%s", message);
545 /* How to get the pretty printable name of a character. */
546 static char rep_buffer[30];
558 rep = pretty_keyname (UnMeta (key));
560 sprintf (temp, "ESC %s", rep);
561 strcpy (rep_buffer, temp);
564 else if (Control_p (key))
568 case '\n': rep = "LFD"; break;
569 case '\t': rep = "TAB"; break;
570 case '\r': rep = "RET"; break;
571 case ESC: rep = "ESC"; break;
574 sprintf (rep_buffer, "C-%c", UnControl (key));
582 case ' ': rep = "SPC"; break;
583 case DEL: rep = "DEL"; break;
586 rep_buffer[1] = '\0';
593 /* Replace the names of functions with the key that invokes them. */
595 replace_in_documentation (string)
598 register int i, start, next;
599 static char *result = (char *)NULL;
602 result = (char *)xmalloc (1 + strlen (string));
604 i = next = start = 0;
606 /* Skip to the beginning of a replaceable function. */
607 for (i = start; string[i]; i++)
609 /* Is this the start of a replaceable function name? */
610 if (string[i] == '\\' && string[i + 1] == '[')
612 char *fun_name, *rep;
615 /* Copy in the old text. */
616 strncpy (result + next, string + start, i - start);
620 /* Move to the end of the function name. */
621 for (i = start; string[i] && (string[i] != ']'); i++);
623 fun_name = (char *)xmalloc (1 + i - start);
624 strncpy (fun_name, string + start, i - start);
625 fun_name[i - start] = '\0';
627 /* Find a key which invokes this function in the info_keymap. */
628 function = named_function (fun_name);
630 /* If the internal documentation string fails, there is a
631 serious problem with the associated command's documentation.
632 We croak so that it can be fixed immediately. */
636 rep = where_is (info_keymap, function);
637 strcpy (result + next, rep);
638 next = strlen (result);
645 strcpy (result + next, string + start);
649 /* Return a string of characters which could be typed from the keymap
650 MAP to invoke FUNCTION. */
651 static char *where_is_rep = (char *)NULL;
652 static int where_is_rep_index = 0;
653 static int where_is_rep_size = 0;
656 where_is (map, function)
662 if (!where_is_rep_size)
663 where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
664 where_is_rep_index = 0;
666 rep = where_is_internal (map, function);
668 /* If it couldn't be found, return "M-x Foo". */
673 name = function_name (function);
676 sprintf (where_is_rep, "M-x %s", name);
683 /* Return the printed rep of FUNCTION as found in MAP, or NULL. */
685 where_is_internal (map, function)
691 /* If the function is directly invokable in MAP, return the representation
692 of that keystroke. */
693 for (i = 0; i < 256; i++)
694 if ((map[i].type == ISFUNC) && map[i].function == function)
696 sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
697 return (where_is_rep);
700 /* Okay, search subsequent maps for this function. */
701 for (i = 0; i < 256; i++)
703 if (map[i].type == ISKMAP)
705 int saved_index = where_is_rep_index;
708 sprintf (where_is_rep + where_is_rep_index, "%s ",
711 where_is_rep_index = strlen (where_is_rep);
712 rep = where_is_internal ((Keymap)map[i].function, function);
715 return (where_is_rep);
717 where_is_rep_index = saved_index;
721 return ((char *)NULL);
724 extern char *read_function_name ();
726 DECLARE_INFO_COMMAND (info_where_is,
727 "Show what to type to execute a given command")
731 command_name = read_function_name (_("Where is command: "), window);
735 info_abort_key (active_window, count, key);
743 function = named_function (command_name);
749 location = where_is (active_window->keymap, function);
753 info_error (_("`%s' is not on any keys"), command_name);
757 if (strncmp (location, "M-x ", 4) == 0)
758 window_message_in_echo_area
759 (_("%s can only be invoked via %s."), command_name, location);
761 window_message_in_echo_area
762 (_("%s can be invoked via %s."), command_name, location);
766 info_error (_("There is no function named `%s'"), command_name);