123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- /* nodemenu.c -- produce a menu of all visited nodes.
- $Id$
- Copyright 1993, 1997, 1998, 2002, 2003, 2004, 2007, 2008, 2011,
- 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- Originally written by Brian Fox. */
- #include "info.h"
- #include "session.h"
- #include "echo-area.h"
- #include "variables.h"
- static NODE *get_visited_nodes (void);
- /* Return a line describing the format of a node information line. */
- static const char *
- nodemenu_format_info (void)
- {
- /* TRANSLATORS: The "\n* Menu:\n\n" part of this should not be translated, as
- it is part of the Info syntax. */
- return _("\n* Menu:\n\n\
- (File)Node Lines Size Containing File\n\
- ---------- ----- ---- ---------------");
- }
- /* Produce a formatted line of information about NODE. Here is what we want
- the output listing to look like:
- * Menu:
- (File)Node Lines Size Containing File
- ---------- ----- ---- ---------------
- * (emacs)Buffers:: 48 2230 /usr/gnu/info/emacs/emacs-1
- * (autoconf)Writing configure.in:: 123 58789 /usr/gnu/info/autoconf/autoconf-1
- * (dir)Top:: 40 589 /usr/gnu/info/dir
- */
- static char *
- format_node_info (NODE *node)
- {
- register int i;
- char *containing_file;
- static struct text_buffer line_buffer = { 0 };
- if (!text_buffer_base (&line_buffer))
- text_buffer_init (&line_buffer);
- else
- text_buffer_reset (&line_buffer);
- if (node->subfile)
- containing_file = node->subfile;
- else
- containing_file = node->fullpath;
- if (!containing_file || !*containing_file)
- text_buffer_printf (&line_buffer, "* %s::", node->nodename);
- else
- text_buffer_printf (&line_buffer, "* (%s)%s::",
- filename_non_directory (node->fullpath),
- node->nodename);
- for (i = text_buffer_off (&line_buffer); i < 36; i++)
- text_buffer_add_char (&line_buffer, ' ');
- {
- int lines = 1;
- for (i = 0; i < node->nodelen; i++)
- if (node->contents[i] == '\n')
- lines++;
- text_buffer_printf (&line_buffer, "%d", lines);
- }
- text_buffer_add_char (&line_buffer, ' ');
- for (i = text_buffer_off (&line_buffer); i < 44; i++)
- text_buffer_add_char (&line_buffer, ' ');
- text_buffer_printf (&line_buffer, "%ld", node->nodelen);
- if (containing_file)
- {
- for (i = text_buffer_off (&line_buffer); i < 51; i++)
- text_buffer_add_char (&line_buffer, ' ');
- text_buffer_printf (&line_buffer, containing_file);
- }
- return xstrdup (text_buffer_base (&line_buffer));
- }
- /* Little string comparison routine for qsort (). */
- static int
- compare_strings (const void *entry1, const void *entry2)
- {
- char **e1 = (char **) entry1;
- char **e2 = (char **) entry2;
- return mbscasecmp (*e1, *e2);
- }
- /* The name of the nodemenu node. */
- static char *nodemenu_nodename = "*Node Menu*";
- /* Produce an informative listing of all the visited nodes, and return it
- in a newly allocated node. */
- static NODE *
- get_visited_nodes (void)
- {
- register int i;
- WINDOW *info_win;
- NODE *node;
- char **lines = NULL;
- size_t lines_index = 0, lines_slots = 0;
- struct text_buffer message;
- for (info_win = windows; info_win; info_win = info_win->next)
- {
- for (i = 0; i < info_win->hist_index; i++)
- {
- NODE *history_node = info_win->hist[i]->node;
- /* We skip mentioning "*Node Menu*" nodes. */
- if (strcmp (history_node->nodename, nodemenu_nodename) == 0)
- continue;
- if (history_node)
- {
- char *line;
- line = format_node_info (history_node);
- add_pointer_to_array (line, lines_index, lines, lines_slots, 20);
- }
- }
- }
- /* Sort the array of information lines, if there are any. */
- if (lines)
- {
- register int j, newlen;
- char **temp;
- qsort (lines, lines_index, sizeof (char *), compare_strings);
- /* Delete duplicates. */
- for (i = 0, newlen = 1; i < lines_index - 1; i++)
- {
- /* Use FILENAME_CMP here, since the most important piece
- of info in each line is the file name of the node. */
- if (FILENAME_CMP (lines[i], lines[i + 1]) == 0)
- {
- free (lines[i]);
- lines[i] = NULL;
- }
- else
- newlen++;
- }
- /* We have free ()'d and marked all of the duplicate slots.
- Copy the live slots rather than pruning the dead slots. */
- temp = xmalloc ((1 + newlen) * sizeof (char *));
- for (i = 0, j = 0; i < lines_index; i++)
- if (lines[i])
- temp[j++] = lines[i];
- temp[j] = NULL;
- free (lines);
- lines = temp;
- lines_index = newlen;
- }
- text_buffer_init (&message);
- text_buffer_printf (&message, "\n");
- text_buffer_printf (&message,
- "%s", replace_in_documentation
- (_("Here is the menu of nodes you have recently visited.\n\
- Select one from this menu, or use '\\[history-node]' in another window.\n"), 0));
- text_buffer_printf (&message, "%s\n", nodemenu_format_info ());
- for (i = 0; (lines != NULL) && (i < lines_index); i++)
- {
- text_buffer_printf (&message, "%s\n", lines[i]);
- free (lines[i]);
- }
- if (lines)
- free (lines);
- node = text_buffer_to_node (&message);
- scan_node_contents (node, 0, 0);
- return node;
- }
- DECLARE_INFO_COMMAND (list_visited_nodes,
- _("Make a window containing a menu of all of the currently visited nodes"))
- {
- WINDOW *new;
- NODE *node;
- /* If a window is visible and showing the buffer list already, re-use it. */
- for (new = windows; new; new = new->next)
- {
- node = new->node;
- if (internal_info_node_p (node) &&
- (strcmp (node->nodename, nodemenu_nodename) == 0))
- break;
- }
- /* If we couldn't find an existing window, try to use the next window
- in the chain. */
- if (!new)
- {
- if (window->next)
- new = window->next;
- /* If there is more than one window, wrap around. */
- else if (window != windows)
- new = windows;
- }
- /* If we still don't have a window, make a new one to contain the list. */
- if (!new)
- new = window_make_window ();
- /* If we couldn't make a new window, use this one. */
- if (!new)
- new = window;
- /* Lines do not wrap in this window. */
- new->flags |= W_NoWrap;
- node = get_visited_nodes ();
- name_internal_node (node, xstrdup (nodemenu_nodename));
- node->flags |= N_WasRewritten;
- info_set_node_of_window (new, node);
- active_window = new;
- }
- DECLARE_INFO_COMMAND (select_visited_node,
- _("Select a node which has been previously visited in a visible window"))
- {
- char *line;
- NODE *node;
- node = get_visited_nodes ();
- line = info_read_completing_in_echo_area (_("Select visited node: "),
- node->references);
- window = active_window;
- if (!line)
- /* User aborts, just quit. */
- info_abort_key (window, 0);
- else if (*line)
- {
- REFERENCE *entry;
- /* Find the selected label in the references. */
- entry = info_get_menu_entry_by_label (node, line, 0);
- if (!entry)
- /* This shouldn't happen, because LINE was in the completion list
- built from the list of references. */
- info_error (_("The reference disappeared! (%s)."), line);
- else
- info_select_reference (window, entry);
- }
- free (line);
- free (node);
- }
|