1 /* infodoc.c -- Functions which build documentation nodes. */
3 /* This file is part of GNU Info, a program for reading online documentation
6 Copyright (C) 1993 Free Software Foundation, Inc.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 Written by Brian Fox (bfox@ai.mit.edu). */
26 /* Normally we do not define HELP_NODE_GETS_REGENERATED because the
27 contents of the help node currently can never change once an info
28 session has been started. You should consider defining this in
29 the case that you place information about dynamic variables in the
30 help text. When that happens, the contents of the help node will
31 change dependent on the value of those variables, and the user will
32 expect to see those changes. */
33 /* #define HELP_NODE_GETS_REGENERATED 1 */
35 /* **************************************************************** */
37 /* Info Help Windows */
39 /* **************************************************************** */
41 /* The name of the node used in the help window. */
42 static char *info_help_nodename = "*Info Help*";
44 /* A node containing printed key bindings and their documentation. */
45 static NODE *internal_info_help_node = (NODE *)NULL;
47 /* A pointer to the contents of the help node. */
48 static char *internal_info_help_node_contents = (char *)NULL;
50 /* The static text which appears in the internal info help node. */
51 static char *info_internal_help_text[] = {
52 "Basic Commands in Info Windows",
53 "******************************",
55 " h Invoke the Info tutorial.",
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.",
75 "\"Advanced\" commands:",
76 "--------------------",
78 " 1 Pick first item in node's menu.",
79 " 2-9 Pick second ... ninth item in node's menu.",
80 " 0 Pick last item in node's menu.",
81 " g Move to node specified by name.",
82 " You may include a filename as well, as in (FILENAME)NODENAME.",
83 " s Search through this Info file for a specified string,",
84 " and select the node in which the next occurrence is found.",
88 static char *where_is (), *where_is_internal ();
91 dump_map_to_message_buffer (prefix, map)
97 for (i = 0; i < 256; i++)
99 if (map[i].type == ISKMAP)
101 char *new_prefix, *keyname;
103 keyname = pretty_keyname (i);
104 new_prefix = (char *)
105 xmalloc (3 + strlen (prefix) + strlen (keyname));
106 sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
108 dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
111 else if (map[i].function)
116 doc = function_documentation (map[i].function);
117 name = function_name (map[i].function);
122 /* Find out if there is a series of identical functions, as in
124 for (last = i + 1; last < 256; last++)
125 if ((map[last].type != ISFUNC) ||
126 (map[last].function != map[i].function))
131 printf_to_message_buffer
132 ("%s%s .. ", prefix, pretty_keyname (i));
133 printf_to_message_buffer
134 ("%s%s\t", prefix, pretty_keyname (last - 1));
138 printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
140 #if defined (NAMED_FUNCTIONS)
141 /* Print the name of the function, and some padding before the
142 documentation string is printed. */
145 int desired_doc_start = 40; /* Must be multiple of 8. */
147 printf_to_message_buffer ("(%s)", name);
148 length_so_far = message_buffer_length_this_line ();
150 if ((desired_doc_start + strlen (doc)) >= the_screen->width)
151 printf_to_message_buffer ("\n ");
154 while (length_so_far < desired_doc_start)
156 printf_to_message_buffer ("\t");
157 length_so_far += character_width ('\t', length_so_far);
161 #endif /* NAMED_FUNCTIONS */
162 printf_to_message_buffer ("%s\n", doc);
167 /* How to create internal_info_help_node. */
169 create_internal_info_help_node ()
172 char *contents = (char *)NULL;
175 #if !defined (HELP_NODE_GETS_REGENERATED)
176 if (internal_info_help_node_contents)
177 contents = internal_info_help_node_contents;
178 #endif /* !HELP_NODE_GETS_REGENERATED */
182 int printed_one_mx = 0;
184 initialize_message_buffer ();
186 for (i = 0; info_internal_help_text[i]; i++)
187 printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
189 printf_to_message_buffer ("---------------------\n\n");
190 printf_to_message_buffer ("The current search path is:\n");
191 printf_to_message_buffer (" \"%s\"\n", infopath);
192 printf_to_message_buffer ("---------------------\n\n");
193 printf_to_message_buffer ("Commands available in Info windows:\n\n");
194 dump_map_to_message_buffer ("", info_keymap);
195 printf_to_message_buffer ("---------------------\n\n");
196 printf_to_message_buffer ("Commands available in the echo area:\n\n");
197 dump_map_to_message_buffer ("", echo_area_keymap);
199 #if defined (NAMED_FUNCTIONS)
200 /* Get a list of the M-x commands which have no keystroke equivs. */
201 for (i = 0; function_doc_array[i].func; i++)
203 VFunction *func = function_doc_array[i].func;
205 if ((!where_is_internal (info_keymap, func)) &&
206 (!where_is_internal (echo_area_keymap, func)))
210 printf_to_message_buffer ("---------------------\n\n");
211 printf_to_message_buffer
212 ("The following commands can only be invoked via M-x:\n\n");
216 printf_to_message_buffer
218 function_doc_array[i].func_name,
219 replace_in_documentation (function_doc_array[i].doc));
224 printf_to_message_buffer ("\n");
225 #endif /* NAMED_FUNCTIONS */
227 printf_to_message_buffer
228 ("%s", replace_in_documentation
229 ("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n"));
230 node = message_buffer_to_node ();
231 internal_info_help_node_contents = node->contents;
235 /* We already had the right contents, so simply use them. */
236 node = build_message_node ("", 0, 0);
237 free (node->contents);
238 node->contents = contents;
239 node->nodelen = 1 + strlen (contents);
242 internal_info_help_node = node;
244 /* Do not GC this node's contents. It never changes, and we never need
245 to delete it once it is made. If you change some things (such as
246 placing information about dynamic variables in the help text) then
247 you will need to allow the contents to be gc'd, and you will have to
248 arrange to always regenerate the help node. */
249 #if defined (HELP_NODE_GETS_REGENERATED)
250 add_gcable_pointer (internal_info_help_node->contents);
253 name_internal_node (internal_info_help_node, info_help_nodename);
255 /* Even though this is an internal node, we don't want the window
256 system to treat it specially. So we turn off the internalness
258 internal_info_help_node->flags &= ~N_IsInternal;
261 /* Return a window which is the window showing help in this Info. */
263 info_find_or_create_help_window ()
265 WINDOW *help_window, *eligible, *window;
267 eligible = (WINDOW *)NULL;
268 help_window = get_internal_info_window (info_help_nodename);
270 /* If we couldn't find the help window, then make it. */
275 for (window = windows; window; window = window->next)
277 if (window->height > max)
279 max = window->height;
285 return ((WINDOW *)NULL);
287 #if !defined (HELP_NODE_GETS_REGENERATED)
289 return (help_window);
290 #endif /* !HELP_NODE_GETS_REGENERATED */
292 /* Make sure that we have a node containing the help text. */
293 create_internal_info_help_node ();
295 /* Either use the existing window to display the help node, or create
296 a new window if there was no existing help window. */
299 /* Split the largest window into 2 windows, and show the help text
301 if (eligible->height > 30)
303 active_window = eligible;
304 help_window = window_make_window (internal_info_help_node);
308 set_remembered_pagetop_and_point (active_window);
309 window_set_node_of_window (active_window, internal_info_help_node);
310 help_window = active_window;
315 /* Case where help node always gets regenerated, and we have an
316 existing window in which to place the node. */
317 if (active_window != help_window)
319 set_remembered_pagetop_and_point (active_window);
320 active_window = help_window;
322 window_set_node_of_window (active_window, internal_info_help_node);
324 remember_window_and_node (help_window, help_window->node);
325 return (help_window);
328 /* Create or move to the help window. */
329 DECLARE_INFO_COMMAND (info_get_help_window, "Display help message")
333 help_window = info_find_or_create_help_window ();
336 active_window = help_window;
337 active_window->flags |= W_UpdateWindow;
341 info_error (CANT_MAKE_HELP);
345 /* Show the Info help node. This means that the "info" file is installed
346 where it can easily be found on your system. */
347 DECLARE_INFO_COMMAND (info_get_info_help_node, "Visit Info node `(info)Help'")
352 /* If there is a window on the screen showing the node "(info)Help" or
353 the node "(info)Help-Small-Screen", simply select that window. */
357 for (win = windows; win; win = win->next)
359 if (win->node && win->node->filename &&
361 (filename_non_directory (win->node->filename), "info") == 0) &&
362 ((strcmp (win->node->nodename, "Help") == 0) ||
363 (strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
371 /* If the current window is small, show the small screen help. */
372 if (active_window->height < 24)
373 nodename = "Help-Small-Screen";
377 /* Try to get the info file for Info. */
378 node = info_get_node ("Info", nodename);
382 if (info_recent_file_error)
383 info_error (info_recent_file_error);
385 info_error (CANT_FILE_NODE, "Info", nodename);
389 /* If the current window is very large (greater than 45 lines),
390 then split it and show the help node in another window.
391 Otherwise, use the current window. */
393 if (active_window->height > 45)
394 active_window = window_make_window (node);
397 set_remembered_pagetop_and_point (active_window);
398 window_set_node_of_window (active_window, node);
401 remember_window_and_node (active_window, node);
405 /* **************************************************************** */
407 /* Groveling Info Keymaps and Docs */
409 /* **************************************************************** */
411 /* Return the documentation associated with the Info command FUNCTION. */
413 function_documentation (function)
418 for (i = 0; function_doc_array[i].func; i++)
419 if (function == function_doc_array[i].func)
422 return (replace_in_documentation (function_doc_array[i].doc));
425 #if defined (NAMED_FUNCTIONS)
426 /* Return the user-visible name of the function associated with the
427 Info command FUNCTION. */
429 function_name (function)
435 for (i = 0; function_doc_array[i].func; i++)
436 if (function == function_doc_array[i].func)
439 return (function_doc_array[i].func_name);
442 /* Return a pointer to the function named NAME. */
444 named_function (name)
449 for (i = 0; function_doc_array[i].func; i++)
450 if (strcmp (function_doc_array[i].func_name, name) == 0)
453 return (function_doc_array[i].func);
455 #endif /* NAMED_FUNCTIONS */
457 /* Return the documentation associated with KEY in MAP. */
459 key_documentation (key, map)
463 VFunction *function = map[key].function;
466 return (function_documentation (function));
468 return ((char *)NULL);
471 DECLARE_INFO_COMMAND (describe_key, "Print documentation for KEY")
474 int keyname_index = 0;
475 unsigned char keystroke;
480 map = window->keymap;
484 message_in_echo_area ("Describe key: %s", keyname);
485 keystroke = info_get_input_char ();
486 unmessage_in_echo_area ();
488 if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
490 if (map[ESC].type != ISKMAP)
492 window_message_in_echo_area
493 ("ESC %s is undefined.", pretty_keyname (UnMeta (keystroke)));
497 strcpy (keyname + keyname_index, "ESC ");
498 keyname_index = strlen (keyname);
499 keystroke = UnMeta (keystroke);
500 map = (Keymap)map[ESC].function;
503 /* Add the printed representation of KEYSTROKE to our keyname. */
504 rep = pretty_keyname (keystroke);
505 strcpy (keyname + keyname_index, rep);
506 keyname_index = strlen (keyname);
508 if (map[keystroke].function == (VFunction *)NULL)
510 message_in_echo_area ("%s is undefined.", keyname);
513 else if (map[keystroke].type == ISKMAP)
515 map = (Keymap)map[keystroke].function;
516 strcat (keyname, " ");
517 keyname_index = strlen (keyname);
522 char *message, *fundoc, *funname = "";
524 #if defined (NAMED_FUNCTIONS)
525 funname = function_name (map[keystroke].function);
526 #endif /* NAMED_FUNCTIONS */
528 fundoc = function_documentation (map[keystroke].function);
530 message = (char *)xmalloc
531 (10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
533 #if defined (NAMED_FUNCTIONS)
534 sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
536 sprintf (message, "%s is defined to %s.", keyname, fundoc);
537 #endif /* !NAMED_FUNCTIONS */
539 window_message_in_echo_area ("%s", message);
546 /* How to get the pretty printable name of a character. */
547 static char rep_buffer[30];
559 rep = pretty_keyname (UnMeta (key));
561 sprintf (temp, "ESC %s", rep);
562 strcpy (rep_buffer, temp);
565 else if (Control_p (key))
569 case '\n': rep = "LFD"; break;
570 case '\t': rep = "TAB"; break;
571 case '\r': rep = "RET"; break;
572 case ESC: rep = "ESC"; break;
575 sprintf (rep_buffer, "C-%c", UnControl (key));
583 case ' ': rep = "SPC"; break;
584 case DEL: rep = "DEL"; break;
587 rep_buffer[1] = '\0';
594 /* Replace the names of functions with the key that invokes them. */
596 replace_in_documentation (string)
599 register int i, start, next;
600 static char *result = (char *)NULL;
603 result = (char *)xmalloc (1 + strlen (string));
605 i = next = start = 0;
607 /* Skip to the beginning of a replaceable function. */
608 for (i = start; string[i]; i++)
610 /* Is this the start of a replaceable function name? */
611 if (string[i] == '\\' && string[i + 1] == '[')
613 char *fun_name, *rep;
616 /* Copy in the old text. */
617 strncpy (result + next, string + start, i - start);
621 /* Move to the end of the function name. */
622 for (i = start; string[i] && (string[i] != ']'); i++);
624 fun_name = (char *)xmalloc (1 + i - start);
625 strncpy (fun_name, string + start, i - start);
626 fun_name[i - start] = '\0';
628 /* Find a key which invokes this function in the info_keymap. */
629 function = named_function (fun_name);
631 /* If the internal documentation string fails, there is a
632 serious problem with the associated command's documentation.
633 We croak so that it can be fixed immediately. */
637 rep = where_is (info_keymap, function);
638 strcpy (result + next, rep);
639 next = strlen (result);
646 strcpy (result + next, string + start);
650 /* Return a string of characters which could be typed from the keymap
651 MAP to invoke FUNCTION. */
652 static char *where_is_rep = (char *)NULL;
653 static int where_is_rep_index = 0;
654 static int where_is_rep_size = 0;
657 where_is (map, function)
663 if (!where_is_rep_size)
664 where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
665 where_is_rep_index = 0;
667 rep = where_is_internal (map, function);
669 /* If it couldn't be found, return "M-x Foo". */
674 name = function_name (function);
677 sprintf (where_is_rep, "M-x %s", name);
684 /* Return the printed rep of FUNCTION as found in MAP, or NULL. */
686 where_is_internal (map, function)
692 /* If the function is directly invokable in MAP, return the representation
693 of that keystroke. */
694 for (i = 0; i < 256; i++)
695 if ((map[i].type == ISFUNC) && map[i].function == function)
697 sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
698 return (where_is_rep);
701 /* Okay, search subsequent maps for this function. */
702 for (i = 0; i < 256; i++)
704 if (map[i].type == ISKMAP)
706 int saved_index = where_is_rep_index;
709 sprintf (where_is_rep + where_is_rep_index, "%s ",
712 where_is_rep_index = strlen (where_is_rep);
713 rep = where_is_internal ((Keymap)map[i].function, function);
716 return (where_is_rep);
718 where_is_rep_index = saved_index;
722 return ((char *)NULL);
725 extern char *read_function_name ();
727 DECLARE_INFO_COMMAND (info_where_is,
728 "Show what to type to execute a given command")
732 command_name = read_function_name ("Where is command: ", window);
736 info_abort_key (active_window, count, key);
744 function = named_function (command_name);
750 location = where_is (active_window->keymap, function);
754 info_error ("`%s' is not on any keys", command_name);
758 if (strncmp (location, "M-x ", 4) == 0)
759 window_message_in_echo_area
760 ("%s can only be invoked via %s.", command_name, location);
762 window_message_in_echo_area
763 ("%s can be invoked via %s.", command_name, location);
767 info_error ("There is no function named `%s'", command_name);