#include "info.h"
static char *info_help_nodename = "*Info Help*";
static NODE *internal_info_help_node = (NODE *)NULL;
static char *internal_info_help_node_contents = (char *)NULL;
static char *info_internal_help_text[] = {
N_ ("Basic Commands in Info Windows"),
"******************************",
"",
" h Invoke the Info tutorial.",
" CTRL-x 0 Quit this help.",
" q Quit Info altogether.",
"",
"Selecting other nodes:",
"----------------------",
" n Move to the \"next\" node of this node.",
" p Move to the \"previous\" node of this node.",
" u Move \"up\" from this node.",
" m Pick menu item specified by name.",
" Picking a menu item causes another node to be selected.",
" f Follow a cross reference. Reads name of reference.",
" l Move to the last node seen in this window.",
" d Move to the `directory' node. Equivalent to `g(DIR)'.",
"",
"Moving within a node:",
"---------------------",
" SPC Scroll forward a page.",
" DEL Scroll backward a page.",
" b Go to the beginning of this node.",
" e Go to the end of this node.",
"",
"Other commands:",
"--------------------",
" 1 Pick first item in node's menu.",
" 2-9 Pick second ... ninth item in node's menu.",
" 0 Pick last item in node's menu.",
" g Move to node specified by name.",
" You may include a filename as well, as in (FILENAME)NODENAME.",
" s Search through this Info file for a specified string,",
" and select the node in which the next occurrence is found.",
NULL
};
static char *where_is (), *where_is_internal ();
void
dump_map_to_message_buffer (prefix, map)
char *prefix;
Keymap map;
{
register int i;
for (i = 0; i < 256; i++)
{
if (map[i].type == ISKMAP)
{
char *new_prefix, *keyname;
keyname = pretty_keyname (i);
new_prefix = (char *)
xmalloc (3 + strlen (prefix) + strlen (keyname));
sprintf (new_prefix, "%s%s%s ", prefix, *prefix ? " " : "", keyname);
dump_map_to_message_buffer (new_prefix, (Keymap)map[i].function);
free (new_prefix);
}
else if (map[i].function)
{
register int last;
char *doc, *name;
doc = function_documentation (map[i].function);
name = function_name (map[i].function);
if (!*doc)
continue;
for (last = i + 1; last < 256; last++)
if ((map[last].type != ISFUNC) ||
(map[last].function != map[i].function))
break;
if (last - 1 != i)
{
printf_to_message_buffer
("%s%s .. ", prefix, pretty_keyname (i));
printf_to_message_buffer
("%s%s\t", prefix, pretty_keyname (last - 1));
i = last - 1;
}
else
printf_to_message_buffer ("%s%s\t", prefix, pretty_keyname (i));
#if defined (NAMED_FUNCTIONS)
{
int length_so_far;
int desired_doc_start = 40;
printf_to_message_buffer ("(%s)", name);
length_so_far = message_buffer_length_this_line ();
if ((desired_doc_start + strlen (doc)) >= the_screen->width)
printf_to_message_buffer ("\n ");
else
{
while (length_so_far < desired_doc_start)
{
printf_to_message_buffer ("\t");
length_so_far += character_width ('\t', length_so_far);
}
}
}
#endif
printf_to_message_buffer ("%s\n", doc);
}
}
}
static void
create_internal_info_help_node ()
{
register int i;
char *contents = (char *)NULL;
NODE *node;
#if !defined (HELP_NODE_GETS_REGENERATED)
if (internal_info_help_node_contents)
contents = internal_info_help_node_contents;
#endif
if (!contents)
{
int printed_one_mx = 0;
initialize_message_buffer ();
for (i = 0; info_internal_help_text[i]; i++)
printf_to_message_buffer ("%s\n", info_internal_help_text[i]);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer ("The current search path is:\n");
printf_to_message_buffer (" \"%s\"\n", infopath);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer ("Commands available in Info windows:\n\n");
dump_map_to_message_buffer ("", info_keymap);
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer ("Commands available in the echo area:\n\n");
dump_map_to_message_buffer ("", echo_area_keymap);
#if defined (NAMED_FUNCTIONS)
for (i = 0; function_doc_array[i].func; i++)
{
VFunction *func = function_doc_array[i].func;
if ((!where_is_internal (info_keymap, func)) &&
(!where_is_internal (echo_area_keymap, func)))
{
if (!printed_one_mx)
{
printf_to_message_buffer ("---------------------\n\n");
printf_to_message_buffer
(_("The following commands can only be invoked via M-x:\n\n"));
printed_one_mx = 1;
}
printf_to_message_buffer
("M-x %s\n %s\n",
function_doc_array[i].func_name,
replace_in_documentation (function_doc_array[i].doc));
}
}
if (printed_one_mx)
printf_to_message_buffer ("\n");
#endif
printf_to_message_buffer
("%s", replace_in_documentation
(_("--- Use `\\[history-node]' or `\\[kill-node]' to exit ---\n")));
node = message_buffer_to_node ();
internal_info_help_node_contents = node->contents;
}
else
{
node = build_message_node ("", 0, 0);
free (node->contents);
node->contents = contents;
node->nodelen = 1 + strlen (contents);
}
internal_info_help_node = node;
#if defined (HELP_NODE_GETS_REGENERATED)
add_gcable_pointer (internal_info_help_node->contents);
#endif
name_internal_node (internal_info_help_node, info_help_nodename);
internal_info_help_node->flags &= ~N_IsInternal;
}
static WINDOW *
info_find_or_create_help_window ()
{
WINDOW *help_window, *eligible, *window;
eligible = (WINDOW *)NULL;
help_window = get_internal_info_window (info_help_nodename);
if (!help_window)
{
int max = 0;
for (window = windows; window; window = window->next)
{
if (window->height > max)
{
max = window->height;
eligible = window;
}
}
if (!eligible)
return ((WINDOW *)NULL);
}
#if !defined (HELP_NODE_GETS_REGENERATED)
else
return (help_window);
#endif
create_internal_info_help_node ();
if (!help_window)
{
if (eligible->height > 30)
{
active_window = eligible;
help_window = window_make_window (internal_info_help_node);
}
else
{
set_remembered_pagetop_and_point (active_window);
window_set_node_of_window (active_window, internal_info_help_node);
help_window = active_window;
}
}
else
{
if (active_window != help_window)
{
set_remembered_pagetop_and_point (active_window);
active_window = help_window;
}
window_set_node_of_window (active_window, internal_info_help_node);
}
remember_window_and_node (help_window, help_window->node);
return (help_window);
}
DECLARE_INFO_COMMAND (info_get_help_window, _("Display help message"))
{
WINDOW *help_window;
help_window = info_find_or_create_help_window ();
if (help_window)
{
active_window = help_window;
active_window->flags |= W_UpdateWindow;
}
else
{
info_error (CANT_MAKE_HELP);
}
}
DECLARE_INFO_COMMAND (info_get_info_help_node, _("Visit Info node `(info)Help'"))
{
NODE *node;
char *nodename;
{
WINDOW *win;
for (win = windows; win; win = win->next)
{
if (win->node && win->node->filename &&
(strcasecmp
(filename_non_directory (win->node->filename), "info") == 0) &&
((strcmp (win->node->nodename, "Help") == 0) ||
(strcmp (win->node->nodename, "Help-Small-Screen") == 0)))
{
active_window = win;
return;
}
}
}
if (active_window->height < 24)
nodename = "Help-Small-Screen";
else
nodename = "Help";
node = info_get_node ("Info", nodename);
if (!node)
{
if (info_recent_file_error)
info_error (info_recent_file_error);
else
info_error (CANT_FILE_NODE, "Info", nodename);
}
else
{
if (active_window->height > 45)
active_window = window_make_window (node);
else
{
set_remembered_pagetop_and_point (active_window);
window_set_node_of_window (active_window, node);
}
remember_window_and_node (active_window, node);
}
}
char *
function_documentation (function)
VFunction *function;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (function == function_doc_array[i].func)
break;
return (replace_in_documentation (function_doc_array[i].doc));
}
#if defined (NAMED_FUNCTIONS)
char *
function_name (function)
VFunction *function;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (function == function_doc_array[i].func)
break;
return (function_doc_array[i].func_name);
}
VFunction *
named_function (name)
char *name;
{
register int i;
for (i = 0; function_doc_array[i].func; i++)
if (strcmp (function_doc_array[i].func_name, name) == 0)
break;
return (function_doc_array[i].func);
}
#endif
char *
key_documentation (key, map)
char key;
Keymap map;
{
VFunction *function = map[key].function;
if (function)
return (function_documentation (function));
else
return ((char *)NULL);
}
DECLARE_INFO_COMMAND (describe_key, _("Print documentation for KEY"))
{
char keyname[50];
int keyname_index = 0;
unsigned char keystroke;
char *rep;
Keymap map;
keyname[0] = '\0';
map = window->keymap;
while (1)
{
message_in_echo_area (_("Describe key: %s"), keyname);
keystroke = info_get_input_char ();
unmessage_in_echo_area ();
if (Meta_p (keystroke) && (!ISO_Latin_p || key < 160))
{
if (map[ESC].type != ISKMAP)
{
window_message_in_echo_area
(_("ESC %s is undefined."), pretty_keyname (UnMeta (keystroke)));
return;
}
strcpy (keyname + keyname_index, "ESC ");
keyname_index = strlen (keyname);
keystroke = UnMeta (keystroke);
map = (Keymap)map[ESC].function;
}
rep = pretty_keyname (keystroke);
strcpy (keyname + keyname_index, rep);
keyname_index = strlen (keyname);
if (map[keystroke].function == (VFunction *)NULL)
{
message_in_echo_area (_("%s is undefined."), keyname);
return;
}
else if (map[keystroke].type == ISKMAP)
{
map = (Keymap)map[keystroke].function;
strcat (keyname, " ");
keyname_index = strlen (keyname);
continue;
}
else
{
char *message, *fundoc, *funname = "";
#if defined (NAMED_FUNCTIONS)
funname = function_name (map[keystroke].function);
#endif
fundoc = function_documentation (map[keystroke].function);
message = (char *)xmalloc
(10 + strlen (keyname) + strlen (fundoc) + strlen (funname));
#if defined (NAMED_FUNCTIONS)
sprintf (message, "%s (%s): %s.", keyname, funname, fundoc);
#else
sprintf (message, _("%s is defined to %s."), keyname, fundoc);
#endif
window_message_in_echo_area ("%s", message);
free (message);
break;
}
}
}
static char rep_buffer[30];
char *
pretty_keyname (key)
unsigned char key;
{
char *rep;
if (Meta_p (key))
{
char temp[20];
rep = pretty_keyname (UnMeta (key));
sprintf (temp, "ESC %s", rep);
strcpy (rep_buffer, temp);
rep = rep_buffer;
}
else if (Control_p (key))
{
switch (key)
{
case '\n': rep = "LFD"; break;
case '\t': rep = "TAB"; break;
case '\r': rep = "RET"; break;
case ESC: rep = "ESC"; break;
default:
sprintf (rep_buffer, "C-%c", UnControl (key));
rep = rep_buffer;
}
}
else
{
switch (key)
{
case ' ': rep = "SPC"; break;
case DEL: rep = "DEL"; break;
default:
rep_buffer[0] = key;
rep_buffer[1] = '\0';
rep = rep_buffer;
}
}
return (rep);
}
char *
replace_in_documentation (string)
char *string;
{
register int i, start, next;
static char *result = (char *)NULL;
maybe_free (result);
result = (char *)xmalloc (1 + strlen (string));
i = next = start = 0;
for (i = start; string[i]; i++)
{
if (string[i] == '\\' && string[i + 1] == '[')
{
char *fun_name, *rep;
VFunction *function;
strncpy (result + next, string + start, i - start);
next += (i - start);
start = i + 2;
for (i = start; string[i] && (string[i] != ']'); i++);
fun_name = (char *)xmalloc (1 + i - start);
strncpy (fun_name, string + start, i - start);
fun_name[i - start] = '\0';
function = named_function (fun_name);
if (!function)
abort ();
rep = where_is (info_keymap, function);
strcpy (result + next, rep);
next = strlen (result);
start = i;
if (string[i])
start++;
}
}
strcpy (result + next, string + start);
return (result);
}
static char *where_is_rep = (char *)NULL;
static int where_is_rep_index = 0;
static int where_is_rep_size = 0;
static char *
where_is (map, function)
Keymap map;
VFunction *function;
{
char *rep;
if (!where_is_rep_size)
where_is_rep = (char *)xmalloc (where_is_rep_size = 100);
where_is_rep_index = 0;
rep = where_is_internal (map, function);
if (!rep)
{
char *name;
name = function_name (function);
if (name)
sprintf (where_is_rep, "M-x %s", name);
rep = where_is_rep;
}
return (rep);
}
static char *
where_is_internal (map, function)
Keymap map;
VFunction *function;
{
register int i;
for (i = 0; i < 256; i++)
if ((map[i].type == ISFUNC) && map[i].function == function)
{
sprintf (where_is_rep + where_is_rep_index, "%s", pretty_keyname (i));
return (where_is_rep);
}
for (i = 0; i < 256; i++)
{
if (map[i].type == ISKMAP)
{
int saved_index = where_is_rep_index;
char *rep;
sprintf (where_is_rep + where_is_rep_index, "%s ",
pretty_keyname (i));
where_is_rep_index = strlen (where_is_rep);
rep = where_is_internal ((Keymap)map[i].function, function);
if (rep)
return (where_is_rep);
where_is_rep_index = saved_index;
}
}
return ((char *)NULL);
}
extern char *read_function_name ();
DECLARE_INFO_COMMAND (info_where_is,
"Show what to type to execute a given command")
{
char *command_name;
command_name = read_function_name (_("Where is command: "), window);
if (!command_name)
{
info_abort_key (active_window, count, key);
return;
}
if (*command_name)
{
VFunction *function;
function = named_function (command_name);
if (function)
{
char *location;
location = where_is (active_window->keymap, function);
if (!location)
{
info_error (_("`%s' is not on any keys"), command_name);
}
else
{
if (strncmp (location, "M-x ", 4) == 0)
window_message_in_echo_area
(_("%s can only be invoked via %s."), command_name, location);
else
window_message_in_echo_area
(_("%s can be invoked via %s."), command_name, location);
}
}
else
info_error (_("There is no function named `%s'"), command_name);
}
free (command_name);
}